Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 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.
Здравствуйте, samius, Вы писали:
PD>>Приходит WM_PAINT при движении контура или нет. S>Да, приходит, прчем вместе с WM_ERASEBKGND и даже без контура чисто на WM_MOUSEMOVE (даже не нажатый). S>Полагаю, ты немедленно избавишься от этого софта?
Так мне же уже Sinix объяснил, что у меня его нет
PD>>Ладно, давай не будем еще и здесь флейм на эту тему устраивать. S>Ты начал. Уверен,что в большинстве современного софта проблемы производительности растут не из-за того что рисуются лишние пиксели в WM_PAINT.
Я лишь свои рекомендации дал.
With best regards
Pavel Dvorkin
Re[2]: GDI+ быстрый вывод
От:
Аноним
Дата:
14.12.10 15:34
Оценка:
Здравствуйте, vit_as, Вы писали:
_>Обновление графики только в событии Paint
всё мерцает. если вне события то просто не очищаются старые линии.
_>Чтобы не было мерцания у контрола надо поставить свойство DoubleBuffered=true
Двойной буффер/Оптимизированый (SetStyle) или вместе абсолютно не дают результат. что с ними что без.
Re[2]: GDI+ быстрый вывод
От:
Аноним
Дата:
14.12.10 15:44
Оценка:
Здравствуйте, samius, Вы писали:
S>За очистку фона перед OnPaint отвечает метод OnPaintBackground, который трогать не надо если не планируется сложный фон. Как правило хватает свойств BackColor/BakcgroundImage. Color.Transparent нельзя использовать в качестве цвета для очистки фона.
А>то тормоза отпадают но как уже понятно не очищается ничего.
А>base.OnPaintBackground слишком медленно работает
Взял форму из стандартного шаблона, внес изменения только в From1.cs (в дизайнере ничего не менял).
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Paint += Form1_Paint;
SetStyle(ControlStyles.ResizeRedraw, true);
//SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
void Form1_Paint(object sender, PaintEventArgs e)
{
var rect = ClientRectangle;
using (var pen = new Pen(Color.Red, 50))
e.Graphics.DrawLine(pen, rect.Left, rect.Top, rect.Right, rect.Bottom);
}
}
При запуске в винде с включенной опцией "Рисовать окно при перетаскивании", рисуется красная жирная линия с безбожным фликанием во время ресайза формы. Раскомментирование второй строчки SetStyle флики убирает.
Первая строчка SetStyle нужна для того что бы организовать автоматическую перерисовку при ресайзе формы.
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает. Да и не смог нагуглить как в GDI+/c# выводить графику в реал-тайме.
А>
Что бы совсем подавить мерцание и артефакты, нужно рисовать всегда в два битмапа — основной для статического контента и вспомогательный для динамического.
Щас скажу страшное — для простоты кода, для подавления мерцания с артефактами вся отрисовка только OnPaint в оба битмапа и на главный Graphics !!! Это если ты конечно не игру пишешь и нет никаких тяжелых анимаций.
Основной битмап обновляется крайне редко — у меня где то раз в несколько секунд или даже минут.
Вспомогательный, для мышиных операций, обновляется каждый раз когда есть выделение мышом и тд.
Для вспомогательного примерно так же, но см. ниже — фоном для вспомогательного будет основной.
Итого, как происходит отрисовка
0. В OnMouseMove управляем флагами для перерисовки, что нужно обновлять.
1. в OnPaint проверяем, надо ли перерисовать статический контент, если надо — перерисовать основной битмап.
2. в OnPaint проверяем, надо ли перерисовать динамический контент, если надо — перерисовываем вспомогательный битмап, в качестве фона — основной битмап.
3. в конце отрисовываем или основной битмап или вспомогательный вот такой функцией
Здравствуйте, Ikemefula, Вы писали:
I>Итого, как происходит отрисовка
I>0. В OnMouseMove управляем флагами для перерисовки, что нужно обновлять. I>1. в OnPaint проверяем, надо ли перерисовать статический контент, если надо — перерисовать основной битмап. I>2. в OnPaint проверяем, надо ли перерисовать динамический контент, если надо — перерисовываем вспомогательный битмап, в качестве фона — основной битмап. I>3. в конце отрисовываем или основной битмап или вспомогательный вот такой функцией
+1
Примерно к такой же схеме я пришел когда занимался ГИС-ом, где была и статическая информация (очень много, до нескольких секунд, или даже до минуты вывода GDI средствами) и динамическая, которая всегда должна быть актуальна, даже во время длительной отрисовки статической. Т.е. паузы в отображении динамической информации быть не должно.
Отличия были в том, что динамической информации было как-правило мало, и она не требовала буферизации. Но само-собой, выводилась не на DC контрола, а в итоговый буфер, где склеивались различные буфера, после чего этот буфер копировался на DC контрола.
А статических буферов было несколько. Так же был D3D рельеф ортогонального вида, который тоже приходилось буферизовывать, т.к. рисовался он немаленьким mesh-ем.
Для комфортных Pan/Zoom/ResizeWindow приходилось держать буферы значительно превышающие размеры окна. Это позволяло при изменениях параметров вида получать превью статической информации с помощью трансформаций буферов. После завершения выбора параметров вида (т.е. когда пользователь повозит мышкой и успокоится), начиналась фоновая отрисовка статических буферов с регулярным (раз 5-10 в секунду) выбросом нарендеренной статики на девайс контрола. Динамическая информация при этом обновлялась от 20и раз в секунду.
Специально для Павла: в 2004м году вся эта кухня позволяла комфортно работать на 4м пне с 256Мб оперативки с интегрированной графикой на 1м тогда фреймворке . Работало и на 3м пне. Но там даже винда сама по себе тормозила.
Ну и как-то на фоне всего происходящего, экономить на том что бы делать Invalidate по ребрам раббера, просто в голову не приходило.
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме.
1. В обработчике OnMouseMove вызывать у контрола Invalidate с заданной областью. Чем меньше и точнее область, тем лучше.
2. В обработчике OnPaint перерисовать, но только то, что пересекается с PaintEventArgs.ClipRectangle. В этот прямоугольник как раз попадет та область, которую задал при вызове Invalidate (или череде вызовов). Чем она меньше, а также чем алгоритмически лучше происходит вычисление пересечения, тем быстрее отрисовка.
3. Мерцание убрать через двойную буферизацию у контрола (установить стили через SetStyle).
4. Рисовать напрямую через CreateGraphics — часто плохая идея. Но бывают исключения. Здесь не тот случай.
Нужно понимать, что Invalidate посылает сообщение, которое ставится в очередь потока GUI. Можно вызывать Invalidate многократно. Когда OnMouseMove отработает, поток GUI достанет из очереди все накопившиеся сообщения Invalidate и сделает вызов OnPaint. Таков основной цикл.
з.ы. Очень жаль, что в WPF и Silverlight совсем не так. Оттуда безбожно вырезали этот замечательный механизм, который позволял отрисовывать десятки тысяч разбросанных графических элементов одновременно. При хороших алгоритмах и доступной памяти можно было держать и сотни тысяч элементов или даже более. Но нужно было думать. Сейчас в WPF и Silverlight думает машина
Здравствуйте, samius, Вы писали:
S>Специально для Павла: в 2004м году вся эта кухня позволяла комфортно работать на 4м пне с 256Мб оперативки с интегрированной графикой на 1м тогда фреймворке . Работало и на 3м пне. Но там даже винда сама по себе тормозила.
Надеюсь, ты понимаешь, что объем ОП здесь едва ли при чем, так как карта у тебя DDB (я полагаю), а поэтому хранится в видеопамяти (тоже полагаю) Тем более не имеет отношения к делу версия FW — здесь работает только подлежащий слой.
S>Ну и как-то на фоне всего происходящего, экономить на том что бы делать Invalidate по ребрам раббера, просто в голову не приходило.
Здравствуйте, dsorokin, Вы писали:
D>Нужно понимать, что Invalidate посылает сообщение, которое ставится в очередь потока GUI. Можно вызывать Invalidate многократно. Когда OnMouseMove отработает, поток GUI достанет из очереди все накопившиеся сообщения Invalidate и сделает вызов OnPaint. Таков основной цикл.
Немного уточню. В очереди не будет нескольких сообщений. WM_PAINT в очереди всегда один (В действительности там флаг на все окна потока)
Если до его обработки добавляется новая инвалидная область, то Windows модифицирует параметры WM_PAINT, установив инвалидный прямоугольник как минимальный прямоугольник, включающий все ранее взятые и новый. Иными словами, если вначале инвалидить (0,0,100,100), а потом (200,200,300,300), то в OnPaint придет (0,0,300,300)
The QS_PAINT flag is handled differently. If a window created by the thread has an invalid region, the QS_PAINT flag is turned on. When the area occupied by all windows created by this thread becomes validated (usually by a call to ValidateRect, ValidateRegion, or BeginPaint), the QS_PAINT flag is turned off. This flag is turned off only when all windows created by the thread are validated. Calling GetMessage or PeekMessage has no effect on this wake flag.
Здравствуйте, dsorokin, Вы писали:
D>з.ы. Очень жаль, что в WPF и Silverlight совсем не так. Оттуда безбожно вырезали этот замечательный механизм, который позволял отрисовывать десятки тысяч разбросанных графических элементов одновременно. При хороших алгоритмах и доступной памяти можно было держать и сотни тысяч элементов или даже более. Но нужно было думать. Сейчас в WPF и Silverlight думает машина
Какой механизм?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
S>>Специально для Павла: в 2004м году вся эта кухня позволяла комфортно работать на 4м пне с 256Мб оперативки с интегрированной графикой на 1м тогда фреймворке . Работало и на 3м пне. Но там даже винда сама по себе тормозила.
PD>Надеюсь, ты понимаешь, что объем ОП здесь едва ли при чем, так как карта у тебя DDB (я полагаю), а поэтому хранится в видеопамяти (тоже полагаю) Тем более не имеет отношения к делу версия FW — здесь работает только подлежащий слой.
Карта у меня была векторная. А буферами ведал D3D. Где он их хранил — без понятия, он сам рулит. При 8М видеопамяти выбору у него много не было.
Мне это было не важно, т.к. весь мой пайплайн со склейкой буферов рельефа, статических данных карты, динамических, а так же рабберов и других инструметов взаимодействия, в том числе собственные прозрачные и всплыающие от наезда мыши панели и скроллбары, мог выкидывать 20 кадров в секунду в окне, распахнутом на весь рабочий стол.
А ты говоришь — давайте экономить и посылать на перерисовку по одному ребру раббера. Я полагаю, ты хочешь что-бы видеокарта не перегрелась, делая лишний битблит?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да, но только при уходе всплывающего окна. Не беда.
Это не беда, это отстойный рендеринг.
PD>Ну а если тебе уж именно так хочется, могу предложить следующее решение. Снимаем с картинки 4 битмэпа толщиной в одну линию , то есть прямоугольник в виде битмэпов. Рисуем тут же линию твоего цвета. После передвижения мышки рисуем эти битмэпы обратно, снимаем новые. Можно даже и без битмэпов — просто снять значения с помощью GetPixel, сойдет PD>Главное — никакой перерисовки, никаких WM_PAINT.
Это тянет на хороший студенческий подход
PD>InvalidateRect(верхняя линия прямоугольника); PD>UpdateWindow(); PD>InvalidateRect(левая линия прямоугольника); PD>UpdateWindow(); PD>и т.д. PD>По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
Здравствуйте, Pavel Dvorkin, Вы писали:
S>>Чем так страшен WM_PAINT, если есть двойной буфер? PD>На каждый мышкин чих перерисовывать прямоугольник ?
Конечно. БОлее того — это и в OnMouseMove придется делать точно так же. Потому что прямоугольник этот динамически меняется.
S>>А ради чего собственно выжимать такты на ровном месте? Тебя не устраивает скорость BitBlt? PD>На каждое мышкино передвижение ?
Слушай, не смешно. Дохлый комп может швырять битмапы на экран с такой скоростью, что загрузка процессора в этом случае нисколько не растет
Кроме того, почти всегда обновляется только конкретный регион.
Здравствуйте, samius, Вы писали:
S>Карта у меня была векторная. А буферами ведал D3D.
Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw.
S>А ты говоришь — давайте экономить и посылать на перерисовку по одному ребру раббера. Я полагаю, ты хочешь что-бы видеокарта не перегрелась, делая лишний битблит?
Мне просто совсем не по нутру, когда ради того, чтобы переисовать периметр прямоугольника, перерисовавают его весь. Ну вот такой у меня характер
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Хм. Если размер контура будет во весь экран ? Тоже тормозить не будет ? На любой видеокарте ? На машине с процессором 5-7 летней давнсти ? Не уверен.
Здравствуйте, Ikemefula, Вы писали:
I>Это тянет на хороший студенческий подход
Ну мы не в КСВ, дорогой. Если есть аргументы, давай. Без болтовни.
PD>>InvalidateRect(верхняя линия прямоугольника); PD>>UpdateWindow(); PD>>InvalidateRect(левая линия прямоугольника); PD>>UpdateWindow(); PD>>и т.д. PD>>По идее UpdateWindow заставит немедленно перерисовать именно эту линию и снять флаг инвалидности.
I>И это говорит человек, который знает! Винапи
UpdateWindow заставляет немедленно выполниться обработчик WM_PAINT. А пока что там всего лишь один инвалидный прямоугольник шириной в 1 пиксель. После OnPaint он будет зарисован и флаг QS_PAINT в очереди сообщений снят.
MSDN: (выделено мной)
The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window's update region is not empty. The function sends a WM_PAINT message directly to the window procedure of the specified window, bypassing the application queue. If the update region is empty, no message is sent.
Рихтер :
The QS_PAINT flag is handled differently. If a window created by the thread has an invalid region, the QS_PAINT flag is turned on. When the area occupied by all windows created by this thread becomes validated (usually by a call to ValidateRect, ValidateRegion, or BeginPaint), the QS_PAINT flag is turned off. This flag is turned off only when all windows created by the thread are validated. Calling GetMessage or PeekMessage has no effect on this wake flag.
Последующие InvalidateRect + UpdateWindow аналогичным образом сработают на оставшиеся 3 линии.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
S>>Карта у меня была векторная. А буферами ведал D3D.
PD>Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw.
О, наверное в те времена DirectDraw умел работать с 3D и GDI?
Т.е. ты считаешь, когда у D3D буфера просишь создать Graphics (или на низком уровне получить HDC), то там на самом деле работает DirectDraw, а не GDI, когда ты отправляешь Graphics.DrawString?
PD>Мне просто совсем не по нутру, когда ради того, чтобы переисовать периметр прямоугольника, перерисовавают его весь. Ну вот такой у меня характер
Это трепетное отношение к premature optimization. А к характеру имеет отношение то, что ты хочешь что бы все остальные проявляли бы к ней такую же трепетность, а от студентов еще и требуешь (судя по всему). Извини, не хотел обсуждать твой характер, но тут такая провокация!
Здравствуйте, Ikemefula, Вы писали:
PD>>На каждый мышкин чих перерисовывать прямоугольник ?
I>Конечно. Более того — это и в OnMouseMove придется делать точно так же. Потому что прямоугольник этот динамически меняется.
Конечно меняется.
На MouseMove при использовании механизма SetROP2 перерисовывают только рамку. Внутренность не перерисовывают, потому что незачем. Следующий mousemove приведет к тому же — вот и все.
case WM_MOUSEMOVE:
{
SetROP2
Select NULL_BRUSH в hdc
Select нужное перо в hdc
Rectangle по старому прямоугольнику (запомненному в первый раз по WM_LBUTTONDOWN, а потом измененному на mousemove, см. ниже
старый прямоугольник = новый прямоугольник (левый-верхний без изменения, правый-нижний из mousemove lParam)
Rectangle по новому прямоугольнику
I>Слушай, не смешно. Дохлый комп может швырять битмапы на экран с такой скоростью, что загрузка процессора в этом случае нисколько не растет
Этим не процессор, а скорее всего видеокарта занимается.
Здравствуйте, samius, Вы писали:
PD>>Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw. S>О, наверное в те времена DirectDraw умел работать с 3D и GDI?
Наоборот. Direct3D работал через DirectDraw, а GDI сам по себе.
DirectDraw и GDI — это два разных механизма. Подробности у Фень Юаня, там об этом много.
GDI слишком медленный для игр, поэтому-то DirectDraw и был сделан.
S>Т.е. ты считаешь, когда у D3D буфера просишь создать Graphics (или на низком уровне получить HDC), то там на самом деле работает DirectDraw, а не GDI, когда ты отправляешь Graphics.DrawString?
HDC в DirectDraw получают иным способом, через directdraw surface
Ты просто, видимо, не в курсе всего этого.
PD>>Мне просто совсем не по нутру, когда ради того, чтобы переисовать периметр прямоугольника, перерисовавают его весь. Ну вот такой у меня характер
S>Это трепетное отношение к premature optimization. А к характеру имеет отношение то, что ты хочешь что бы все остальные проявляли бы к ней такую же трепетность, а от студентов еще и требуешь (судя по всему). Извини, не хотел обсуждать твой характер, но тут такая провокация!
Считай как хочешь. Я иначе не могу. Тебя никто не заставляет с этим соглашаться.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>На MouseMove при использовании механизма SetROP2 перерисовывают только рамку. Внутренность не перерисовывают, потому что незачем. Следующий mousemove приведет к тому же — вот и все.
А если надо будет чтото сложнее пустого прямоугольника рисовать ?
Здравствуйте, Pavel Dvorkin, Вы писали:
I>>И это говорит человек, который знает! Винапи
PD>UpdateWindow заставляет немедленно выполниться обработчик WM_PAINT. А пока что там всего лишь один инвалидный прямоугольник шириной в 1 пиксель. После OnPaint он будет зарисован и флаг QS_PAINT в очереди сообщений снят.
...
PD>Последующие InvalidateRect + UpdateWindow аналогичным образом сработают на оставшиеся 3 линии.
PD>Контраргументы есть ?
Конечно. Сделай решение для общего случая — например прямоугольник с заливкой, маркерами, подписями к маркерам и ты поймешь почему такой способ не используется.
Здравствуйте, Ikemefula, Вы писали:
PD>>Контраргументы есть ?
I>Конечно. Сделай решение для общего случая — например прямоугольник с заливкой, маркерами, подписями к маркерам и ты поймешь почему такой способ не используется.
Я спросил про контраргументы насчет моего якобы незнания винапи , то есть как работает InvalidateRect и UpdateWindow. Есть что по этому поводу сказать ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw. S>>О, наверное в те времена DirectDraw умел работать с 3D и GDI?
PD>HDC в DirectDraw получают иным способом, через directdraw surface
PD>http://programmersforum.ru/showthread.php?p=432552
PD>Ты просто, видимо, не в курсе всего этого.
Ты видимо не в курсе того, что если я делаю вызов DrawString по HDC, полученному у IDirect3DSurface, то работает именно GDI. Ты меня уговариваешь что GDI на самом деле не было и я не в курсе и заместо GDI работал DirectDraw. Если там DirectDraw где и учавствует — то только в процесе лока. GDI он собой никак не заменяет.
Здравствуйте, samius, Вы писали:
S>Ты видимо не в курсе того, что если я делаю вызов DrawString по HDC, полученному у IDirect3DSurface, то работает именно GDI. Ты меня уговариваешь что GDI на самом деле не было и я не в курсе и заместо GDI работал DirectDraw. Если там DirectDraw где и учавствует — то только в процесе лока. GDI он собой никак не заменяет.
Я всего лишь утверждаю, что при работе D3D работа шла через DirectDraw, Использует ли внутри себя DirectDraw GDI или нет и где именно — это другой вопрос. Да, использует.
Здравствуйте, samius, Вы писали:
PD>>Здравствуйте, Ikemefula, Вы писали:
I>>>А если надо будет чтото сложнее пустого прямоугольника рисовать ?
PD>>Речь в задаче ТС шла о резиновом контуре, только.
S>Речь в задаче ТС шла о том что бы убрать флики. R2_NOT резинкой флики полностью не исключить, даже если посылать на отрисовку отдельными гранями.
Флики мы с тобой уже обсудили, а здесь речь идет о другом. Просто Икемефулв решил мне задачу усложнить (что будет если...), ну я ему и ответил, что усложнение не рассматривается.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
S>>Ты видимо не в курсе того, что если я делаю вызов DrawString по HDC, полученному у IDirect3DSurface, то работает именно GDI. Ты меня уговариваешь что GDI на самом деле не было и я не в курсе и заместо GDI работал DirectDraw. Если там DirectDraw где и учавствует — то только в процесе лока. GDI он собой никак не заменяет.
PD>Я всего лишь утверждаю, что при работе D3D работа шла через DirectDraw, Использует ли внутри себя DirectDraw GDI или нет и где именно — это другой вопрос. Да, использует.
Я не пытаюсь с тобой спорить, использует ли DirectDraw GDI.
До этого ты утверждал что у меня не было GDI. Я настаиваю на том, что если делается вызов GDI, то работает GDI. А DirectDraw может оперировать лишь буферами и пикселформатами, в то время как кистями, шрифтами и т.п. он не владеет. Даже растровую развертку полигона сделать средствами DirectDraw не выйдет.
Здравствуйте, samius, Вы писали:
S>Я не пытаюсь с тобой спорить, использует ли DirectDraw GDI. S>До этого ты утверждал что у меня не было GDI.
Я утверждал, что ты работал через DirectDraw в том, что касается получения HDC. HDC у тебя не от GDI, а от DirectDraw. То есть это иной контекст. Используются ли при работе с ним средства от GDI — я не говорил вообще.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
S>>Я не пытаюсь с тобой спорить, использует ли DirectDraw GDI. S>>До этого ты утверждал что у меня не было GDI.
PD>Я утверждал, что ты работал через DirectDraw в том, что касается получения HDC. HDC у тебя не от GDI, а от DirectDraw. То есть это иной контекст. Используются ли при работе с ним средства от GDI — я не говорил вообще.
Иной контекст твого утверждения, я полагаю?
Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw.
Здравствуйте, samius, Вы писали:
PD>>Я утверждал, что ты работал через DirectDraw в том, что касается получения HDC. HDC у тебя не от GDI, а от DirectDraw. То есть это иной контекст. Используются ли при работе с ним средства от GDI — я не говорил вообще.
S>Иной контекст твого утверждения, я полагаю? S>
S>Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw.
S>Потому как контекст устройства там именно от GDI.
Что-то я уже вообще не понимаю. Ты согласился вроде, что там через DirectDraw идет ?
Ну вот тебе куски моего кода 10-летней давности
LPDIRECTDRAWSURFACE4 g_pDDSBack = NULL; // DirectDraw back surface
...
// Get a pointer to the back buffer
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);
...
g_pDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
...
if (g_pDDSBack->GetDC(&hdc) == DD_OK)
{
SetBkMode(hdc, TRANSPARENT);
HPEN hP = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
HPEN hPOld = (HPEN) SelectObject(hdc, hP);
// Small windowfor(int i = - 3; i < 4; i++)
for(int j = - 3; j < 4; j++)
{
if(i + DebLineY < 0 || j + DebLineX < 0)
continue;
COLORREF cr = GetPixel(hdc, j + DebLineX, i + DebLineY);
for(int a = 0; a < 8; a++)
for(int b = 0; b < 8; b++)
SetPixel(hdc, 400 + j*9+b, 200 + i*9+a, cr);
Как видишь, для получения этого hdc используется хоть и GetDC, но от LPDIRECTDRAWSURFACE4. Что не мешает потом вызывать SelectObject и SetBkMode
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Я утверждал, что ты работал через DirectDraw в том, что касается получения HDC. HDC у тебя не от GDI, а от DirectDraw. То есть это иной контекст. Используются ли при работе с ним средства от GDI — я не говорил вообще.
S>>Иной контекст твого утверждения, я полагаю? S>>
S>>Это значит, что у тебя был не GDI. Direct3D по крайней мере тогда работал через DirectDraw.
S>>Потому как контекст устройства там именно от GDI.
PD>Что-то я уже вообще не понимаю. Ты согласился вроде, что там через DirectDraw идет ?
Через — это значит что DirectDraw вызывает Lock, заполняет некую структуру GDI, и возвращает HDC. Больше здесь DirectDraw ни за что не отвечает.
PD>Ну вот тебе куски моего кода 10-летней давности PD>
Здравствуйте, samius, Вы писали:
PD>>Как видишь, для получения этого hdc используется хоть и GetDC, но от LPDIRECTDRAWSURFACE4. Что не мешает потом вызывать SelectObject и SetBkMode
S>Не мешает лишь потому что DirectDraw корректно заполнил заголовок. Всю работу SelectObject и SetBkMode делает именно GDI.
А я спорю ? Делает GDI, делает. Я же всего-то сказал, что HDC ты получмшь он DD, и хотя он бесспорно HDC, но относится к поверхности, созданной иными средствами — DirectDraw. И блиттинг там свой —
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
PD>>>Как видишь, для получения этого hdc используется хоть и GetDC, но от LPDIRECTDRAWSURFACE4. Что не мешает потом вызывать SelectObject и SetBkMode
S>>Не мешает лишь потому что DirectDraw корректно заполнил заголовок. Всю работу SelectObject и SetBkMode делает именно GDI.
PD>А я спорю ? Делает GDI, делает.
Я думал что ты споришь с тем, что там работает GDI.
>Я же всего-то сказал, что HDC ты получмшь он DD, и хотя он бесспорно HDC, но относится к поверхности, созданной иными средствами — DirectDraw. И блиттинг там свой —
GDI как раз поровну, чем там делана поверхность, хоть пальцем.
PD> STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, LPDDBLTFX) PURE;
Логично, что там блиттинг свой
Re[4]: GDI+ быстрый вывод
От:
Аноним
Дата:
15.12.10 13:16
Оценка:
Здравствуйте, samius, Вы писали:
S>Взял форму из стандартного шаблона, внес изменения только в From1.cs (в дизайнере ничего не менял). S>
S>public partial class Form1 : Form
S>{
S> public Form1()
S> {
S> InitializeComponent();
S> Paint += Form1_Paint;
S> SetStyle(ControlStyles.ResizeRedraw, true);
S> //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
S> }
S> void Form1_Paint(object sender, PaintEventArgs e)
S> {
S> var rect = ClientRectangle;
S> using (var pen = new Pen(Color.Red, 50))
S> e.Graphics.DrawLine(pen, rect.Left, rect.Top, rect.Right, rect.Bottom);
S> }
S>}
S>
S>При запуске в винде с включенной опцией "Рисовать окно при перетаскивании", рисуется красная жирная линия с безбожным фликанием во время ресайза формы. Раскомментирование второй строчки SetStyle флики убирает. S>Первая строчка SetStyle нужна для того что бы организовать автоматическую перерисовку при ресайзе формы.
А если так
public partial class TestForm : System.Windows.Forms.Form
{
Point m_ChooseBegPos;
Point m_LastMouseLocation;
bool m_InChoosing;
public TestForm()
{
InitializeComponent();
Paint += Form1_Paint;
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
void Form1_Paint(object sender, PaintEventArgs e) //или OnPaint(PaintEventArgs e) с вызовом base.OnPaint в конце
{
if(m_InChoosing)
using (var p = new Pen(Color.Red, 5))
{
Graphics gr = e.Graphics;
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);
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
m_ChooseBegPos = e.Location;
m_InChoosing = true;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
m_InChoosing = false;
Invalidate();
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
m_LastMouseLocation = e.Location;
if (m_InChoosing)
{
Invalidate();
}
base.OnMouseMove(e);
}
}
то мерцает ещё особенно если форма на весь экран.
добавил
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Мерцания прекратились но всё ещё заметно как линии не успевают за курсором. в windows explorerе или любом графическом редакторе так сильно не отстают.
Здравствуйте, samius, Вы писали:
S>Я думал что ты споришь с тем, что там работает GDI.
Да нет... В конце концов где там что в ядре в win32k.sys + драйвер видеокарты — черт разберется.
>>Я же всего-то сказал, что HDC ты получмшь он DD, и хотя он бесспорно HDC, но относится к поверхности, созданной иными средствами — DirectDraw. И блиттинг там свой — S>GDI как раз поровну, чем там делана поверхность, хоть пальцем.
Верно, но свойства у этого HDC иные, недели у созданного через CreateCompatibleDC/GetDC, к примеру.
PD>> STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, LPDDBLTFX) PURE; S>Логично, что там блиттинг свой
Здравствуйте, Pavel Dvorkin, Вы писали:
I>>Слушай, не смешно. Дохлый комп может швырять битмапы на экран с такой скоростью, что загрузка процессора в этом случае нисколько не растет
PD>Этим не процессор, а скорее всего видеокарта занимается.
В том то и дело. А вот если ты начнешь свои примитивы херачить, то аппаратное ускорение поможет только в GDI32. GDI+ это уже софтверный рендеринг, какие то клочки используют акселерацию от GDI32.
Так что твои мега-алгоритмы рисовавния пустых прямоугольников вполне могут кушать _больше_ процессора, нежели в случае с битмапами.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, samius, Вы писали:
S>>Взял форму из стандартного шаблона, внес изменения только в From1.cs (в дизайнере ничего не менял).
S>>При запуске в винде с включенной опцией "Рисовать окно при перетаскивании", рисуется красная жирная линия с безбожным фликанием во время ресайза формы. Раскомментирование второй строчки SetStyle флики убирает. S>>Первая строчка SetStyle нужна для того что бы организовать автоматическую перерисовку при ресайзе формы.
А>А если так
А>
А>public partial class TestForm : System.Windows.Forms.Form
А>
да, так моргает
А>то мерцает ещё особенно если форма на весь экран. А>добавил А>SetStyle(ControlStyles.AllPaintingInWmPaint, true);
А>Мерцания прекратились но всё ещё заметно как линии не успевают за курсором. в windows explorerе или любом графическом редакторе так сильно не отстают.
Открыл Paint, там резиновая R2Not рамка, как Павел советует. И отстает от курсора, но меньше. И моргает.
Открыл Paint.NET, там рамка с затемнением. Не моргает, но отстает от курсора сильнее.
if (g_pDDSBack->GetDC(&hdc) == DD_OK)
{
..
// Small windowfor(int i = - 3; i < 4; i++)
for(int j = - 3; j < 4; j++)
{
if(i + DebLineY < 0 || j + DebLineX < 0)
continue;
COLORREF cr = GetPixel(hdc, j + DebLineX, i + DebLineY);
for(int a = 0; a < 8; a++)
for(int b = 0; b < 8; b++)
SetPixel(hdc, 400 + j*9+b, 200 + i*9+a, cr);
Ну и код, вложенность от 5 и выше и куча констант в коде Ты его один что ли писал ?
Re[6]: GDI+ быстрый вывод
От:
Аноним
Дата:
15.12.10 13:43
Оценка:
Здравствуйте, samius, Вы писали:
S>Открыл Paint, там резиновая R2Not рамка, как Павел советует. И отстает от курсора, но меньше. И моргает. S>Открыл Paint.NET, там рамка с затемнением. Не моргает, но отстает от курсора сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
I>>Интересный аргумент — в байте 8 бит и поэтому вложенность 5 и всякие константы это нормально
PD>Во-первых, не 5, а все же 4.
5 = if + 4 for
В своем же коде не можешь вложенность посчитать А еще рассказываешь какие нынче плохие программисты.
>Во-вторых, это тест (стану я сюда что-то иное постить!). В третьих, в байте 8 бит, а окно это под байт
Для теста еще сгодится. А с байтом всетаки не ясно " 400 + j*9+b, 200 + i*9+a"
А>>Мерцания прекратились но всё ещё заметно как линии не успевают за курсором. в windows explorerе или любом графическом редакторе так сильно не отстают. S>Открыл Paint, там резиновая R2Not рамка, как Павел советует. И отстает от курсора, но меньше. И моргает. S>Открыл Paint.NET, там рамка с затемнением. Не моргает, но отстает от курсора сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, samius, Вы писали:
S>>Открыл Paint, там резиновая R2Not рамка, как Павел советует. И отстает от курсора, но меньше. И моргает. S>>Открыл Paint.NET, там рамка с затемнением. Не моргает, но отстает от курсора сильнее.
PD>Вот здесь
PD>http://files.rsdn.ru/187/BLOKOUT2.C
PD>пример из Петцольда. Если можешь, попробуй его и скажи, мигает или нет и как насчет отставания курсора
Скомпилил в best-optimization на GCC, запустил.
Мигает безбожно. Курсор отстает. Менее заметно, чем в Paint.NET, но не меньше чем в MS Paint. При быстром движении курсора легко отстает пикселов на 10-15. Машина не новая, но и не тормоз. C2D E6600 Win7.
PD>Компилировать без Unicode. 1995 год, однако
PD>P.S. В примере ошибка — неправильно берутся координаты при выходе курсора влево от окна или выше. Исправляется элементарно.
Оно мне надо? Своих хватает.
Здравствуйте, samius, Вы писали:
PD>>пример из Петцольда. Если можешь, попробуй его и скажи, мигает или нет и как насчет отставания курсора S>Скомпилил в best-optimization на GCC, запустил. S>Мигает безбожно. Курсор отстает. Менее заметно, чем в Paint.NET, но не меньше чем в MS Paint. При быстром движении курсора легко отстает пикселов на 10-15. Машина не новая, но и не тормоз. C2D E6600 Win7.
Любопытно.
На моей машине Phenom 955 / GeForce 9600 тоже мигает безбожно, более того, линии не всегда прорисовываются, так что иногда вместо видно только 3 стороны (конечно, тут же исправится, но заметно) А вот на работе старенький Athlon 4200/ GeForce 6150, что у нас в учебном классе стоит, не мигает, не отстает и вообще ведет себя замечательно.
Надо будет поисследовать.
Здравствуйте, Ikemefula, Вы писали:
I>В OnMouseMove ничего рисовать нельзя, иначе мерцание побороть не удастся. OnMouseMove должен устанвливать флаг обновления.
А можно поподробнее, какие проблемы с рисованием в OnMouse... ? Если AllPaintingInWmPaint, чем плохо в мышином обработчике делать синхронный Refresh() (или Invalidate+Update), вместо отложенного Invalidate ?
Хотя если ты имел ввиду в мышином обработчике this.CreateGraphics() , то понятно.
Для вызовов из OnMouseMove, Update (а из него OnPaint) — с этим противопоказаний нет?
Здравствуйте, Silver_S, Вы писали:
I>>В OnMouseMove ничего рисовать нельзя, иначе мерцание побороть не удастся. OnMouseMove должен устанвливать флаг обновления.
S_S> А можно поподробнее, какие проблемы с рисованием в OnMouse... ? Если AllPaintingInWmPaint, чем плохо в мышином обработчике делать синхронный Refresh()
(или Invalidate+Update), вместо отложенного Invalidate ?
Refresh это очень дорогое удовольствое, т.к. перерисовыват всю клиентскую область и все дочерние контролы. Update тоже недалеко ушел — это принудительный вызов OnPaint. В треде выше предлагалось вызывать не Update а рисовать прямо на экран. Во это и есть проблема.
Можно словить кое какие артефакты. Например Graphics, созданый явно руками, по мелочевке все равно отличается от того, что придет в OnPaint. Вроде все доступные проперти одинковые, а в отрисовке есть небольшая разница и это сильно раздражает. Ну и мерцание это отдельнй вопрос. Полностью подавить его можно только отрисовывая в битмап который в свою очередь нужно рисовать в OnPaint.
Кроме того, разделяя логику поведения и отрисовки код упрощается до безобразия. Но это конечно если ты понимаешь такие концепции как MVC
Здравствуйте, Silver_S, Вы писали:
S_S>Хотя если ты имел ввиду в мышином обработчике this.CreateGraphics() , то понятно. S_S>Для вызовов из OnMouseMove, Update (а из него OnPaint) — с этим противопоказаний нет?
Есть, это будет как минимум лишнее или же просядет перформанс. Напримерй в свей проге я такое просто не могу себе позволить
Не ясно, зачем тебе Update этот. Мне хватает одного Invalidate в OnMouseMove.
Здравствуйте, Ikemefula, Вы писали:
I>Можно словить кое какие артефакты. Например Graphics, созданый явно руками, по мелочевке все равно отличается от того, что придет в OnPaint. Вроде все доступные проперти одинковые, а в отрисовке есть небольшая разница и это сильно раздражает.
Что за разница? WinAPI.BeginPaint очищает фон и устанавливает Clip, в чем еще отличаи от WinAPI.GetDC, что-то связанное с фонтами и палитрами?
Если я рисую через Direct2D/3D а GDI используется только чтобы сбросить Bitmap на экран (иногда, если карточка слабая и надо обновить только маленький участок, поскольку DX10/11 умеет только все окно обновлять).
Какие-то проблемы могут быть? Не видел никаких артефактов.
Если код примерно такой:
_Texture.CopySubresourceRegionFrom(0, 0, 0, 0, backBuffer, 0, BoxMake.From2D(rect));
IntPtr hdc = GDIInterop.GetDC(_WindowHandle);
var mapped = _Texture.Map(0, Staging_MapMode.Read, false);
var rs = new SizeU(mapped.SystemMemoryPitch / 4, _CurSize.Height);
GDIInterop.SetDIBitsToDevice_BGRX(hdc, mapped.SystemMemory ,rs, true,
new Point2U(rect.Left, rect.Top), new RectU(0,0,rect.Width,rect.Height)
);
_Texture.Unmap(0);
GDIInterop.ReleaseDC(_WindowHandle, hdc);
I>Кроме того, разделяя логику поведения и отрисовки код упрощается до безобразия.
Одно другому не мешает. Разделить всегда можно.
Здравствуйте, Silver_S, Вы писали:
I>>Можно словить кое какие артефакты. Например Graphics, созданый явно руками, по мелочевке все равно отличается от того, что придет в OnPaint. Вроде все доступные проперти одинковые, а в отрисовке есть небольшая разница и это сильно раздражает.
S_S> Что за разница? WinAPI.BeginPaint очищает фон и устанавливает Clip, в чем еще отличаи от WinAPI.GetDC, что-то связанное с фонтами и палитрами?
Да, шрифты и палитры.
S_S> Если я рисую через Direct2D/3D а GDI используется только чтобы сбросить Bitmap на экран (иногда, если карточка слабая и надо обновить только маленький участок, поскольку DX10/11 умеет только все окно обновлять). S_S> Какие-то проблемы могут быть? Не видел никаких артефактов.
Мало ли чего ты не видел Но если ты рисуешь чисто битмапы, то проблем быть не должно. Но вот зачем это делать в OnMouseMove — ума не приложу.
S_S> Если код примерно такой:
Код я скипнул, т.к. мне непонятны названия и операции.
I>>Кроме того, разделяя логику поведения и отрисовки код упрощается до безобразия. S_S> Одно другому не мешает. Разделить всегда можно.
Ну да, все в одном обработчике и это называется разделение Если тебе нужно прорабатывать сложный бехевиор типа драг-дроп со всякими феньками и тд, то рисование в OnMouseMove просто невозможно отладить.
Здравствуйте, Ikemefula, Вы писали:
I>Есть, это будет как минимум лишнее или же просядет перформанс. Напримерй в свей проге я такое просто не могу себе позволить I>Не ясно, зачем тебе Update этот. Мне хватает одного Invalidate в OnMouseMove.
Почему здесь экран не перерисовывается пока мышка не остановится? 10 секунд ждать обновления экрана это нормальный перфоманс?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer,true);
}
public Point p;
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
p = e.Location;
System.Threading.Thread.Sleep(10);
Invalidate();
//Update();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(Color.White);
e.Graphics.DrawLine(Pens.Black, new Point(p.X, p.Y), new Point(p.X, p.Y + 100));
}
}
Здравствуйте, Silver_S, Вы писали:
I>>Не ясно, зачем тебе Update этот. Мне хватает одного Invalidate в OnMouseMove.
S_S>Почему здесь экран не перерисовывается пока мышка не остановится? 10 секунд ждать обновления экрана это нормальный перфоманс?
Ты прав, Update и Refresh хороши аккурат для Sleep в OnMouseMove.
Здравствуйте, Ikemefula, Вы писали:
I>Ты прав, Update и Refresh хороши аккурат для Sleep в OnMouseMove.
HitTesting от Sleep чем нибудь отличаются?
Ты предлагаешь делать(неявно) BeginPaint, перед HitTest и если не надо обновлять то return?
Да и где гарантии что перерисовка не станет залипать даже если OnMouseMove только флажок устанавливает.
И за счет чего должен перфоманс повыситься — за счет потери некоторых кадров (Inbalidate'ов) ?
Где гарантии что они будут теряться именно как надо?
По какому принципу теряются кадры при Invalidate не ясно, исходников нет, в документации это подробно не описано.
Зачем полагаться на такой скользкий функционал.
Не ясно, что у тебя за софтина с отрисовкой
S_S>HitTesting от Sleep чем нибудь отличаются?
Конечно. Правильно написаный хиттест много времени не отнимает. Проверено примерно на 100-200 тыс объектов.
S_S>Ты предлагаешь делать(неявно) BeginPaint, перед HitTest и если не надо обновлять то return?
Я этого не предлагаю Нужен хиттест — напиши его правильно.
S_S>Да и где гарантии что перерисовка не станет залипать даже если OnMouseMove только флажок устанавливает.
Перерисовка может замерзнуть, я про это писал. В своей проге например Hover пришлось отключить, потому что он влечет полную перерисовку в силу ряда причин.
S_S> И за счет чего должен перфоманс повыситься — за счет потери некоторых кадров (Inbalidate'ов) ?
Перформанс проседать не должен. Про повышение никто не говорил. Если тебе надо какие то клочки рисовать и насрать на побочные эффекты — рисуй где хочешь.
S_S>Где гарантии что они будут теряться именно как надо?
У тебя какая задача, что ты хочешь отрисовывать и какой хочешь бехевиор мышиный ?
S_S> По какому принципу теряются кадры при Invalidate не ясно, исходников нет, в документации это подробно не описано.
Какие еще выпадения кадров ?
S_S>Зачем полагаться на такой скользкий функционал.
Ты придумал какого то коня в вакууме. Я ведь вроде про русски написал :
"Это если ты конечно не игру пишешь и нет никаких тяжелых анимаций. Основной битмап обновляется крайне редко — у меня где то раз в несколько секунд или даже минут.
Вспомогательный, для мышиных операций, обновляется каждый раз когда есть выделение мышом и тд."
Функционал никакой не скользкий. Техника старая ка GDI32.
Здравствуйте, Ikemefula, Вы писали:
I>Какие еще выпадения кадров ?
Залипания. Когда не каждый MouseMove+Invalidate вызывает перерисовку, некоторые пропускаются.
Не вижу причин удалять Update, не уговоришь
Здравствуйте, Silver_S, Вы писали:
I>>Какие еще выпадения кадров ? S_S> Залипания. Когда не каждый MouseMove+Invalidate вызывает перерисовку, некоторые пропускаются.
В каком софте критичны эти кадры ?
S_S>Не вижу причин удалять Update, не уговоришь
Не удаляй, мне фиолетово чего у тебя в коде творится.
Здравствуйте, Ikemefula, Вы писали:
I>Не удаляй, мне фиолетово чего у тебя в коде творится.
Я привел пример когда вариант без Update может быть хуже.
Можешь привести пример когда с Update будет хуже? Я пока такого не видел.
Здравствуйте, Silver_S, Вы писали:
I>>Не удаляй, мне фиолетово чего у тебя в коде творится. S_S>Я привел пример когда вариант без Update может быть хуже.
Ты хорошо русский язык понимаешь ?
Ты хорошо понимаешь, что для разных приложений оптимальной будут разные схемы отрисовки ?
S_S>Можешь привести пример когда с Update будет хуже? Я пока такого не видел.
Ты много чего не видел вероятно. Если у тебя Invalidate вызывается исключительно в OnMouseMove и рисовать нужно мелочевку, то и ежу понятно, что в этом случае без разницы, как будет вызываться отрисовка — принудительно или нет. Дворкин привел хорший пример с отрисовкой четырех линий.
Своим Update ты только увеличиваешь частоту отрисовок, это в первую очередь ест перформанс. При этом нет никакой гарантии что твои кадры не будут пропадать.
Пример — надо отрисовывать чтото серьезное и Invalidate вызывается не только в OnMouseMove(бекграунд подгружается в фоне и тд). Получается не сильно приятная картина — от твоих Update никакого толку нет, т.к. все равно тоже самое надо отобразить обычным способм.
Второй пример — ты наводишь мышом на объект и он меняет стиль с Regular на Hovered. Убираешь мышь — стиль меняется на старый. Какой ректангл надо перерисовать ? Если ты можешь локализовать изменения, то только один объект. Если нет — перерисовывай всю сцену. Итого — Gdi+ сожрет все 100% ядра при движении мыша, потоу что аппаратного ускорения в Gdi+ почти что нет,
Спрошу еще раз, на всякий — ты хорошо русский язык понимаешь ?
Ты хорошо понимаешь, что для разных приложений оптимальной будут разные схемы отрисовки ?
Здравствуйте, Ikemefula, Вы писали:
I>Ты хорошо русский язык понимаешь ?
Намекаешь, что пытался на русском написать?
I>... Убираешь мышь — стиль меняется на старый. Какой ректангл надо перерисовать ? Если ты можешь локализовать изменения, то только один объект. Если нет — перерисовывай всю сцену.
Не понимаю как ректангл связан с отложенной перерисовкой.
I>... что для разных приложений оптимальной будут разные схемы отрисовки ?
Я про разные не спрашивал, а только про тот где не стоит Update вызывать.
Здравствуйте, Silver_S, Вы писали:
I>>... Убираешь мышь — стиль меняется на старый. Какой ректангл надо перерисовать ? Если ты можешь локализовать изменения, то только один объект. Если нет — перерисовывай всю сцену. S_S> Не понимаю как ректангл связан с отложенной перерисовкой.
Не понимаешь, зато советуешь именно этот способ. Неудивительно.
Здравствуйте, Аноним, Вы писали:
А>Появилась задача сделать выделение областей мышкой на форме. пробовал множество способов — у всех (кроме 1) при каждом движении курсора всё (или только линии выделения) безбожно мигает.
Вот такая панелька точно работает без мигания при отрисовке в обработчиках события OnPaint.
public class VirtualPanel : Panel
{
public VirtualPanel() :
base()
{
base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint, true);
}
}