Название: Рисование на слое Отправлено: Igors от Января 10, 2014, 11:53 Добрый день
Хотелось бы иметь возможность рисовать "поверх" всех виджетов, типа как делает drag'n drop, Пример: - есть окно в котором много чего нарисовано. Теперь (всего-навсего) нужно дать пользователю возможность что-то выбрать в окне рамкой. Приходится заводить члены класса, добавлять код рисования рамки в paint и перерисовываться всякий раз при ее изменении. А если paint большой и/или небыстрый, то придется его кешировать. Все это не выглядит хорошо/грамотно. В нативняке техника рисования на слое известна уже более 10 лет. А как это сделать средствами Qt? Спасибо Название: Re: Рисование на слое Отправлено: Racheengel от Января 10, 2014, 12:19 QRubberBand ?
Название: Re: Рисование на слое Отправлено: Igors от Января 10, 2014, 12:31 QRubberBand ? Да, в этом направлении, но QRubberBand hard-coded, больше чем он дает по дефаулту не получить. Название: Re: Рисование на слое Отправлено: GreatSnake от Января 10, 2014, 12:33 Хотелось бы иметь возможность рисовать "поверх" всех виджетов, типа как делает drag'n drop drag'n drop рисует в с воём собственном окне)Можно на главном окне создать виджет и на нём рисовать. Можно вообще поместить отдельное прозрачное окно поверх нарисованного и уже на нём рисовать. Название: Re: Рисование на слое Отправлено: Racheengel от Января 10, 2014, 12:45 Можно на главном окне создать виджет и на нём рисовать. Можно вообще поместить отдельное прозрачное окно поверх нарисованного и уже на нём рисовать. +1 Название: Re: Рисование на слое Отправлено: Igors от Января 10, 2014, 13:51 drag'n drop рисует в с воём собственном окне) На OSX дело сводится к вызову системного DnD. Есть QDesktopWidget - он имеет именно тот нативный тип окна что предназначен для этих целей. Но как мне прорваться к рисованию на нем?Можно на главном окне создать виджет и на нём рисовать. Так новое окно становится в фокус и бросает тень. С виджетом буду пробовать Можно вообще поместить отдельное прозрачное окно поверх нарисованного и уже на нём рисовать. Название: Re: Рисование на слое Отправлено: GreatSnake от Января 10, 2014, 14:55 Есть QDesktopWidget - он имеет именно тот нативный тип окна что предназначен для этих целей. Но как мне прорваться к рисованию на нем? Средствами Qt навряд-ли получится рисовать на root-овом окне.Цитировать Так новое окно становится в фокус и бросает тень. С виджетом буду пробовать А что, разве на OSX нельзя иметь окно без декораций и теней?Название: Re: Рисование на слое Отправлено: Igors от Января 11, 2014, 12:04 C QDesktop.. видимо глухо - ничего не дают. Вставить в окно прозрачный виджет и на нем рисовать - работает, но при попытке перерисовать этот виджет вызывается paint всего окна, причем дважды (почему - хз). Поэтому сосредоточился на варианте "прозрачное окно поверх". Смену фокуса убрал с помощью WA_ShowWithoutActivation. Тень убрал вызовом нативной ф-ции, ну ничего, боковым зрением видел в Qt5.x это уже есть, потом вычищу нативняк. Таким образом я могу рисовать "поверх" и при этом никаких paint для нижнего окна не вызывается, и никаких изменений в коде нижнего не требуется - хорошо.
Но при этом я не учел маленькой вещи - надо рисовать XOR'ом, а он работает "в пределах верхнего окна" т.е. никак не учитывает нижнее. Можно конечно сначала скопировать нижнее в верхнее - но это совсем коряво :'( Как это порешать? Спасибо Название: Re: Рисование на слое Отправлено: GreatSnake от Января 11, 2014, 14:40 Можно конечно сначала скопировать нижнее в верхнее - но это совсем коряво :'( Как это порешать? Дык, разве есть варианты?Если Qt<5, то можно легко через QWidget::windowSurface() через приватный инклюдник добраться до double-buffer основного окна. Название: Re: Рисование на слое Отправлено: Igors от Января 11, 2014, 18:37 Дык, разве есть варианты? Можно и просто через QPixmap::grabWindow (работает и для окон с OpenGL). Ну а дальше-то что? Напр нужно провести хоr-линию, не буду же я выцарапывать и инвертировать по пикселю :'( Остается скопировать все содержимое в верхнее, ну как бы покрыть окно его же копией и там уже xor-ить. Но тогда придется следить за изменением нижнего - не кайфЕсли Qt<5, то можно легко через QWidget::windowSurface() через приватный инклюдник добраться до double-buffer основного окна. Название: Re: Рисование на слое Отправлено: Racheengel от Января 11, 2014, 23:58 Напр нужно провести хоr-линию, не буду же я выцарапывать и инвертировать по пикселю :'( и все же... QRubberBand? :) Название: Re: Рисование на слое Отправлено: Racheengel от Января 12, 2014, 00:02 но в целом, ответ на вопросе содержался уже в вопросе :)
Приходится заводить члены класса, добавлять код рисования рамки в paint и перерисовываться всякий раз при ее изменении. ну, добавится пару строчек кода. проверить, активно ли выделение, и если да, отрисовать прямоугольник. Зачем заморачиваться с какими-то окнами, ксорами...? Название: Re: Рисование на слое Отправлено: Igors от Января 12, 2014, 11:53 и все же... QRubberBand? :) На OSX он просто создает белый виджет с альфой 0.25 (hard-coded). Это все что можно получитьну, добавится пару строчек кода. проверить, активно ли выделение, и если да, отрисовать прямоугольник. Зачем заморачиваться с какими-то окнами, ксорами...? Не пару - придется отслеживать mouseMove и.т.п. А резоны такие1) Тяжелый/длинный paint (доли секунды и больше). Здесь рамочка будет "застревать" (если делать ее в основном paint) 2) Уже имеются какие-то окна (возможно писаные др программистом). Влезать в чужой (развесиситый) класс, и не один - небольшое удовольствие. Выделять базовый (ради сервиса рамочки) - минимум спорно. Задумка сделать сервис выделения рамкой независимым, чтобы он мог применяться к любому окну. Это ценно/важно Название: Re: Рисование на слое Отправлено: Racheengel от Января 13, 2014, 02:56 Независимым, боюсь, не получится. В любом случае ведь придется как-то помечать выделенные объекты. Т.е. они как минимум должны иметь состояние "выделен-не выделен". То есть у всех них видится единый базовый класс, который бы отвечал за статус выделения. И, скорей всего, в зависимости от этого статуса должен меняться их внешний вид, правильно?
Название: Re: Рисование на слое Отправлено: Igors от Января 13, 2014, 11:54 Независимым, боюсь, не получится. В любом случае ведь придется как-то помечать выделенные объекты. Т.е. они как минимум должны иметь состояние "выделен-не выделен". То есть у всех них видится единый базовый класс, который бы отвечал за статус выделения. И, скорей всего, в зависимости от этого статуса должен меняться их внешний вид, правильно? Конечно только само окно знает какие в нем объекты, могут ли они быть выделены и.т.п. Но сначала нужно получить прямоугольник от юзера (т.е. "где выделять"). И тащить этот выбор в каждый или базовый класс совсем не тянет. Хотелось бы напр такКод
Название: Re: Рисование на слое Отправлено: GreatSnake от Января 13, 2014, 12:12 Можно и просто через QPixmap::grabWindow (работает и для окон с OpenGL). Ну а дальше-то что? Напр нужно провести хоr-линию, не буду же я выцарапывать и инвертировать по пикселю :'( Остается скопировать все содержимое в верхнее, ну как бы покрыть окно его же копией и там уже xor-ить. Но тогда придется следить за изменением нижнего - не кайф Почему обязательно через XOR и QRubberBand?Разве свой rubber-band сложно сделать? Например, типа затемнённой заливки? При изменениях области через QPixmap::grabWindow() захватываешь соответствующую область с основного окна, заливаешь полученный пиксмап через drawRect() полупрозрачным QBrush и непрозрачным QPen и уже этот пиксмап отрисовываешь на верхнем окне. Насчёт слежения за изменениями нижнего... А нужно ли? Ведь показывать верхнее окно следует только по нажатию кнопкой мыши. Думаю ничего страшного не произойдёт, если картинка замрёт. Не вижу проблемы) Кстати, судя по описанию QPixmap::grabWindow(): Цитировать The grabWindow() function grabs pixels from the screen, not from the window, i.e. if there is another window partially or entirely over the one you grab, you get pixels from the overlying window, too. The mouse cursor is generally not grabbed. использовать его в данном случае не получится.У себя я добирался непосредственно до double-buffer так: Код
Название: Re: Рисование на слое Отправлено: Igors от Января 13, 2014, 13:24 Кстати, судя по описанию QPixmap::grabWindow(): Получается. Создаваемое окно имеет те же флаги что и нижнее. Если нижнее было перекрыто каким-то окном (напр палеткой) то верхнее/созданное также будет перекрыто ... использовать его в данном случае не получится. У себя я добирался непосредственно до double-buffer так: Это не работает с нативным double-buffer там device не QImage/QPiхmap а нативный контекст Почему обязательно через XOR и QRubberBand? Да, все работает. Но хотелось бы обойтись чисто композитом, без копирования содержимого. К сожалению не вижу как разрулить XOR, а без него сложно :'(Разве свой rubber-band сложно сделать? Например, типа затемнённой заливки? При изменениях области через QPixmap::grabWindow() захватываешь соответствующую область с основного окна, заливаешь полученный пиксмап через drawRect() полупрозрачным QBrush и непрозрачным QPen и уже этот пиксмап отрисовываешь на верхнем окне. Насчёт слежения за изменениями нижнего... А нужно ли? Ведь показывать верхнее окно следует только по нажатию кнопкой мыши. Думаю ничего страшного не произойдёт, если картинка замрёт. Не вижу проблемы) Название: Re: Рисование на слое Отправлено: GreatSnake от Января 13, 2014, 13:35 Это не работает с нативным double-buffer там device не QImage/QPiхmap а нативный контекст Хм... Странно, по исходникам этого не скажешь.Название: Re: Рисование на слое Отправлено: Igors от Января 13, 2014, 14:05 Можно и без приватного хедера
Код На Вындоуз имеем QImage, на OSX 2 нуля Название: Re: Рисование на слое Отправлено: Racheengel от Января 13, 2014, 22:30 а если создавать по нажатию мыша окно и заливать его кистью с цветом Qt::transparent? и рамочку потом поверху?
не знаю, будет ли на маке работать, но по идее должно. Название: Re: Рисование на слое Отправлено: Igors от Января 14, 2014, 05:51 а если создавать по нажатию мыша окно и заливать его кистью с цветом Qt::transparent? и рамочку потом поверху? Так же и делаю. Вместо заливки проще WA_TranslucentBackground. Еще нужно пресечь смену фокуса и убрать тень (см обсуждение выше). К сожалению, не нашел элегантного способа XOR-ить это окно с тем что под ним не знаю, будет ли на маке работать, но по идее должно. Название: Re: Рисование на слое Отправлено: Old от Января 14, 2014, 07:27 К сожалению, не нашел элегантного способа XOR-ить это окно с тем что под ним Почему вы так хотите xor-ить содержимое? В восмедисятых-девяностых 20 века - ну ладно, сейчас 21 век... :)Название: Re: Рисование на слое Отправлено: Igors от Января 14, 2014, 08:56 Почему вы так хотите xor-ить содержимое? В восмедисятых-девяностых 20 века - ну ладно, сейчас 21 век... :) С удовольствием бы от него избавился, но что взамен? Предлагайте. Какой-то цвет (напр красный) - так его надо задавать в преференсах. Плюс лезть во все драги и переписать логику инверсии (не смертельный, но неприятный пробег по чужому коду). [/offtop] "восьмидесятых" :) Название: Re: Рисование на слое Отправлено: Old от Января 14, 2014, 09:17 Цвет лучше выбрать фиолетовый, он круче красного.
Скажите, а сейчас вам не надо пробегаться по всем местам чужих исходников? А по поводу описки... Уж простите. Ну не всем так повезло, иметь учителя русского языка в семье. :) Отвечаю без цитат, пока могу писать (обратите внимание, ударение на второй слог) только с телефона. |