Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает. Да и не смог нагуглить как в GDI+/c# выводить графику в реал-тайме.
Пытался глянуть исходники Paint.NET (где всё реализовано плавно и красиво), но там всё так запутано что неделя на разбор потребуется.
Нужно обновлять вывод при каждом движении мыши если левая кнопка зажата.
Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
gr.Clear(Color.Transparent);
делает всё чёррным. как решить?
protected override void OnMouseMove(MouseEventArgs e)
{
m_LastMouseLocation = e.Location;
if (m_InChoosing)
{
Graphics gr = this.CreateGraphics();
Pen p = new Pen(new SolidBrush(Color.Black), 0.1f);
gr.DrawLine(p, m_ChooseBegPos, new Point(m_ChooseBegPos.X, m_LastMouseLocation.Y));
gr.DrawLine(p, m_ChooseBegPos, new Point(m_LastMouseLocation.X, m_ChooseBegPos.Y));
gr.DrawLine(p, new Point(m_ChooseBegPos.X, m_LastMouseLocation.Y), m_LastMouseLocation);
gr.DrawLine(p, new Point(m_LastMouseLocation.X, m_ChooseBegPos.Y), m_LastMouseLocation);
//base.Invalidate(new Rectangle(m_LastMouseLocation, new Size(1, 1)), false);
}
base.OnMouseMove(e);
}
P.S. в Paint.NET видел, используются методы со словом Transform в Graphics.
может тут как-то можно их применить?
Здравствуйте, <Аноним>, Вы писали:
А>Пытался глянуть исходники Paint.NET (где всё реализовано плавно и красиво), но там всё так запутано что неделя на разбор потребуется.
Offtop, они же вроде больше не раздают исходники?
Не поделитесь на EUGEN . RATA @ GMAIL . COM
Спасибо
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
The life is relative and reversible.
Re: Offtop - Re: GDI+ быстрый вывод
От:
Аноним
Дата:
13.12.10 22:20
Оценка:
Здравствуйте, Holms, Вы писали:
H>Здравствуйте, <Аноним>, Вы писали:
А>>Пытался глянуть исходники Paint.NET (где всё реализовано плавно и красиво), но там всё так запутано что неделя на разбор потребуется. H>Offtop, они же вроде больше не раздают исходники? H>Не поделитесь на EUGEN . RATA @ GMAIL . COM H>Спасибо
Оу, не обратил внимания, там аж 2006 год.
1я ссылка в гугле.
Здравствуйте, <Аноним>, Вы писали:
А>Оу, не обратил внимания, там аж 2006 год. А>1я ссылка в гугле.
аа, ну это у меня то-же есть, думал что-то посвежее появилось
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает. Да и не смог нагуглить как в GDI+/c# выводить графику в реал-тайме.
А>Пытался глянуть исходники Paint.NET (где всё реализовано плавно и красиво), но там всё так запутано что неделя на разбор потребуется.
Там используется свой canvas с хитрой отрисовкой. Оверкилл.
А>Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает. Да и не смог нагуглить как в GDI+/c# выводить графику в реал-тайме.
От мигания избавляются установкой стилей где-нибудь в конструкторе (ЮзерКонтрола, формы)
А>Нужно обновлять вывод при каждом движении мыши если левая кнопка зажата.
При движении мыши следует вычислять минимальную область для обновления и посылать эту область в метод Invalidate. Никакого рисования в хэндлерах мыши. Рисование только в Paint.
А>Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
gr.Clear(Color.Transparent);
делает всё чёррным. как решить?
За очистку фона перед OnPaint отвечает метод OnPaintBackground, который трогать не надо если не планируется сложный фон. Как правило хватает свойств BackColor/BakcgroundImage. Color.Transparent нельзя использовать в качестве цвета для очистки фона.
А>
А> protected override void OnMouseMove(MouseEventArgs e)
А> {
А> m_LastMouseLocation = e.Location;
А> if (m_InChoosing)
А> {
А> Graphics gr = this.CreateGraphics();
А> Pen p = new Pen(new SolidBrush(Color.Black), 0.1f);
А> gr.DrawLine(p, m_ChooseBegPos, new Point(m_ChooseBegPos.X, m_LastMouseLocation.Y));
А> gr.DrawLine(p, m_ChooseBegPos, new Point(m_LastMouseLocation.X, m_ChooseBegPos.Y));
А> gr.DrawLine(p, new Point(m_ChooseBegPos.X, m_LastMouseLocation.Y), m_LastMouseLocation);
А> gr.DrawLine(p, new Point(m_LastMouseLocation.X, m_ChooseBegPos.Y), m_LastMouseLocation);
А> //base.Invalidate(new Rectangle(m_LastMouseLocation, new Size(1, 1)), false);
А> }
А> base.OnMouseMove(e);
А> }
А>
Все что связано с Graphics в событие Paint. Graphics не создавать, брать из аргументов события.
А>P.S. в Paint.NET видел, используются методы со словом Transform в Graphics. А>может тут как-то можно их применить?
В борьбе с безбожным миганием эти методы не помогут.
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает. Да и не смог нагуглить как в GDI+/c# выводить графику в реал-тайме.
А>Нужно обновлять вывод при каждом движении мыши если левая кнопка зажата.
Обновление графики только в событии Paint
Чтобы не было мерцания у контрола надо поставить свойство DoubleBuffered=true
Здравствуйте, samius, Вы писали:
А>>Нужно обновлять вывод при каждом движении мыши если левая кнопка зажата. S>При движении мыши следует вычислять минимальную область для обновления и посылать эту область в метод Invalidate. Никакого рисования в хэндлерах мыши. Рисование только в Paint.
Почему ? В Win API эта задача (резиновый контур, если я правильно понял) решается именно рисованием на WM_MOUSEMOVE, только с установкой SetROP2/R2_NOT или R2_XORPEN
А>>Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
gr.Clear(Color.Transparent);
делает всё чёррным. как решить?
Установив SetROP2, очистку получишь автоматически. Просто будет стираться старый и рисоваться новй прямоугольник. И деже double buffer здесь не нужен, потому что нет инвалидации и не приходит WM_PAINT
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
А>>>Нужно обновлять вывод при каждом движении мыши если левая кнопка зажата. S>>При движении мыши следует вычислять минимальную область для обновления и посылать эту область в метод Invalidate. Никакого рисования в хэндлерах мыши. Рисование только в Paint.
PD>Почему ? В Win API эта задача (резиновый контур, если я правильно понял) решается именно рисованием на WM_MOUSEMOVE, только с установкой SetROP2/R2_NOT или R2_XORPEN
При наличии всплывающих окон грязь гарантируется
А>>>Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
gr.Clear(Color.Transparent);
делает всё чёррным. как решить?
PD>Установив SetROP2, очистку получишь автоматически. Просто будет стираться старый и рисоваться новй прямоугольник. И деже double buffer здесь не нужен, потому что нет инвалидации и не приходит WM_PAINT
Инвертированные контуры — прошлый век. Навскидку не назову ни одну современную программу, что так делает. Ну и опять таки, что бы избежать грязи на рабочем столе, нужен double buffer. А раз он нужен, то нет смысла в инвертированных контурах, кроме как если они в ТЗ обозначены.
PD>>Почему ? В Win API эта задача (резиновый контур, если я правильно понял) решается именно рисованием на WM_MOUSEMOVE, только с установкой SetROP2/R2_NOT или R2_XORPEN
S>При наличии всплывающих окон грязь гарантируется
Принять меры на случай WM_PAINT — перерисовать все
А>>>>Способ приведённый ниже не мерцает но есть потребность в очистке от прошлых линий.
gr.Clear(Color.Transparent);
делает всё чёррным. как решить?
PD>>Установив SetROP2, очистку получишь автоматически. Просто будет стираться старый и рисоваться новй прямоугольник. И деже double buffer здесь не нужен, потому что нет инвалидации и не приходит WM_PAINT
S>Инвертированные контуры — прошлый век. Навскидку не назову ни одну современную программу, что так делает. Ну и опять таки, что бы избежать грязи на рабочем столе, нужен double buffer. А раз он нужен, то нет смысла в инвертированных контурах, кроме как если они в ТЗ обозначены.
Что за инвертированный контур ? Тебя не устраивает вид линии, что ли, что она будет не одного цвета ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Почему ? В Win API эта задача (резиновый контур, если я правильно понял) решается именно рисованием на WM_MOUSEMOVE, только с установкой SetROP2/R2_NOT или R2_XORPEN
S>>При наличии всплывающих окон грязь гарантируется
PD>Принять меры на случай WM_PAINT — перерисовать все
Без двойного буфера это будет заметно
S>>Инвертированные контуры — прошлый век. Навскидку не назову ни одну современную программу, что так делает. Ну и опять таки, что бы избежать грязи на рабочем столе, нужен double buffer. А раз он нужен, то нет смысла в инвертированных контурах, кроме как если они в ТЗ обозначены.
PD>Что за инвертированный контур ? Тебя не устраивает вид линии, что ли, что она будет не одного цвета ?
Меня — нет. Если я заказал рисовать красную линию, то она должна быть красная, а не контекстно серо-буро-малиновая в крапинку. Такое поведение сегодня — норма. MS Офис так рисует, OpenOffice так рисует, и даже Paint так рисует. Я последний раз видел R2_NOT в действии больше чем 10 лет назад.
Здравствуйте, samius, Вы писали:
PD>>Принять меры на случай WM_PAINT — перерисовать все S>Без двойного буфера это будет заметно
Да, но только при уходе всплывающего окна. Не беда.
S>>>Инвертированные контуры — прошлый век. Навскидку не назову ни одну современную программу, что так делает. Ну и опять таки, что бы избежать грязи на рабочем столе, нужен double buffer. А раз он нужен, то нет смысла в инвертированных контурах, кроме как если они в ТЗ обозначены.
PD>>Что за инвертированный контур ? Тебя не устраивает вид линии, что ли, что она будет не одного цвета ?
S>Меня — нет. Если я заказал рисовать красную линию, то она должна быть красная, а не контекстно серо-буро-малиновая в крапинку. Такое поведение сегодня — норма. MS Офис так рисует, OpenOffice так рисует, и даже Paint так рисует. Я последний раз видел R2_NOT в действии больше чем 10 лет назад.
Paint.net так не рисует.
Да и нельзя так. Что за выделение у тебя получится, если красным по красному ?
Ну а если тебе уж именно так хочется, могу предложить следующее решение. Снимаем с картинки 4 битмэпа толщиной в одну линию , то есть прямоугольник в виде битмэпов. Рисуем тут же линию твоего цвета. После передвижения мышки рисуем эти битмэпы обратно, снимаем новые. Можно даже и без битмэпов — просто снять значения с помощью GetPixel, сойдет
Главное — никакой перерисовки, никаких WM_PAINT.
Хотя... Еще одна идея.
Пусть Invalidate, пусть WM_PAINT, но только чтобы областей не было, только чтобы линии рисовались. Но если WM_PAINT дать 4 линии , то она объединит их в суммарный прямоугольник и ничего не получится. А вот если скармливать линии одна за одной и делать UpdateWindow каждый раз ?
InvalidateRect(верхняя линия прямоугольника);
UpdateWindow();
InvalidateRect(левая линия прямоугольника);
UpdateWindow();
и т.д.
По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
Здравствуйте, Pavel Dvorkin, Вы писали:
S>>Меня — нет. Если я заказал рисовать красную линию, то она должна быть красная, а не контекстно серо-буро-малиновая в крапинку. Такое поведение сегодня — норма. MS Офис так рисует, OpenOffice так рисует, и даже Paint так рисует. Я последний раз видел R2_NOT в действии больше чем 10 лет назад.
PD>Paint.net так не рисует.
А попробуй нарисовать в нем линию, или прямоугольник
PD>Да и нельзя так. Что за выделение у тебя получится, если красным по красному ?
Да, тут соглашусь. Выделять лучше через R2. Но сомневаюсь, что это делается в мышинном событии, когда двойной буфер все-равно используется.
PD>Ну а если тебе уж именно так хочется, могу предложить следующее решение. Снимаем с картинки 4 битмэпа толщиной в одну линию , то есть прямоугольник в виде битмэпов. Рисуем тут же линию твоего цвета. После передвижения мышки рисуем эти битмэпы обратно, снимаем новые. Можно даже и без битмэпов — просто снять значения с помощью GetPixel, сойдет PD>Главное — никакой перерисовки, никаких WM_PAINT.
Чем так страшен WM_PAINT, если есть двойной буфер? Более того, при интенсивной прорисовке содержимого без двойного буфера сложно обходиться. Я раньше занимался ГИС-ами, потому очень четко себе представляю ситуацию, когда сидишь минуту-другую ждешь окончания прорисовки, потом всплывает аська и все заново (без буфера-то).
PD>Хотя... Еще одна идея.
PD>Пусть Invalidate, пусть WM_PAINT, но только чтобы областей не было, только чтобы линии рисовались. Но если WM_PAINT дать 4 линии , то она объединит их в суммарный прямоугольник и ничего не получится. А вот если скармливать линии одна за одной и делать UpdateWindow каждый раз ?
PD>InvalidateRect(верхняя линия прямоугольника); PD>UpdateWindow(); PD>InvalidateRect(левая линия прямоугольника); PD>UpdateWindow(); PD>и т.д.
PD>По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
А ради чего собственно выжимать такты на ровном месте? Тебя не устраивает скорость BitBlt?
Более того, я даже не уверен, что посылка нескольких InvalidateRect-ов и UpdateWindow будет быстрее BitBlt.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Pavel Dvorkin, Вы писали:
S>>>Меня — нет. Если я заказал рисовать красную линию, то она должна быть красная, а не контекстно серо-буро-малиновая в крапинку. Такое поведение сегодня — норма. MS Офис так рисует, OpenOffice так рисует, и даже Paint так рисует. Я последний раз видел R2_NOT в действии больше чем 10 лет назад.
PD>>Paint.net так не рисует. S>А попробуй нарисовать в нем линию, или прямоугольник
Не понял. Я же только о контуре говорил.
PD>>Да и нельзя так. Что за выделение у тебя получится, если красным по красному ? S>Да, тут соглашусь. Выделять лучше через R2. Но сомневаюсь, что это делается в мышинном событии, когда двойной буфер все-равно используется.
Что-то у меня не получается посмотреть Spy++ окно paint.net. А другого ничего нет. Попробуй.
S>Чем так страшен WM_PAINT, если есть двойной буфер?
На каждый мышкин чих перерисовывать прямоугольник ?
PD>>По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
S>А ради чего собственно выжимать такты на ровном месте? Тебя не устраивает скорость BitBlt?
На каждое мышкино передвижение ?
S>Более того, я даже не уверен, что посылка нескольких InvalidateRect-ов и UpdateWindow будет быстрее BitBlt.
Так InvalidateRect + UpdateWindow и приведут к BitBlt, только на 4 линии. Остально-то зачем перерисовывать ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Paint.net так не рисует. S>>А попробуй нарисовать в нем линию, или прямоугольник
PD>Не понял. Я же только о контуре говорил.
Да, подтверждаю версию Sinix-а. Инверсная граница, а содержимое слегка тонировано.
PD>Что-то у меня не получается посмотреть Spy++ окно paint.net. А другого ничего нет. Попробуй.
А что ты хочешь увидешь?
S>>Чем так страшен WM_PAINT, если есть двойной буфер?
PD>На каждый мышкин чих перерисовывать прямоугольник ?
PD>>>По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
S>>А ради чего собственно выжимать такты на ровном месте? Тебя не устраивает скорость BitBlt?
PD>На каждое мышкино передвижение ?
S>>Более того, я даже не уверен, что посылка нескольких InvalidateRect-ов и UpdateWindow будет быстрее BitBlt.
PD>Так InvalidateRect + UpdateWindow и приведут к BitBlt, только на 4 линии. Остально-то зачем перерисовывать ?
Просто что бы не мудрить.
Вот смотри. Сейчас собираю прототип html смотрелки со спецвозможностями (т.е. существующие не устраивают). Для отладки мне удобно выводить некоторую посторонюю информацию о лэйаутинге на то же устройство (координаты мыши, атрибуты узлов, над чьими боксами я тащу мышь, границы боксов, и т.п.).
Сделал в лоб WM_PAINT-ом на каждый мышиный чих. Т.е. не блит, а вся отрисовка всех глифов с доп информацией + блит из двойного буфера (от фликов). Ну и что бы ты думал? Все отлично рисуется, правда немного поджирается процессор. Меня это не беспокоит на столько что бы заниматься экономией перерисовки на уровне пикселов. И пока у меня нет отсечения по страницам. Т.е. на каждый мышиный чих рисуется весь документ, хоть и видна лишь его часть.
Можешь сказать что из-за таких как я тормозит виндовс, но мое мнение — одиночных блитов бояться не нужно в современных интерактивных приложениях.
В более менее сложных и многослойных могут работать и множественные блиты (2 и более буферов).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Версия, идущая с Windows 7.
Не, там старый добрый MsPaint. Paint.Net из коробки бывает только в кулхацкерских сборках.
PD>>Что-то у меня не получается посмотреть Spy++ окно paint.net. А другого ничего нет. Попробуй. S>А что ты хочешь увидешь?
Приходит WM_PAINT при движении контура или нет.
S>>>Чем так страшен WM_PAINT, если есть двойной буфер?
PD>>На каждый мышкин чих перерисовывать прямоугольник ? S>
PD>>Так InvalidateRect + UpdateWindow и приведут к BitBlt, только на 4 линии. Остально-то зачем перерисовывать ? S>Просто что бы не мудрить.
Хм. Если размер контура будет во весь экран ? Тоже тормозить не будет ? На любой видеокарте ? На машине с процессором 5-7 летней давнсти ? Не уверен.
S>Вот смотри. Сейчас собираю прототип html смотрелки со спецвозможностями (т.е. существующие не устраивают). Для отладки мне удобно выводить некоторую посторонюю информацию о лэйаутинге на то же устройство (координаты мыши, атрибуты узлов, над чьими боксами я тащу мышь, границы боксов, и т.п.).
S>Сделал в лоб WM_PAINT-ом на каждый мышиный чих. Т.е. не блит, а вся отрисовка всех глифов с доп информацией + блит из двойного буфера (от фликов). Ну и что бы ты думал? Все отлично рисуется, правда немного поджирается процессор. Меня это не беспокоит на столько что бы заниматься экономией перерисовки на уровне пикселов. И пока у меня нет отсечения по страницам. Т.е. на каждый мышиный чих рисуется весь документ, хоть и видна лишь его часть.
S>Можешь сказать что из-за таких как я тормозит виндовс, но мое мнение — одиночных блитов бояться не нужно в современных интерактивных приложениях. S>В более менее сложных и многослойных могут работать и множественные блиты (2 и более буферов).
Ладно, давай не будем еще и здесь флейм на эту тему устраивать.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Что-то у меня не получается посмотреть Spy++ окно paint.net. А другого ничего нет. Попробуй. S>>А что ты хочешь увидешь?
PD>Приходит WM_PAINT при движении контура или нет.
Да, приходит, прчем вместе с WM_ERASEBKGND и даже без контура чисто на WM_MOUSEMOVE (даже не нажатый).
Полагаю, ты немедленно избавишься от этого софта?
PD>>>Так InvalidateRect + UpdateWindow и приведут к BitBlt, только на 4 линии. Остально-то зачем перерисовывать ? S>>Просто что бы не мудрить.
PD>Хм. Если размер контура будет во весь экран ? Тоже тормозить не будет ? На любой видеокарте ? На машине с процессором 5-7 летней давнсти ? Не уверен.
Я на этом не экономил на занюханном P4, на котором работал в институте во время выхода первого фреймворка. Пользователи не жаловались. Наоборот получалось значительно экономить за счет каскада буферов, а не на одиночных пикселях.
PD>Ладно, давай не будем еще и здесь флейм на эту тему устраивать.
Ты начал. Уверен,что в большинстве современного софта проблемы производительности растут не из-за того что рисуются лишние пиксели в WM_PAINT.