Улучшить код для обработчиков WM_PAINT и WM_CTLCOLORSTATIC.

ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:

Я реализовал сложную отрисовку фона главного окна и его дочерних статических элементов управления.

На картинке ниже показано, как это выглядит.

введите здесь описание изображения

Статические элементы управления имеют стиль SS_NOTIFY, что важно упомянуть, так как определенные вещи происходят, когда пользователь нажимает на них.

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

И главное окно, и статические элементы управления имеют градиентный фон, который был создан с использованием GradientFill(...) API.

Верхний баннер главного окна создан серой кистью, а линии сетки созданы с помощью LineTo(...) и MoveTo(...) API.

Карта на оранжевом статическом элементе управления и верхний левый логотип — это EMF файлов, верхний правый логотип — это PNG файл, а остальные изображения — это растровые изображения.

Оранжевый статический элемент управления имеет 4 дочерних статических элемента управления, которые имеют owner drawn и стиль SS_NOTIFY.

Это был единственный способ, который я мог придумать, который позволил мне нарисовать элемент управления так, как меня просили (если я могу улучшить это, пожалуйста, предложите это, я приму любое разумное предложение).

Чтобы нарисовать оранжевый статический элемент управления, я решил нарисовать его фон в обработчике WM_CTLCOLORSTATIC, а владельцу нарисовать дочерние статические элементы управления в процедуре подкласса.

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

Я решил предоставить ссылку на демонстрационный проект, вместо того, чтобы делать этот пост довольно длинным с фрагментами кода.

Я попытался представить демонстрационное приложение настолько маленьким и простым, насколько это возможно.

Я не скупился на комментарии, поэтому считаю, что все хорошо освещено и объяснено в исходном коде.

Если остались вопросы, пожалуйста, оставьте комментарий, и я отвечу как можно скорее (обычно сразу или, по крайней мере, в тот же день).

Вот ссылка на демонстрационный проект:http://www.filedropper.com/geotermistgrafika_1

Важное обновление:

/==========================================================/

Текст ниже в квадратных скобках был исходной частью вопроса, но теперь опущен, поскольку в проекте были утечки памяти. Вышеприведенная ссылка ведет на улучшенную версию.

[ Обновлено в ответ на комментарий участника xMRi: Эта ссылка должна быть правильной: http://www.filedropper.com/geotermistgrafika ]

/==========================================================/

Я работаю на Windows XP, использую MS Visual Studio C++ и чистый Win32 API.

Одно примечание: поскольку версия VS Express не имеет редактора ресурсов, файл ресурсов и заголовок ресурса были созданы с помощью ResEdit отсюда: http://www.resedit.net/.

ПРОБЛЕМА:

Когда я изменяю размер окна, статические элементы управления слегка мерцают.

МОИ УСИЛИЯ ПО РЕШЕНИЮ ПРОБЛЕМЫ:

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

Я думаю, что я правильно обработал WM_ERASEBKGND, и я исключил стили CS_VREDRAW и CS_HREDRAW из своего класса окна - поэтому мерцание не должно вызываться из-за этого.

Я забыл упомянуть, что мое окно имеет стиль WS_CLIPCHILDREN, поэтому я упоминаю об этом сейчас, в ответ на комментарий ниже, сделанный участником Roger Rowland.

Я реализовал двойную буферизацию для обоих обработчиков, чтобы избежать мерцания.

ВОПРОСЫ:

  1. Как изменить код в демонстрационном проекте, чтобы избавиться от мерцания?

  2. Мне нужен совет, как оптимизировать обработчики WM_PAINT и WM_CTLCOLORSTATIC, чтобы мой код рисования стал более эффективным и быстрым.

Небольшое примечание ко второму вопросу:

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

Таким образом, я бы возвращал только NULL_BRUSH в своем обработчике WM_CTLCOLORSTATIC и выполнял всю работу в WM_PAINT.

Я на правильном пути с этой идеей? Может ли это работать?

Спасибо. С Уважением.


person AlwaysLearningNewStuff    schedule 02.11.2013    source источник
comment
Ссылка на демонстрационный проект не работает!   -  person xMRi    schedule 02.11.2013
comment
Ваше главное окно имеет стиль WS_CLIPCHILDREN?   -  person Roger Rowland    schedule 02.11.2013
comment
@RogerRowland Да, это так.   -  person AlwaysLearningNewStuff    schedule 02.11.2013
comment
@xMRi У меня никогда не было проблем с загрузкой, но в последнее время ссылка время от времени перестает работать, поэтому я загрузил проект в другое место. Надеюсь, проблема решена. С уважением.   -  person AlwaysLearningNewStuff    schedule 03.11.2013
comment
Мерцание происходит, когда вы рисуете более одного раза. Вы рисуете дважды. Один раз, чтобы нарисовать фон и один раз, чтобы нарисовать передний план. Вам нужно объединить их в один.   -  person Raymond Chen    schedule 04.11.2013
comment
@RaymondChen Можете ли вы дать краткие конкретные инструкции? Я был бы очень признателен, так как я понятия не имею, как это сделать в данный момент. С Уважением.   -  person AlwaysLearningNewStuff    schedule 04.11.2013
comment
Кратко: ничего не делайте в своем WM_PAINT. Делайте всю работу в WM_CTLCOLORSTATIC, в которой вы рисуете на экране только один раз. (Скомпонуйте все в растровое изображение, а затем BitBlt растровое изображение на экран.)   -  person Raymond Chen    schedule 05.11.2013


Ответы (1)


Во-первых, ваше приложение чертовски дырявое. Не искал утечки, но большинство из них должно быть в WM_CTLCOLORSTATIC, так как вы забыли удалить HBITMAP (используйте это удобное бесплатное программное обеспечение http://www.nirsoft.net/utils/gdi_handles.html для поиска утечек gdi).

Во-вторых, ваш код слишком большой. Я заметил, что вы не использовали функции, может быть, потому, что не знаете, на что они способны. Например, я бы использовал:

void DrawBackground(HDC &hDC, SOMEINFOSTRUCT GradientInfo, LPCTSTR Text);

чтобы значительно упростить ваш код.

Впрочем, хватит лекций, давайте вернемся к вашей проблеме. В WM_CTLCOLORSTATIC вы должны вернуть кисть, которой хотите рисовать фон. Теперь вы рисуете фон вручную, используя Bitblt(), затем возвращаете нулевую кисть, и программа рисует ее на уже нарисованном фоне. Вместо того, чтобы рисовать самостоятельно, пусть кисть сделает всю работу. Просто вместо последней Bitblt() используйте CreatePatternBrush(), но тогда вам нужно позаботиться об этой кисти, и вот что вы должны сделать:

HBRUSH TempBrush = NULL; //Create global brush

//Some Code....

case WM_CTLCOLORSTATIC:
    {
        if (TempBrush != NULL)
        {
            DeleteObject(TempBrush);
            TempBrush = NULL;
        }

        //Let's skip to the end....
        GradientFill( MemDC, vertex3, 3, &gTriangle, 1, 
        GRADIENT_FILL_TRIANGLE );

        TempBrush  = CreatePatternBrush(bmp);// these 3 line should be at the 
                                            //end of every if
        DeleteDC(MemDC);      // or put them once outside if's
        DeleteObject(bmp);  // also if you delete HDC first, you don't need to
                            //unselect hbitmap
        }
        return (LRESULT)TempBrush;
    }
    break;

case WM_CLOSE:
        {
            if (TempBrush != NULL)
            {
                DeleteObject(TempBrush);
                TempBrush = NULL;
            }
//.......
person FrogTheFrog    schedule 02.11.2013
comment
Вы правы, я довольно неопытен с Winapi. Вставлять вещи в функции и вызывать их там, где это необходимо, для меня сложно в данный момент, но я попробую. Вопрос для кисти: Должна ли она быть статической или просто глобальной переменной ? Возможно, это глупый вопрос, но я должен его задать. Я постараюсь реализовать ваши предложения и сообщу о своих результатах как можно скорее. Большое вам спасибо, я многому научился! С Уважением. - person AlwaysLearningNewStuff; 03.11.2013
comment
По сути, (глобальная переменная) == (статическая переменная вне каких-либо функций). Если вы создаете нестатическую переменную внутри функции, после того, как она существует, ее значение исчезнет. Но если вы хотите сохранить значение до следующего использования функции, вы добавляете static. - person FrogTheFrog; 03.11.2013
comment
Я просто должен был быть уверен, поговорю с вами вскоре после того, как получу какие-то результаты. Еще раз спасибо, с уважением. - person AlwaysLearningNewStuff; 03.11.2013
comment
Кажется, что эффект тот же. Я не заметил особых улучшений. Что касается GDIView, не могли бы вы объяснить мне, как вы отслеживали утечки памяти? Я включил параметр отображения Счетчики+Изменения F3 в меню Параметры, и все объекты имели нулевое значение, кроме шрифтов. Их размер быстро увеличивается при каждом изменении размера. Также у меня есть 4 региона, у которых в скобках указано значение +4. Возможно, я куда-то сливаю шрифты и регионы, но не знаю как, я считаю, что я все правильно подчистил. Скоро поговорим, я не сдаюсь. С уважением. - person AlwaysLearningNewStuff; 03.11.2013
comment
Если можете, загрузите свой исправленный/обновленный проект, я добавлю для вас кое-что полезное, также я постараюсь упростить вашу программу. Кроме того, в столбце All gdi (или что-то в этом роде) при запуске цикла сообщений должно быть 13 (или больше, если вы загружаете изображения из ресурсов) объектов. Затем оно должно увеличиться, скажем, до 24, но когда ваша программа снова простаивает, она должна вернуться к предыдущему числу. Я заметил, что ваш номер просто продолжал увеличиваться, и поэтому я узнал, что произошла утечка gdi (также в диспетчере задач быстро увеличивается используемая память). Затем вы должны посмотреть на другие столбцы и... - person FrogTheFrog; 03.11.2013
comment
... определите причину вашей проблемы (например, количество кистей постоянно увеличивалось). А затем вперед к кошмарным поискам справедливости в стране кода C++. Когда/если вы обновите свой проект, я добавлю оболочку CALLBACK, которая позволит вам сохранять обратные вызовы в классе, что позволит использовать локальные функции и переменные, потому что глобальные переменные - плохой выбор с точки зрения безопасности и прочего. - person FrogTheFrog; 03.11.2013
comment
Проект является коммерческим и поэтому не может быть полностью загружен. Эта часть рисования в демонстрационном проекте точно такая же, как и в основном проекте. Надеюсь, вы сможете сделать с ним то, что намеревались сделать с исходным. помогите, буду признателен.Спасибо.С уважением. - person AlwaysLearningNewStuff; 03.11.2013
comment
Роджер, тогда вам придется адаптировать мои изменения самостоятельно. - person FrogTheFrog; 03.11.2013
comment
давайте продолжим это обсуждение в чате - person FrogTheFrog; 04.11.2013
comment
Хотя есть больше возможностей для улучшения, я приму этот ответ, поскольку идея улучшения меня устраивает. Спасибо за помощь. С новым годом! С наилучшими пожеланиями. - person AlwaysLearningNewStuff; 12.01.2014