Рисование из другого потока без мерцания
От: ObKo  
Дата: 23.09.08 06:15
Оценка:
Есть некий поток в котором бесконечно выполняется:

Monitor::Enter(this);
Draw();
Monitor::Exit(this);


Draw():

G->Clear(Color::White);
//Дальше идет рисование фигур


G — Объект Graphics, полученый методом CreateGraphics() конрола.
Все рисуется нормально, только очень сильно мерцает.
Конрол самопальный, установка Style
ControlStyles::UserPaint | ControlStyles::AllPaintingInWmPaint | ControlStyles::DoubleBuffer

Не помогает.
Пробовал рисовать в битмап, потом выводить — сильно тормозит.

У кого какие есть мысли по этому поводу?
Re: Рисование из другого потока без мерцания
От: flenov www.hackishcode.com
Дата: 23.09.08 06:50
Оценка:
Попробуй переопределить OnPaintBackground и оставить его пустым. Это событие генерируется для прорисовки фона и закрашивает контрол цветом фона, а вот после этого ты уже рисуешь свое, поэтому и мерцание
Re: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 06:57
Оценка:
Здравствуйте, ObKo, Вы писали:

OK>Есть некий поток в котором бесконечно выполняется:

OK>Monitor::Enter(this);
OK>Draw();
OK>Monitor::Exit(this);


Чем вызвана необходимость рисовать из другого потока? В какой момент времени вы это делаете? Обработка-то WM_PAINT происходит в основном потоке…
Как и в какой момент времени вы получаете Graphics? Как начинаете рисовать?

OK>Конрол самопальный, установка Style

OK>ControlStyles::UserPaint | ControlStyles::AllPaintingInWmPaint | ControlStyles::DoubleBuffer

OK>Не помогает.

Ещё бы!

OK>Пробовал рисовать в битмап, потом выводить — сильно тормозит.


Как рисовали? В отдельном потоке? А как потом "выводили"?

OK>У кого какие есть мысли по этому поводу?


Сначала надо разобраться, что же мешает рисовать в основном потоке?
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Рисование из другого потока без мерцания
От: Аноним  
Дата: 23.09.08 06:58
Оценка:
Здравствуйте, flenov, Вы писали:

F>Попробуй переопределить OnPaintBackground и оставить его пустым. Это событие генерируется для прорисовки фона и закрашивает контрол цветом фона, а вот после этого ты уже рисуешь свое, поэтому и мерцание


Пробовал, не помогло....
Re[2]: Рисование из другого потока без мерцания
От: ObKo  
Дата: 23.09.08 07:03
Оценка:
Ок.
Программа просчитывает гравитационное взаимодействие двух и более тел. В дополнительном потоке просчитывается изменение координат и выводится результат на конрол.
Re[3]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 07:10
Оценка:
Здравствуйте, ObKo, Вы писали:

OK>Программа просчитывает гравитационное взаимодействие двух и более тел. В дополнительном потоке просчитывается изменение координат и выводится результат на конрол.


В смысле, расчёты долгие и каждый раз при отрисовке их делать тяжело?

Тогда делается так: отдельный поток рассчитывает данные и сообщает потоку GUI о том, что надо отрисоваться, например через SynchronizationContext. Поток GUI вызывает по наступлению этого события Invalidate, затем в обработчике OnPaint(…) по рассчитанным данным производится отрисовка. Остаётся только не забыть о синхронизации.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 23.09.08 07:52
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Сначала надо разобраться, что же мешает рисовать в основном потоке?


А, собственно говоря, что изменится от рисования в основном потоке ? Я вообще-то особенного криминала в рисовании в другом потоке не вижу — если, конечно, их не 10 и они не пытаются одновременно рисовать. . А так — пожалуйста. Если основной поток сейчас не рисует, а рисует другой — на здоровье. Здесь WM_PAINT и не пахнет.

Тут, похоже, иное. Что за самопальный контрол и не генерирует ли он WM_PAINT (InvalidateRect) каждую секунду или около того ? Вот если так — неудивительно. Один рисует, другой перерисовывает...
With best regards
Pavel Dvorkin
Re[3]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 07:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Тут, похоже, иное.


Фон мигает, естественно, не из-за этого.

А вот о практике или опыте рисования из разных потоков мне как-то раньше слышать ничего хорошего не прихдилось
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 23.09.08 08:37
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>А вот о практике или опыте рисования из разных потоков мне как-то раньше слышать ничего хорошего не прихдилось


Хм. Можем мы рисовать из разных место одного потока ? Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate. Естественно, надо куда-то добавить новую фигуру для возможного WM_PAINT, но в самой такой идее нет решительно ничего криминального. Более того, если WM_PAINT медленный, то это наилучшее решение. Да что там WM_LBUTTONDOWN — по таймеру ведь рисуют!

А теперь это же, но из другого потока. И что ? То же получение HDC окна , то же рисование. Честно говоря, не вижу разницы. Скажу больше — а как на десктопе рисуют ? Он-то уж точно не окно моего потока

Вот если 2 потока одновременно рисовать начнут — тогда точно ничего хорошего не выйдет
With best regards
Pavel Dvorkin
Re[5]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 23.09.08 09:38
Оценка:
Попробовал сейчас


   public partial class Form1 : Form
    {
        public bool stop;
        public void DoWork()
        {
            Graphics g = CreateGraphics();
            Pen pen = new Pen(Color.Blue);
            for (int i = 0; i < 10000; i++)
            {
                Thread.Sleep(10);
                if (stop)
                    return;
                g.DrawEllipse(pen, new Rectangle(0, 0, i, i));
            }
                
        }
        public Form1()
        {
            InitializeComponent();
            stop = false;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart threadDelegate = new ThreadStart(DoWork);
            Thread newThread = new Thread(threadDelegate);
            newThread.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            stop = true;
        }
    }


Ничего криминального не вижу и ничего не мигает. Естественно, при WM_PAINT рисунок не восстановится

Сорри за некорректные действия с переменной stop — лень было писать как следует.
With best regards
Pavel Dvorkin
Re[5]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 09:43
Оценка: 1 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

_FR>>А вот о практике или опыте рисования из разных потоков мне как-то раньше слышать ничего хорошего не прихдилось


PD>Хм. Можем мы рисовать из разных место одного потока?


Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.


Где такая техника применяется?

PD>Естественно, надо куда-то добавить новую фигуру для возможного WM_PAINT, но в самой такой идее нет решительно ничего криминального.


В я не вижу смысла, и потому она кажется криминальной: ну нарисуем мы что-нибудь, а потом свёрнём-развернём окно. И кто нам заново что-то отрисует? Что значит "куда-то добавить новую фигуру"? Можно нарисовать, например, в битмап, а из WM_PAINT рисовать уже с этого битмапа. Так рисование в битмап и рисование на окне — две разные вещи. В картинку можно рисовать не только из другого потока, но и из другого процесса, не важно. Рисовать же в окне нужно из WM_PAINT.

PD>Более того, если WM_PAINT медленный, то это наилучшее решение.


Что значит "WM_PAINT медленный" Я могу понять "GDI\GDI+ медленный". А скорость WM_PAINT такая, как мы её сделаем. Если рисовать быстро не получается, значит, надо что-то думать над тем, как бы ускорить WM_PAINT, а не над тем, где бы ещё порисовать. Конечно, если кто-то всё окно на каждый WM_PAINT перересовывает, то может быть медленно. Или инвалидирует, что бы хорошо не думать, так же всё целиком, то будет не быстро. Но ведь так можно и подругому: посчитал данные, потом посчитал, в какой части экрана они отображаются, и заинвалидировал этот региончик. В обработчике рисования (там известен квадрат, в котором надо рисовать) посчитал, где те данные, которые надо перерисовать, и перерисовал только их. Эти расчёты будут намного быстрее перерисовываний, дело за хорошо подобранной моделью данных.

PD>Да что там WM_LBUTTONDOWN — по таймеру ведь рисуют!


По таймеру рисуют так: в обработчике таймера рассчитывают данные. Затем рассчитывают регион, данные которого поменялись и инвалидируют регион. Всё: остальное сделает винда, выставив WM_PAINT. Скажу больше: именно под такую схему и подобраны (назначены) приоритеты сообщений WM_TIMER и WM_PAINT в потрохах винды. Отойти от этой схемы опять же не мешает ничто, кроме незнания и недоверия общепринятой практике.

PD>А теперь это же, но из другого потока. И что ? То же получение HDC окна , то же рисование. Честно говоря, не вижу разницы. Скажу больше — а как на десктопе рисуют ? Он-то уж точно не окно моего потока


Ага, это вот как раз и есть special case, который нужно применять очень осторожно на свой страх и риск (рисование на чёжом окне). Между прочим, что мешает от окна засабклассится и рисовать из его WM_PAINT? И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 23.09.08 10:27
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?


Я хотел бы знать, что в этом может быть плохого ?

PD>>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.


_FR>Где такая техника применяется?


Сплошь и рядом в Win32. Банальный, заурядный прием, из учебника. GetDC и т.д.

_FR>В я не вижу смысла, и потому она кажется криминальной: ну нарисуем мы что-нибудь, а потом свёрнём-развернём окно. И кто нам заново что-то отрисует?


Обработчик WM_PAINT.

>Что значит "куда-то добавить новую фигуру"? Можно нарисовать, например, в битмап, а из WM_PAINT рисовать уже с этого битмапа.


Да.

>Так рисование в битмап и рисование на окне — две разные вещи. В картинку можно рисовать не только из другого потока, но и из другого процесса, не важно. Рисовать же в окне нужно из WM_PAINT.


Ну это далеко не так. По WM_PAINT не рисуют, а отрисовывают инвалидную область. А рисовать можно где угодно. Естественно, при этом надо принять меры, чтобы в случае появления инвалидной области обработчик WM_PAINT нарисовал то же, отрисовал, иными словами. Но это еще может быть, очень нескоро будет.


PD>>Более того, если WM_PAINT медленный, то это наилучшее решение.


_FR>Что значит "WM_PAINT медленный"


Обработчик медленный. Много рисовать, и без битовой карты.

> Я могу понять "GDI\GDI+ медленный". А скорость WM_PAINT такая, как мы её сделаем. Если рисовать быстро не получается, значит, надо что-то думать над тем, как бы ускорить WM_PAINT, а не над тем, где бы ещё порисовать.


Какое это имеет отношение к вопросу ?

>Конечно, если кто-то всё окно на каждый WM_PAINT перересовывает, то может быть медленно. Или инвалидирует, что бы хорошо не думать, так же всё целиком, то будет не быстро. Но ведь так можно и подругому: посчитал данные, потом посчитал, в какой части экрана они отображаются, и заинвалидировал этот региончик. В обработчике рисования (там известен квадрат, в котором надо рисовать) посчитал, где те данные, которые надо перерисовать, и перерисовал только их. Эти расчёты будут намного быстрее перерисовываний, дело за хорошо подобранной моделью данных.


Нет. Если мне надо новый эллипс, вписанный в окно, нарисовать, то никакие прямоугольнички не получатся. Тут проще именно эллипс напрямую нарисовать, а на битовую карту его тоже положить. Это быстрее будет, чем делать копирование всей битовой карты для каждого эллипса. Последнее оставим для WM_PAINT, там никуда не денешься, придется всю картинку выводить. А здесь лишь эллипс.



PD>>Да что там WM_LBUTTONDOWN — по таймеру ведь рисуют!


_FR>По таймеру рисуют так: в обработчике таймера рассчитывают данные. Затем рассчитывают регион, данные которого поменялись и инвалидируют регион. Всё: остальное сделает винда, выставив WM_PAINT.


Сделает. Только медленно это будет.


>Скажу больше: именно под такую схему и подобраны (назначены) приоритеты сообщений WM_TIMER и WM_PAINT в потрохах винды. Отойти от этой схемы опять же не мешает ничто, кроме незнания и недоверия общепринятой практике.


Ты просто, видимо, с этой методикой не знаком. Честное слово, вполне стандартная методика в Win32.


PD>>А теперь это же, но из другого потока. И что ? То же получение HDC окна , то же рисование. Честно говоря, не вижу разницы. Скажу больше — а как на десктопе рисуют ? Он-то уж точно не окно моего потока


_FR>Ага, это вот как раз и есть special case, который нужно применять очень осторожно на свой страх и риск (рисование на чёжом окне). Между прочим, что мешает от окна засабклассится и рисовать из его WM_PAINT?


Сабклассить можно только окна своего процесса. Или хук вешай.

>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?


Visual Studio при старте. И другие.
With best regards
Pavel Dvorkin
Re[6]: Рисование из другого потока без мерцания
От: ObKo  
Дата: 23.09.08 11:20
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Попробовал сейчас



PD>
PD>   public partial class Form1 : Form
PD>    {
PD>        public bool stop;
PD>        public void DoWork()
PD>        {
PD>            Graphics g = CreateGraphics();
PD>            Pen pen = new Pen(Color.Blue);
PD>            for (int i = 0; i < 10000; i++)
PD>            {
PD>                Thread.Sleep(10);
PD>                if (stop)
PD>                    return;
PD>                g.DrawEllipse(pen, new Rectangle(0, 0, i, i));
PD>            }
                
PD>        }
PD>        public Form1()
PD>        {
PD>            InitializeComponent();
PD>            stop = false;
PD>        }

PD>        private void button1_Click(object sender, EventArgs e)
PD>        {
PD>            ThreadStart threadDelegate = new ThreadStart(DoWork);
PD>            Thread newThread = new Thread(threadDelegate);
PD>            newThread.Start();
PD>        }

PD>        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
PD>        {
PD>            stop = true;
PD>        }
PD>    }
PD>


PD>Ничего криминального не вижу и ничего не мигает. Естественно, при WM_PAINT рисунок не восстановится


PD>Сорри за некорректные действия с переменной stop — лень было писать как следует.
Re[6]: Рисование из другого потока без мерцания
От: Аноним  
Дата: 23.09.08 11:22
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Попробовал сейчас


PD>Ничего криминального не вижу и ничего не мигает. Естественно, при WM_PAINT рисунок не восстановится


PD>Сорри за некорректные действия с переменной stop — лень было писать как следует.



В том и проблема, что мне нужно очищать перед перересовкой!
Re[7]: Рисование из другого потока без мерцания
От: MxKazan Португалия  
Дата: 23.09.08 11:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, _FRED_, Вы писали:


_FR>>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>Я хотел бы знать, что в этом может быть плохого ?
Да вообще-т _FRED_ привел пример, что плохого. Никакой WM_PAINT ничего нам не отрисует, если мы банальным GetDC чего-то накалякаем из другого потока.
В любом случае, обращаться к контролам и их ресурсам рекомендуется только в том же потоке, где контрол создается.
Нарушать эту рекомендацию, значит вступать в противоречие с поведением ОС.

PD>>>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.

_FR>>Где такая техника применяется?
PD>Сплошь и рядом в Win32. Банальный, заурядный прием, из учебника. GetDC и т.д.
Я правильно понимаю, что в этом случае в WM_PAINT и в WM_LBUTTONDOWN все-таки один и тот же код рисует?

_FR>>В я не вижу смысла, и потому она кажется криминальной: ну нарисуем мы что-нибудь, а потом свёрнём-развернём окно. И кто нам заново что-то отрисует?

PD>Обработчик WM_PAINT.
>>Что значит "куда-то добавить новую фигуру"? Можно нарисовать, например, в битмап, а из WM_PAINT рисовать уже с этого битмапа.
PD>Да.
>>Так рисование в битмап и рисование на окне — две разные вещи. В картинку можно рисовать не только из другого потока, но и из другого процесса, не важно. Рисовать же в окне нужно из WM_PAINT.

PD>Ну это далеко не так. По WM_PAINT не рисуют, а отрисовывают инвалидную область. А рисовать можно где угодно. Естественно, при этом надо принять меры, чтобы в случае появления инвалидной области обработчик WM_PAINT нарисовал то же, отрисовал, иными словами. Но это еще может быть, очень нескоро будет.

Я еще не пробовал, но вроде WPF от данной проблемы избавляет. Правда ни о каких WM_PAINT'ах, GetDC и пр. там речи не идет.


>>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?

PD>Visual Studio при старте. И другие.
Серьезно?
Re: Рисование из другого потока без мерцания
От: ObKo  
Дата: 23.09.08 11:46
Оценка:
Все, проблему решил с помощью OnPaint и Invalidate()
Re[7]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 12:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

_FR>>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>Я хотел бы знать, что в этом может быть плохого ?

Большие проблемы в поддержке.

PD>>>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.

_FR>>Где такая техника применяется?
PD>Сплошь и рядом в Win32. Банальный, заурядный прием, из учебника. GetDC и т.д.

Какого учебника? Давайте конкретнее. А ещё лучше, на софт. это использующий.

_FR>>В я не вижу смысла, и потому она кажется криминальной: ну нарисуем мы что-нибудь, а потом свёрнём-развернём окно. И кто нам заново что-то отрисует?

PD>Обработчик WM_PAINT.
>>Что значит "куда-то добавить новую фигуру"? Можно нарисовать, например, в битмап, а из WM_PAINT рисовать уже с этого битмапа.
PD>Да.
>>Так рисование в битмап и рисование на окне — две разные вещи. В картинку можно рисовать не только из другого потока, но и из другого процесса, не важно. Рисовать же в окне нужно из WM_PAINT.
PD>Ну это далеко не так. По WM_PAINT не рисуют, а отрисовывают инвалидную область.

Извините, но вы выдумываете: покажите-ка мне где-либо в профессиональной литературе по данному вопросу термин "отрисовка" в контексте различия с "рисованием"?

PD>А рисовать можно где угодно. Естественно, при этом надо принять меры, чтобы в случае появления инвалидной области обработчик WM_PAINT нарисовал то же, отрисовал, иными словами. Но это еще может быть, очень нескоро будет.


Я же сам сказал — что рисовать можно что угодно и где угодно, но если это не будет сделано в WM_PAINT, то толку от этого нет. Рисование в картинку в любом потоке не отменяем рисование каринки в WM_PAINT.

PD>>>Более того, если WM_PAINT медленный, то это наилучшее решение.

_FR>>Что значит "WM_PAINT медленный"
PD>Обработчик медленный. Много рисовать, и без битовой карты.

Ага, а с битовой картой обработчик получается быстрым? Значит, я прав-таки, говоря, что скорость обработчика зависит от того, как его реализовать?

>>Конечно, если кто-то всё окно на каждый WM_PAINT перересовывает, то может быть медленно. Или инвалидирует, что бы хорошо не думать, так же всё целиком, то будет не быстро. Но ведь так можно и подругому: посчитал данные, потом посчитал, в какой части экрана они отображаются, и заинвалидировал этот региончик. В обработчике рисования (там известен квадрат, в котором надо рисовать) посчитал, где те данные, которые надо перерисовать, и перерисовал только их. Эти расчёты будут намного быстрее перерисовываний, дело за хорошо подобранной моделью данных.


PD>Нет. Если мне надо новый эллипс, вписанный в окно, нарисовать, то никакие прямоугольнички не получатся. Тут проще именно эллипс напрямую нарисовать, а на битовую карту его тоже положить. Это быстрее будет, чем делать копирование всей битовой карты для каждого эллипса. Последнее оставим для WM_PAINT, там никуда не денешься, придется всю картинку выводить. А здесь лишь эллипс.


А если у вас тысяса элипсов, то всю тысячу перерисовывать будете? Я бы не перересрвывал. еденица рисование — не пиксел, а примитив. До него и надо "округлять".

>>Скажу больше: именно под такую схему и подобраны (назначены) приоритеты сообщений WM_TIMER и WM_PAINT в потрохах винды. Отойти от этой схемы опять же не мешает ничто, кроме незнания и недоверия общепринятой практике.

PD>Ты просто, видимо, с этой методикой не знаком. Честное слово, вполне стандартная методика в Win32.

Возможно. Покажите-ка описание этой методики?

>>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?

PD>Visual Studio при старте.

Ага, а Spy++ запустить не пробовали?

Резюмируя: если вы знаете, что есть некая методика рисования не в обработчике WM_PAINT (именно рисования на окне, а не в буфере), то не могли бы дать мне с ней ознакомиться? Интересно, как следуя такой методике повышается скорость и появляются прочие бенефиты. Методика, о которой говорю я описана как в MSDN (Painting and Drawing), так и у Рихтера.
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 23.09.08 12:47
Оценка:
Здравствуйте, MxKazan, Вы писали:

MK>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Здравствуйте, _FRED_, Вы писали:


_FR>>>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>>Я хотел бы знать, что в этом может быть плохого ?
MK>Да вообще-т _FRED_ привел пример, что плохого. Никакой WM_PAINT ничего нам не отрисует, если мы банальным GetDC чего-то накалякаем из другого потока.

Слушай. я же ясно там написал, что надо обеспечить, чтобы по WM_PAINT отрисовывалось то же.

MK>В любом случае, обращаться к контролам и их ресурсам рекомендуется только в том же потоке, где контрол создается.

MK>Нарушать эту рекомендацию, значит вступать в противоречие с поведением ОС.

PD>>>>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.

_FR>>>Где такая техника применяется?
PD>>Сплошь и рядом в Win32. Банальный, заурядный прием, из учебника. GetDC и т.д.
MK>Я правильно понимаю, что в этом случае в WM_PAINT и в WM_LBUTTONDOWN все-таки один и тот же код рисует?

Нет. Простейший пример, первое задание, что я даю студентам. По WM_LBUTTONDOWN рисовать прямоугольники, а по WM_RBUTTONDOWN эллипсы. С backbuffer они еще не знакомы, поэтому список фигур

2 варианта

1. Рисуем по WM_?BUTTONDOWN и добавляем в список. По WM_PAINT отрисовываем весь список.
2. По WM_?BUTTONDOWN добавляем в список и InvalidateRect

В первом случае рисуется только одна фигура на нажатие кнопки. Весь список будет отрисовываться только когда будет инвалидная область. А она, мб, еще не скоро появится.
Во втором случае рисуется весь список. Всегда.

При 10-100 фигурах разницы в скорости нет. При тысячах — есть.

Естественно, в дальнейшем я их знакомлю с offscreen и битовыми картами, так что список выкидывается.

Но, конечно, рисовать они должны так, чтобы все сошлось. То есть WM_PAINT должен отрисовать список по тем же координатам и т.д, что и все WM_?BUTTONDOWN, вместе взятые.

Честно говоря, удивлен, что это надо объяснять. Это стандартная методика, еще раз говорю. Одна из двух.

MK>Я еще не пробовал, но вроде WPF от данной проблемы избавляет. Правда ни о каких WM_PAINT'ах, GetDC и пр. там речи не идет.


WPF избавляет . Он от много избавляет, в том числе от знания базовых принципов Win32. Не обижайся


>>>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?

PD>>Visual Studio при старте. И другие.
MK>Серьезно?

Абсолютно. Приложения, которые выводят стартовую картинку, рисуют на десктопе. GetDC(NULL). Это тоже общеизвестно. Вот, пожалуйста

http://img.meta.ua/rsdnsearch/?q=%F0%E8%F1%EE%E2%E0%F2%FC+%E4%E5%F1%EA%F2%EE%EF&amp;mode=rank&amp;group=N

А, пардон, где им еще рисовать ? Окна-то своего еще нет.

И кстати, характерный эффект. Если картинка висит достаточно долго, и за это время ее успеет перекрыть и уйти откуда-то взявшееся постороннее окно, то вместо картинки мы видим порой белый прямоугольник. Замечал такое ? В обычном окне такого не бывает — на то WM_PAINT есть. А тут просто рисование.
With best regards
Pavel Dvorkin
Re[9]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 23.09.08 12:53
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Нет. Простейший пример, первое задание, что я даю студентам. По WM_LBUTTONDOWN рисовать прямоугольники, а по WM_RBUTTONDOWN эллипсы. С backbuffer они еще не знакомы, поэтому список фигур


А, помню я такую книжку по МФЦ: там тоже в графическом редакторе рисовали гужки по левой кнопке. Но только вот это же учебник был: в следующей главе кружки уже сохранялись и рисовались в WM_PAINT.

>>>>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?

PD>>>Visual Studio при старте. И другие.
MK>>Серьезно?
PD>Абсолютно. Приложения, которые выводят стартовую картинку, рисуют на десктопе. GetDC(NULL). Это тоже общеизвестно. Вот, пожалуйста
PD>http://img.meta.ua/rsdnsearch/?q=%F0%E8%F1%EE%E2%E0%F2%FC+%E4%E5%F1%EA%F2%EE%EF&amp;mode=rank&amp;group=N
PD>А, пардон, где им еще рисовать ? Окна-то своего еще нет.
PD>И кстати, характерный эффект. Если картинка висит достаточно долго, и за это время ее успеет перекрыть и уйти откуда-то взявшееся постороннее окно, то вместо картинки мы видим порой белый прямоугольник. Замечал такое ? В обычном окне такого не бывает — на то WM_PAINT есть. А тут просто рисование.

Только вот как объяснить то, что можно навести сверху чужое окно, потом убрать, и оно отрисуется-таки?
Help will always be given at Hogwarts to those who ask for it.
Re[9]: Рисование из другого потока без мерцания
От: MxKazan Португалия  
Дата: 23.09.08 13:11
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

Ну, повеселились и хватит...

PD>Здравствуйте, MxKazan, Вы писали:


MK>>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>>Здравствуйте, _FRED_, Вы писали:


_FR>>>>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>>>Я хотел бы знать, что в этом может быть плохого ?
MK>>Да вообще-т _FRED_ привел пример, что плохого. Никакой WM_PAINT ничего нам не отрисует, если мы банальным GetDC чего-то накалякаем из другого потока.
PD>Слушай. я же ясно там написал, что надо обеспечить, чтобы по WM_PAINT отрисовывалось то же.

MK>>В любом случае, обращаться к контролам и их ресурсам рекомендуется только в том же потоке, где контрол создается.

MK>>Нарушать эту рекомендацию, значит вступать в противоречие с поведением ОС.
PD>>>>>Например, на WM_LBUTTONDOWN некое рисование делается тут же, без Invalidate.
_FR>>>>Где такая техника применяется?
PD>>>Сплошь и рядом в Win32. Банальный, заурядный прием, из учебника. GetDC и т.д.
MK>>Я правильно понимаю, что в этом случае в WM_PAINT и в WM_LBUTTONDOWN все-таки один и тот же код рисует?
PD>Нет. Простейший пример, первое задание, что я даю студентам. По WM_LBUTTONDOWN рисовать прямоугольники, а по WM_RBUTTONDOWN эллипсы. С backbuffer они еще не знакомы, поэтому список фигур
PD>Честно говоря, удивлен, что это надо объяснять. Это стандартная методика, еще раз говорю. Одна из двух.
Хаааа. Клааасс.. Я так и думал, что будет нечто подобное приведено. Ага, ага... только правильнее скорее описать, что это не способ рисования в Win32, а вообще просто методика рисования. И мы здесь всё же знакомы с битовыми картами

MK>>Я еще не пробовал, но вроде WPF от данной проблемы избавляет. Правда ни о каких WM_PAINT'ах, GetDC и пр. там речи не идет.

PD>WPF избавляет . Он от много избавляет, в том числе от знания базовых принципов Win32. Не обижайся
Ага, не обижаюсь. Ведь на самом деле WPF использует прицнип в чем то схожий с тем, что приведен тобой выше На даёт мне забыть! Спасибо ей

>>>>И, кстати, можно пример серьёзного (не поделки) приложения, которое рисует на десктопе?

PD>>>Visual Studio при старте. И другие.
MK>>Серьезно?
PD>Абсолютно. Приложения, которые выводят стартовую картинку, рисуют на десктопе. GetDC(NULL). Это тоже общеизвестно. Вот, пожалуйста

PD>http://img.meta.ua/rsdnsearch/?q=%F0%E8%F1%EE%E2%E0%F2%FC+%E4%E5%F1%EA%F2%EE%EF&amp;mode=rank&amp;group=N

PD>А, пардон, где им еще рисовать ? Окна-то своего еще нет.

PD>И кстати, характерный эффект. Если картинка висит достаточно долго, и за это время ее успеет перекрыть и уйти откуда-то взявшееся постороннее окно, то вместо картинки мы видим порой белый прямоугольник. Замечал такое ? В обычном окне такого не бывает — на то WM_PAINT есть. А тут просто рисование.

Окно то там вполне себе есть. А нет там стандартного message loop'а, поэтому при показе картинки, окно отрисовывают "насильно", а дальше перерисовывать уже некому, потому что приложение занято запуском.
Re[10]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 01:30
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>А, помню я такую книжку по МФЦ: там тоже в графическом редакторе рисовали гужки по левой кнопке. Но только вот это же учебник был: в следующей главе кружки уже сохранялись и рисовались в WM_PAINT.


Совершенно верно. 2 варианта, какой из них лучше — можно долго обсуждать, а если коротко — зависит от ситуации.

PD>>И кстати, характерный эффект. Если картинка висит достаточно долго, и за это время ее успеет перекрыть и уйти откуда-то взявшееся постороннее окно, то вместо картинки мы видим порой белый прямоугольник. Замечал такое ? В обычном окне такого не бывает — на то WM_PAINT есть. А тут просто рисование.


_FR>Только вот как объяснить то, что можно навести сверху чужое окно, потом убрать, и оно отрисуется-таки?


А черт его знает. Мне самому это не совсем понятно. Еще во аремена W95 я попробовал как-то сделать InvalidateRect(GetDesktopWindow(), ...). Никакого эффекта. В общем, десктоп — это , конечно, окно, но уж больно специфическое.

Посмотрел сейчас на него с помощью Spy++. Оказывается, оно WS_POPUP А также WS_VISIBLE (интересно, что будет, если ему сделать ShowWindow(hWnd, SW_HIDE) ?
With best regards
Pavel Dvorkin
Re[10]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 01:33
Оценка:
Здравствуйте, MxKazan, Вы писали:

PD>>Честно говоря, удивлен, что это надо объяснять. Это стандартная методика, еще раз говорю. Одна из двух.

MK>Хаааа. Клааасс.. Я так и думал, что будет нечто подобное приведено. Ага, ага... только правильнее скорее описать, что это не способ рисования в Win32, а вообще просто методика рисования. И мы здесь всё же знакомы с битовыми картами

Способ рисования, методика рисования... Слова, слова, слова. Называй хоть горшком, только в печь не сажай.

MK>>>Я еще не пробовал, но вроде WPF от данной проблемы избавляет. Правда ни о каких WM_PAINT'ах, GetDC и пр. там речи не идет.

PD>>WPF избавляет . Он от много избавляет, в том числе от знания базовых принципов Win32. Не обижайся
MK>Ага, не обижаюсь. Ведь на самом деле WPF использует прицнип в чем то схожий с тем, что приведен тобой выше На даёт мне забыть! Спасибо ей

Ну ин так

MK>Окно то там вполне себе есть.


Доказательства ?
With best regards
Pavel Dvorkin
Re[8]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 02:16
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>>>Рисовать можем. Я хотел бы знать, что в этом может быть хорошего?

PD>>Я хотел бы знать, что в этом может быть плохого ?

_FR>Большие проблемы в поддержке.


_FR>Какого учебника? Давайте конкретнее. А ещё лучше, на софт. это использующий.


Ну софт я искать не буду, нет времени, а вот учебник — пожалуйста

Петцольд. Programming Windows 95. Классика из классик. Все мы из этой книги вышли.

///////////////////////////////////////////////////////////////////////////////////////////////////

Getting a Device Context Handle: Method Two

Although it is best to structure your program so that you can update the entire client area during the WM_PAINT message, you may also find it useful to paint part of the client area while processing messages other than WM_PAINT. Or you may need a device context handle for other purposes, such as obtaining information about the device context.
...
Generally, you'll use the GetDC and ReleaseDC calls in response to keyboard messages (such as in a word processing program) or mouse messages (such as in a drawing program). This allows the program to draw on the client area in prompt reaction to the user's keyboard or mouse input without deliberately invalidating part of the client area to generate WM_PAINT messages. However, even if you paint during messages other than WM_PAINT, your program must still accumulate enough information to be able to update the display whenever you do receive a WM_PAINT message.


///////////////////////////////////////////////////////////////////////////////////////////////////

Кстати, могу привести еще пример, когда эта методика является не одной из двух возможных, а единственно возможной. Это рисование резинового контура. Суть, я думаю, ты помнишь — на WM_MOUSEMOVE рисуем 2 раза в режиме SetROP2 (R2_NOT или R2_XORPEN), второй вызов восстанавливает прежнее изображение, то есть то, что было под контуром. Так вот, тут делать каждый раз InvalidateRect с WM_PAINT попросту бессмысленно, это лишь трата времени. Все действия делаются прямо на WM_MOUSEMOVE. У Петцольда есть пример





void DrawBoxOutline (HWND hwnd, POINT ptBeg, POINT ptEnd)
     {
     HDC hdc ;

     hdc = GetDC (hwnd) ;

     SetROP2 (hdc, R2_NOT) ;
     SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
     Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;

     ReleaseDC (hwnd, hdc) ;
     }


          case WM_MOUSEMOVE :
               if (fBlocking)
                    {
                    SetCursor (LoadCursor (NULL, IDC_CROSS)) ;

                    DrawBoxOutline (hwnd, ptBeg, ptEnd) ;

                    ptEnd.x = LOWORD (lParam) ;
                    ptEnd.y = HIWORD (lParam) ;

                    DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
                    }
               return 0 ;


Кстати, и в учебнике по .Net такое же есть. Тот же Петцольд, но теперь книга по .Net.


protected override void OnMouseMove(MouseEventArgs mea)
{
Graphics grfx = CreateGraphics();
DrawWeb(grfx, BackColor, ptMouse);
ptMouse = new Point(mea.X, mea.Y);
DrawWeb(grfx, ForeColor, ptMouse);
grfx.Dispose();
}
protected override void OnPaint(PaintEventArgs pea)
{
DrawWeb(pea.Graphics, ForeColor, ptMouse);
}
void DrawWeb(Graphics grfx, Color clr, Point pt) // код опустил




_FR>Извините, но вы выдумываете: покажите-ка мне где-либо в профессиональной литературе по данному вопросу термин "отрисовка" в контексте различия с "рисованием"?


Тот же Петцольд. Надеюсь, не будете спорить, что это профессиональная литература Одна глава так и называется — "Painting and Repainting". Цитаты выше — из нее.

_FR>Я же сам сказал — что рисовать можно что угодно и где угодно, но если это не будет сделано в WM_PAINT, то толку от этого нет. Рисование в картинку в любом потоке не отменяем рисование каринки в WM_PAINT.


Разумееется.

_FR>Ага, а с битовой картой обработчик получается быстрым? Значит, я прав-таки, говоря, что скорость обработчика зависит от того, как его реализовать?


Быстрее, да. Но не всегда. Если в окне рисуется один круг, то быстрее без битовой карты .
Битовую карту обычно по двум причинам применяют. Во-первых, и это главное, она позволяет "закрыть" WM_ERASEBKGND, тем самым убрав очистку и мигание. Во-вторых, это действительно быстрее (но не всегда, например, если изображение меняется по таймеру, то это может оказаться медленнее)

А скорость чего угодно зависит от того, как его реализовать

_FR>А если у вас тысяса элипсов, то всю тысячу перерисовывать будете? Я бы не перересрвывал. еденица рисование — не пиксел, а примитив. До него и надо "округлять".


При чем тут пиксель — не понял. Эллипс как раз и есть примитив, а как тут округлять — тоже не понял.
А если нет битовой карты — придется- таки перерисовывать всю тысячу. Предложите иной способ

>>>Скажу больше: именно под такую схему и подобраны (назначены) приоритеты сообщений WM_TIMER и WM_PAINT в потрохах винды. Отойти от этой схемы опять же не мешает ничто, кроме незнания и недоверия общепринятой практике.

PD>>Ты просто, видимо, с этой методикой не знаком. Честное слово, вполне стандартная методика в Win32.

_FR>Возможно. Покажите-ка описание этой методики?


См. выше, цитату из Петцольда.

_FR>Резюмируя: если вы знаете, что есть некая методика рисования не в обработчике WM_PAINT (именно рисования на окне, а не в буфере), то не могли бы дать мне с ней ознакомиться? Интересно, как следуя такой методике повышается скорость и появляются прочие бенефиты. Методика, о которой говорю я описана как в MSDN (Painting and Drawing), так и у Рихтера.


Если речь идет о книге Рихтера для .Net — да, конечно, там именно это. В книгах же по Win32 он вообще о графике не говорит. Но Рихтер, прямо скажу, не есть большой авторитет в плане GDI. Вот в том, что касается ядра и т.д — другое дело, там он классик. А поскольку методика, о которой я говорю, относится к Win32, а в .Net не то чтобы очень популярна , то неудивительно, что Рихтер ее обходит вниманием.

А вообще, если есть желание узнать про скорость и получить всякие бенефиты — настойчиво рекомендую книгу Фень Юаня. Вот там действительно узнаешь все, что надо.
With best regards
Pavel Dvorkin
Re[9]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 24.09.08 06:56
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

_FR>>Какого учебника? Давайте конкретнее. А ещё лучше, на софт. это использующий.

PD>Ну софт я искать не буду, нет времени, а вот учебник — пожалуйста
PD>Петцольд. Programming Windows 95. Классика из классик. Все мы из этой книги вышли.

Хорошо, а теперь назовите главу, в которой рекомендуется так делать из чужого потока.

_FR>>Возможно. Покажите-ка описание этой методики?

PD>См. выше, цитату из Петцольда.

Нет, там (и в ваших) очень узкий пример: реакция на мышь. Понятно, что пока мы что-то рисуем над мышью, перекрыть это будет сложно. И, опять же, помните, с чего начался спор: Я говорю "Не рисуй из чужого пока", а вы: "А чего плохого"? А вот теперь выяснилось, что "рисование из чужого потока" по-вашему не отменяет рисование (или отрисовку, разница, как я вижу, лишь в том, что отрисовка — это рисование уже подготовленной картинки, я прав?).

Я утверждал (и продолжаю, ибо Петцольд не противоречит) что на окне надо рисовать из WM_PAINT. Ваши примеры — лишь очень редкие и частные случаи того, как можно делать. Я знаю только пару мест, в которых так поступают (рисование прямоугольника выделения в ListView да DragDrop) но не вижу, при чём тут многопоточность.

_FR>>Резюмируя: если вы знаете, что есть некая методика рисования не в обработчике WM_PAINT (именно рисования на окне, а не в буфере), то не могли бы дать мне с ней ознакомиться? Интересно, как следуя такой методике повышается скорость и появляются прочие бенефиты. Методика, о которой говорю я описана как в MSDN (Painting and Drawing), так и у Рихтера.


PD>Если речь идет о книге Рихтера для .Net — да, конечно, там именно это. В книгах же по Win32 он вообще о графике не говорит. Но Рихтер, прямо скажу, не есть большой авторитет в плане GDI. Вот в том, что касается ядра и т.д — другое дело, там он классик. А поскольку методика, о которой я говорю, относится к Win32, а в .Net не то чтобы очень популярна , то неудивительно, что Рихтер ее обходит вниманием.


Я говорю о книге по "Создание эффективных WIN32-приложений с учетом специфики 64-разрной версии Windows" в разделе сообщений windows просто говорится о приоритетах, и причинах того, что приоритет WM_PAINT ниже приоритета WM_TAIMER. Кстати, у Петцольд есть такой же (как вы описывали) пример рисования по таймеру?
Help will always be given at Hogwarts to those who ask for it.
Re[11]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 24.09.08 06:57
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

MK>>Окно то там вполне себе есть.

PD>Доказательства ?

Я запустил Spy++ и узнал, что класс этого окна VSSplash.
Help will always be given at Hogwarts to those who ask for it.
Re[10]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 07:56
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Хорошо, а теперь назовите главу, в которой рекомендуется так делать из чужого потока.


Этого я не назову. Но напомню то, с чего начал. Я сказал, что не вижу никакого криминала в этом. Если Вы можете объяснить, в чем здесь криминал — я готов отказаться от своих слов. Но не раньше.

_FR>Нет, там (и в ваших) очень узкий пример: реакция на мышь. Понятно, что пока мы что-то рисуем над мышью, перекрыть это будет сложно.


Разумеется, не отменяет. Само собой. Где я говорил, что отменяет ?
Что же касается того, что это очень узкий пример — ну знаете, так можно долго дискутировать. Вот вам еще один пример — рисование по таймеру (см. внизу) Я еще помню пример с фракталами, но, увы, текст привести не могу, он из старой книги по Win16, по которой я когда-то изучал программирование для Windows, и диска там не было. Но заверяю честным словом, рисование там шло так же. На это Вы, конечно, можете ответить, что и это узкий пример — но так Вы с меня будете требовать пример за примером, я не могу этим заниматься .

_FR>И, опять же, помните, с чего начался спор: Я говорю "Не рисуй из чужого пока", а вы: "А чего плохого"? А вот теперь выяснилось, что "рисование из чужого потока" по-вашему не отменяет рисование (или отрисовку, разница, как я вижу, лишь в том, что отрисовка — это рисование уже подготовленной картинки, я прав?).


Я в своей терминологии называю отрисовкой любое действие, выполняемое по WM_PAINT. Подготовлена к этому моменту картинка или же OnPaint будет рисовать какой-то список фигур — не суть важно. А рисованием я называю любые изменения в любом контексте за пределами обработчика WM_PAINT (и в окне на мышь, и в backbuffer где угодно, и хоть на принтере). За терминологию я не стою, если хотите другую — бога ради.

_FR>Я утверждал (и продолжаю, ибо Петцольд не противоречит) что на окне надо рисовать из WM_PAINT. Ваши примеры — лишь очень редкие и частные случаи того, как можно делать. Я знаю только пару мест, в которых так поступают (рисование прямоугольника выделения в ListView да DragDrop) но не вижу, при чём тут многопоточность.


У нас тут 2 вопроса получились, так вот, давайте отдельно.
Первое — можно ли рисовать (в смысле, что я выше привел) вне WM_PAINT ? Ответ — можно, и Вы с этим согласны, хотя и считаете, что это очень редкие случаи. Я этого не считаю, но это уже спор, который не стоит продолжать.
Второе — можно ли это делать из другого потока. Здесь см. мое замечание в начале этого постинга.


_FR>Я говорю о книге по "Создание эффективных WIN32-приложений с учетом специфики 64-разрной версии Windows" в разделе сообщений windows просто говорится о приоритетах, и причинах того, что приоритет WM_PAINT ниже приоритета WM_TAIMER.


Да, знаком, конечно , на лекции рассказываю. Но из этого следует только, что только при данной расстановке приоритетов вариант с InvalidateRect будет корректен. Если приоритеты поставить иначе, он может быть просто некорректным. Однако из этого не следует ничего в отношении второго варианта.

>Кстати, у Петцольд есть такой же (как вы описывали) пример рисования по таймеру?


Да. Но чуть более хитрый. Да простит меня модератор за цитирование не по профилю форума



// в Winmain

hwnd = CreateWindow(szAppName, "Beeper2 Timer Demo",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
while(!SetTimer(hwnd, ID_TIMER, 1000,(TIMERPROC) TimerProc))


Таймер создается с отдельной callback функцией TimerProc


VOID CALLBACK TimerProc(HWND hwnd, UINT iMsg, UINT iTimerID, DWORD dwTime)
{
static BOOL fFlipFlop = FALSE;
HBRUSH hBrush;
HDC hdc;
RECT rc;
MessageBeep(0);
fFlipFlop = !fFlipFlop;
GetClientRect(hwnd, &rc);
hdc = GetDC(hwnd);
hBrush = CreateSolidBrush(fFlipFlop ? RGB(255,0,0) : RGB(0,0,255));
FillRect(hdc, &rc, hBrush);
ReleaseDC(hwnd, hdc);
DeleteObject(hBrush);
}

В общем, флип-флоп :-)
With best regards
Pavel Dvorkin
Re[12]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 07:59
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Я запустил Spy++ и узнал, что класс этого окна VSSplash.


Доказательство принято.
With best regards
Pavel Dvorkin
Re[11]: в дополнение
От: Pavel Dvorkin Россия  
Дата: 24.09.08 08:16
Оценка:
Кстати, посмотрел еще раз в книге Петцольда по C#. Там примеров с рисованием вне Onpaint не так уж мало. Хинт — поиск по слову CreateGraphics.

Вот твои часы (аналоговые, правда)


//-------------------------------------------
// AnalogClock.cs c 2001 by Charles Petzold
//-------------------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
using Petzold.ProgrammingWindowsWithCSharp;

class AnalogClock: Form
{
     ClockControl clkctl;

     public static void Main()
     {
          Application.Run(new AnalogClock());
     }
     public AnalogClock()
     {
          Text = "Analog Clock";
          BackColor = SystemColors.Window;
          ForeColor = SystemColors.WindowText;

          clkctl = new ClockControl();
          clkctl.Parent    = this;
          clkctl.Time      = DateTime.Now;
          clkctl.Dock      = DockStyle.Fill;
          clkctl.BackColor = Color.Black;
          clkctl.ForeColor = Color.White;

          Timer timer    = new Timer();
          timer.Interval = 100;
          timer.Tick    += new EventHandler(TimerOnTick);
          timer.Start();
     }
     void TimerOnTick(object obj, EventArgs ea)
     {
          clkctl.Time = DateTime.Now;
     }
}

Здесь ставится свойство Time и вот что этот сеттер делает


[c#]
     public DateTime Time
     {
          set 
          { 
               Graphics grfx = CreateGraphics();
               InitializeCoordinates(grfx);

               Pen pen = new Pen(BackColor);

               if (dt.Hour != value.Hour)
               {
                    DrawHourHand(grfx, pen);
               }
               if (dt.Minute != value.Minute)
               {
                    DrawHourHand(grfx, pen);
                    DrawMinuteHand(grfx, pen);
               }
               if (dt.Second != value.Second)
               {
                    DrawMinuteHand(grfx, pen);
                    DrawSecondHand(grfx, pen);
               }
               if (dt.Millisecond != value.Millisecond)
               {
                    DrawSecondHand(grfx, pen);
               }          
               dt  = value;
               pen = new Pen(ForeColor);

               DrawHourHand(grfx, pen);
               DrawMinuteHand(grfx, pen);
               DrawSecondHand(grfx, pen);

               grfx.Dispose();
          }
     }


Убедил ?
With best regards
Pavel Dvorkin
Re[11]: Рисование из другого потока без мерцания
От: _FRED_ Черногория
Дата: 24.09.08 08:51
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

_FR>>Хорошо, а теперь назовите главу, в которой рекомендуется так делать из чужого потока.


PD>Этого я не назову. Но напомню то, с чего начал. Я сказал, что не вижу никакого криминала в этом. Если Вы можете объяснить, в чем здесь криминал — я готов отказаться от своих слов. Но не раньше.


В ковырянии в носу так же нет никакого криминала, однако в некоторых местах это просто… не считается хорошей практикой (аргументом тому может служить отсутствие статей и примеров уважаемых специалистов).

_FR>>Нет, там (и в ваших) очень узкий пример: реакция на мышь. Понятно, что пока мы что-то рисуем над мышью, перекрыть это будет сложно.


PD>Разумеется, не отменяет. Само собой. Где я говорил, что отменяет ?

PD>Что же касается того, что это очень узкий пример — ну знаете, так можно долго дискутировать. Вот вам еще один пример — рисование по таймеру (см. внизу) Я еще помню пример с фракталами, но, увы, текст привести не могу, он из старой книги по Win16, по которой я когда-то изучал программирование для Windows, и диска там не было.

Это чисто учебные и экзотические примеры: не станете же вы утверждать, что это мэйнстрим. Например, если изменять размер окна или таскать его туда-сюда, пока таймер его рисует, то можно будет заметить неприятные артефакты. Для студентов сойдёт.

PD>Но заверяю честным словом, рисование там шло так же. На это Вы, конечно, можете ответить, что и это узкий пример — но так Вы с меня будете требовать пример за примером, я не могу этим заниматься .


Я просил пример реального приложения, которое нельзя было бы назвать поделкой и не получил. Вместо этого получил главы из _учебника_, целью которого является "показать как можно", а не "как надо".

PD>Первое — можно ли рисовать (в смысле, что я выше привел) вне WM_PAINT ? Ответ — можно, и Вы с этим согласны, хотя и считаете, что это очень редкие случаи. Я этого не считаю, но это уже спор, который не стоит продолжать.

PD>Второе — можно ли это делать из другого потока. Здесь см. мое замечание в начале этого постинга.

Потоки так же можно завершать через TerminateThread, а с памятью работать с помощью голых указателей. Но первое, несмотря на то, что существует, повсеместно признано неверным, а для второго придумано множество более удобных способов. Наличие какой-либо возможности вовсе не говорит о том, что ей, этой возможностью, следует пользоваться.

C#, например, позволяет работать c неуправляемыми указателями. Единственно упоминание их в соседнем, наверное, самом посещаемом в рунете форуме, в этюдах nikov-а. Я думаю, это о многом говорит, но на это, при желании, можно и не обращать внимание.

_FR>>Я говорю о книге по "Создание эффективных WIN32-приложений с учетом специфики 64-разрной версии Windows" в разделе сообщений windows просто говорится о приоритетах, и причинах того, что приоритет WM_PAINT ниже приоритета WM_TAIMER.


PD>Да, знаком, конечно , на лекции рассказываю. Но из этого следует только, что только при данной расстановке приоритетов вариант с InvalidateRect будет корректен. Если приоритеты поставить иначе, он может быть просто некорректным. Однако из этого не следует ничего в отношении второго варианта.


Из этого следует, что о рисовании из таймера подумали зазработчики ОС, а так же то, какое решение они для данного случая нашли.

>>Кстати, у Петцольд есть такой же (как вы описывали) пример рисования по таймеру?


Выше я про него рассказал. Для студента или поделки, быть может, и сойдёт. Для мэйнстрима — нет.
Help will always be given at Hogwarts to those who ask for it.
Re[12]: в дополнение
От: _FRED_ Черногория
Дата: 24.09.08 08:58
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Кстати, посмотрел еще раз в книге Петцольда по C#. Там примеров с рисованием вне Onpaint не так уж мало. Хинт — поиск по слову CreateGraphics.

PD>Вот твои часы (аналоговые, правда)

И не сомневаюсь — он показывает "как можно", а не "как надо". Вот можете ли вы аналитически сказать, тем показанный пример лучше того, чем вызов Invalidate и обработка WM_PAINT?

PD>Убедил ?


Нет, ибо наличие примера не показывает того, что он описывает правильную практику. Сомневаюсь, что автор говорит о том, почему указанный пример _нельзя_ делать по-другому (то есть, почему другое решения является неправильным).
Help will always be given at Hogwarts to those who ask for it.
Re[12]: Рисование из другого потока без мерцания
От: Pavel Dvorkin Россия  
Дата: 24.09.08 09:17
Оценка:
Здравствуйте, _FRED_, Вы писали:


_FR>В ковырянии в носу так же нет никакого криминала, однако в некоторых местах это просто… не считается хорошей практикой (аргументом тому может служить отсутствие статей и примеров уважаемых специалистов).


Я же не о том, хорошая практика это или нет, а о том, что в этом криминала нет, писал. А о том, хорошая ли это практика или нет — спорить не буду, так как за такой метод вовсе не стою горой. Я лишь утверждаю, что криминала в этом нет.



_FR>Это чисто учебные и экзотические примеры: не станете же вы утверждать, что это мэйнстрим. Например, если изменять размер окна или таскать его туда-сюда, пока таймер его рисует, то можно будет заметить неприятные артефакты. Для студентов сойдёт.


Ну вот, пожалуйста. Сначала Вы просите ссылки на учебник. Я их даю, с цитированием, из книги классика и по Win32, и по .Net. Теперь оказывается, что это чисто учебные примеры (а какие еще вы в учебнике хотите ? )

Дело не в студентах и не в таймере. Дело в том, что в принципе такое возможно и допустимо.. Это все, что я заявляю. Хорошо это или плохо — зависит от ситуации. Что касается мэйнстрим это или нет — это мне попросту неинтересно. В конкретной ситуации я буду решать, какой из двух вариантов ей больше подходит, и мне не важно, какой из них мэйнстрим, а какой нет. вот если бы второй вариант был технически ошибочен и мог привести к неправильной работе — тогда другое дело.

Что касается артефактов, то они возможны, и поэтому я выберу тот вариант, которы йнаилучшим образом подходит для конкретной задачи. В том числе чтобы и не было артефактов.

Кстати, что за проблема возникнет при перетаскивании окна ? При этом WM_PAINT не шлют. Вот при изменении размера — шлют, и то не всегда, а если стоят CS_HREDRAW и/или CS_VREDRAW в стилях класса.

_FR>Я просил пример реального приложения, которое нельзя было бы назвать поделкой и не получил. Вместо этого получил главы из _учебника_, целью которого является "показать как можно", а не "как надо".


Так. Извиняюсь, но вынужден цитировать

>Какого учебника? Давайте конкретнее. А ещё лучше, на софт. это использующий


http://www.rsdn.ru/forum/message/3113396.1.aspx
Автор: _FRED_
Дата: 23.09.08


Я и дал конкретнее некуда. А искать исходники программ и смотреть, где и как рисуют, у меня времени нет. Извините, но этим заниматься не буду.


_FR>Потоки так же можно завершать через TerminateThread


Можно. Не рекомендуется, но при соблюдении определенных требований — вполне безопасно.

>а с памятью работать с помощью голых указателей.


Ну это за пределами .Net обычная практика

>Но первое, несмотря на то, что существует, повсеместно признано неверным


Не рекомендуемым. Утверждать, что это всегда неверно — неверно. Функции, вызов которых всегда недопустим, не имеют права на существование. Функции, вызова которых надо избегать до последней возможности, а если уж вызываешь — детально проанализировать, какие неприятные последствия от этого могут быть и предупредить их — возможны.

>а для второго придумано множество более удобных способов. Наличие какой-либо возможности вовсе не говорит о том, что ей, этой возможностью, следует пользоваться.


+1. Я бы так сказал — надо проанализировать, стоит ли ей пользоваться, какие преимущества мы можем получить. Истина всегда конкретна.

_FR>C#, например, позволяет работать c неуправляемыми указателями. Единственно упоминание их в соседнем, наверное, самом посещаемом в рунете форуме, в этюдах nikov-а. Я думаю, это о многом говорит, но на это, при желании, можно и не обращать внимание.


Нет, не могу я не обращать внимание на эти неуправляемые указатели. Потому что программа моя, которую я сделал — это просто GUI к некоторой неуправляемой DLL, которая меня именно этими неуправляемыми указателями и кормит. Так что я на них свою зарплату получаю. И в этом плане большое спасибо MS, что они их сделали доступными.


PD>>Да, знаком, конечно , на лекции рассказываю. Но из этого следует только, что только при данной расстановке приоритетов вариант с InvalidateRect будет корректен. Если приоритеты поставить иначе, он может быть просто некорректным. Однако из этого не следует ничего в отношении второго варианта.


_FR>Из этого следует, что о рисовании из таймера подумали зазработчики ОС


Верно. Не допустили ошибки. Или вовремя исправили

>а так же то, какое решение они для данного случая нашли.


Неверно. Они просто расставили приоритеты. К тому, что не относится к вопросу приоритетов, это решения отношения не имеет. они не могли сделать иначе, так как пришлось бы отвечать на вопрос — что делать, если таймер работает быстрее, чем окно перерисовывается путем InvalidateRect, и ответа бы не было. А дать ответ — не используйте для этой цели InvalidateRect — нельзя, почему это его я не могу использовать когда хочу, что за исключение из правил ?

_FR>Выше я про него рассказал. Для студента или поделки, быть может, и сойдёт. Для мэйнстрима — нет.


With best regards
Pavel Dvorkin
Re[13]: в дополнение
От: Pavel Dvorkin Россия  
Дата: 24.09.08 09:35
Оценка: 1 (1)
Здравствуйте, _FRED_, Вы писали:

_FR>И не сомневаюсь — он показывает "как можно", а не "как надо". Вот можете ли вы аналитически сказать, тем показанный пример лучше того, чем вызов Invalidate и обработка WM_PAINT?


Да, конечно. На каждый тик таймера здесь меньше рисуется. К примеру, не перерисовывается окружность часов — незачем. А если по Invalidate всерьез делать — надо битовую карту и BitBlt. А это намного медленнее, чем несколько стрелок (линий) нарисовать.

PD>>Убедил ?


_FR>Нет, ибо наличие примера не показывает того, что он описывает правильную практику. Сомневаюсь, что автор говорит о том, почему указанный пример _нельзя_ делать по-другому (то есть, почему другое решения является неправильным).


А кто сказал, что нельзя по-другому ? Можно. Но и так можно.

Я не думаю, что автор признанного учебника стал бы рекомендовать то, что делать не стоит. Его бы давно высмеяли, а его вместо этого классиком считают. Мы с Вами давно не студенты, а поэтому можем сранивать оба варианта со знанием дела. А ведь студенты, только приступающие к изучению предмета, воспринимают учебник как рекомендацию того, что делать можно. Как-то странно было бы, если бы учебник рекомендовал порочную практику, не так ли ? Да еще лучший в мире учебник.

Не обижайтесь, но мое мнение очень простое. Вы столкнулись с подходом решения задачи, решение которой Вам хорошо известно, но другим подходом. Теперь этот другой подход вызывает у Вас реакцию "доказать, что он неверен". Ничего в этой реакции особенного нет, я , наверное, так же поступил бы. Психологически это вполне объяснимо. Но не стоит дальше искать эти доказательства. Этот подход существует, он вполне возможен, но я вовсе не призываю Вас забыть все, что Вы знали раньше. Просто примите спокойно как факт. что вот такое возможно, и совсем не обязательно так делать.

Кстати, если бы в форуме по Win32 я бы начал с таким усердием доказывать, что это возможно, меня бы просто не поняли — чего он в открытую дверь ломится, нашел что доказывать

За сим, как говорили в старину, примите и проч., а я свое участие в этой дискуссии прекращаю. Аргументы обеих сторон высказаны, новых у них нет, так что дальше продолжать не стоит ИМХО.
With best regards
Pavel Dvorkin
Re[11]: Рисование из другого потока без мерцания
От: MxKazan Португалия  
Дата: 24.09.08 09:51
Оценка: :)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, MxKazan, Вы писали:


MK>>Окно то там вполне себе есть.


PD>Доказательства ?


"Честно говоря, удивлен, что это надо объяснять. Это стандартная методика, еще раз говорю."
Re: Рисование из другого потока без мерцания
От: TK Лес кывт.рф
Дата: 24.09.08 14:47
Оценка:
Здравствуйте, ObKo, Вы писали:

OK>G — Объект Graphics, полученый методом CreateGraphics() конрола.

OK>Все рисуется нормально, только очень сильно мерцает.
OK>Конрол самопальный, установка Style

надо перекрывть метод OnPaint и в нем помечать область окна как валидную без какой-либо отрисовки. После этого, рисовать ее из другого потока как и обычно.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.