Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/18: Рейтинг темы: голосов - 18, средняя оценка - 4.50
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151

Реализация двойной буферизации для рисования графических примитивов

19.11.2018, 23:56. Показов 3707. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Решил я значит порисовать всяких кружков-квадратиков, а они мерцают. Убрал эффект наполовину, перестав обрабатывать WM_ERASEBKGND. Однако мерцание не ушло, ушел только белый цвет фона. Нашел, что проблему можно решить двойной буферизацией, но у меня не очень-то получилось((( вот код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);//получение контекста
            hdcMemDC = CreateCompatibleDC(hdc);
 
 
 
            GetClientRect(hwnd,&r);//работа с рабочей областью
            cx=r.right;
            cy=r.bottom;
 
            background.top=0;//объявление фонового прямоугольника
            background.bottom=cy-1;
            background.right=cy-1;
            background.left=0;
 
          //  br = CreateSolidBrush(RGB(0,0,140));
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(0,0,140)));
 
            Rectangle(hdcMemDC, 0, 0, cy-1, cy-1);//рисуем фоновый прямоугольник
            //FillRect(hdc,&background,br);
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(100,0,0)));
 
            Ellipse(hdcMemDC, cy/2 - 10, cy/2 - 10, cy/2 +10, cy/2+10);
 
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            BitBlt(hdc, 0, 0, cx, cy, hdcMemDC, 0, 0, SRCCOPY);
 
            DeleteDC(hdcMemDC);
            EndPaint(hwnd, &ps);
            InvalidateRect(hwnd, NULL, NULL);
 
            break;
           case  WM_ERASEBKGND :
          break;
Почему-то ничего не рисуется, просто белое окно... Что не так?
Спасибо!
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
19.11.2018, 23:56
Ответы с готовыми решениями:

Основные методы для рисования графических примитивов в Windows Forms
Назвать основные методы для рисования графических примитивов (Windows Forms)

Библиотека C для рисования графических примитивов в буфер или файл
Коллеги, подскажите, пожалуйста ответ на мой вопрос! У меня такая задача - рисовать различные графические элементы (прямые, дуги,...

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

12
 Аватар для Alikberov
131 / 116 / 25
Регистрация: 03.05.2017
Сообщений: 337
Записей в блоге: 1
20.11.2018, 01:10
Пример…
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
            hdc = BeginPaint(hwnd, &ps);//получение контекста
            hdcMemDC = CreateCompatibleDC(hdc);
 
 
            GetClientRect(hwnd,&r);//работа с рабочей областью
            cx=r.right;
            cy=r.bottom;
 
            background.top=0;//объявление фонового прямоугольника
            background.bottom=cy-1;
            background.right=cy-1;
            background.left=0;
 
            oldbm = SelectObject(hdcMemDC, CreateCompatibleBitmap(hdc, r.right,r.bottom)); // Создаём память буфера
 
            //  br = CreateSolidBrush(RGB(0,0,140));
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(0,0,140)));
 
            Rectangle(hdcMemDC, 0, 0, cy-1, cy-1);//рисуем фоновый прямоугольник
            //FillRect(hdc,&background,br);
            //  DeleteObject(SelectObject(hdcMemDC,oldbr));  // Необязательно удалять, если …
 
            DeleteObject(SelectObject(hdcMemDC,CreateSolidBrush(RGB(100,0,0)))); // … кисть снова обновляем
 
            Ellipse(hdcMemDC, cy/2 - 10, cy/2 - 10, cy/2 +10, cy/2+10);
 
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            BitBlt(hdc, 0, 0, cx, cy, hdcMemDC, 0, 0, SRCCOPY);
 
            DeleteObject(SelectObject(hdcMemDC, oldbm)); // Удаляем память буфера
 
            DeleteDC(hdcMemDC);
            EndPaint(hwnd, &ps);
            InvalidateRect(hwnd, NULL, NULL);
1
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
20.11.2018, 01:59
Лучший ответ Сообщение было отмечено sad_guy как решение

Решение

Хотелось бы добавить от себя несколько замечаний. Первое это использование в WM_PAINT функции InvalidateRect. Это зло, не делайте так, попадёте в ад. Ну и второе, это использование кистей для рисования. Со своего опыта могу сказать, что с увеличением строк кода, будет всё запутаннее читать такое.
Вот как я использую двойную буферизацию (типа шаблона)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hWnd, &ps);
    RECT rc;
    GetClientRect(hWnd, &rc);
    const int iWindowWidth = rc.right - rc.left;
    const int iWindowHeight = rc.bottom - rc.top;
    HDC hMemDC = CreateCompatibleDC(hDC);
    HBITMAP hBitmap = CreateCompatibleBitmap(hDC, iWindowWidth, iWindowHeight);
    HBITMAP hOldBitmap = SelectBitmap(hMemDC, hBitmap);
    FillRect(hMemDC, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 11));
 
    int iOldBkMode = SetBkMode(hMemDC, TRANSPARENT);
    
    // Здесь уже рисование.
 
    SetBkMode(hMemDC, iOldBkMode);
 
    BitBlt(hDC, 0, 0, iWindowWidth, iWindowHeight, hMemDC, 0, 0, SRCCOPY);
    SelectBitmap(hMemDC, hOldBitmap);
    DeleteBitmap(hBitmap);
    DeleteDC(hMemDC);
    EndPaint(hWnd, &ps);
1
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151
20.11.2018, 13:39  [ТС]
Я поставил invalidate rect в вм паинт для постоянной перерисовки - планируется динамичная картинка. Можно сделать лучше?
ЗЫ : за шаблон спасибо)
0
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
20.11.2018, 15:07
Цитата Сообщение от sad_guy Посмотреть сообщение
Можно сделать лучше?
Лучше поставить таймер, и перерисовывать через определённые промежутки времени.
0
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151
20.11.2018, 21:02  [ТС]
Попробовал сделать с таймером:
(решил каждую секунду менять размер круга, _size..., создавал таймер при wm create)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
case WM_CREATE:
 
            SetTimer(hwnd, 1, 100, NULL);//установка таймера
 
            break;
        case WM_TIMER:
            if(_size == 10) _size=20;
            else _size = 10;
            InvalidateRect(hwnd, NULL, true);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);//получение контекста
            hdcMemDC = CreateCompatibleDC(hdc);
 
 
 
            GetClientRect(hwnd,&r);//работа с рабочей областью
            cx=r.right;
            cy=r.bottom;
 
            background.top=0;//объявление фонового прямоугольника
            background.bottom=cy-1;
            background.right=cy-1;
            background.left=0;
 
            oldbm = SelectObject(hdcMemDC, CreateCompatibleBitmap(hdc, cx, cy));
 
          //  br = CreateSolidBrush(RGB(0,0,140));
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(0,0,140)));
 
            Rectangle(hdcMemDC, 0, 0, cy-1, cy-1);//рисуем фоновый прямоугольник
            //FillRect(hdc,&background,br);
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(100,0,0)));
 
            Ellipse(hdcMemDC, cy/2 - _size, cy/2 - _size, cy/2 +_size, cy/2+_size);
 
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            BitBlt(hdc, 0, 0, cx, cy, hdcMemDC, 0, 0, SRCCOPY);
 
            DeleteObject(SelectObject(hdcMemDC,oldbm));
 
            DeleteDC(hdcMemDC);
            EndPaint(hwnd, &ps);
            //InvalidateRect(hwnd, NULL, NULL);
 
            break;
почему-то не работает... Может я неправильный timer id сделал?

Добавлено через 11 минут
Он не заходит в вм таймер, т.е. проблема с установленным таймером
0
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
20.11.2018, 23:43
Значит смотрите
C++
1
SetTimer(hwnd, 1, 100, NULL);
100 - это не секунда, 1000 - это секунда (то есть 1000 миллисекунд).

Если используете двойную буферизацию, то третьим параметром InvalidateRect должно быть false, а не true как у Вас в коде.

Цитата Сообщение от sad_guy Посмотреть сообщение
Может я неправильный timer id сделал?
Нет, нормальный.
0
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151
21.11.2018, 09:14  [ТС]
Нет, это не помогло. Я перепробовал кучу вариантов реализации, даже брейк убирал для провала в паинт, но ничего не помогло. Отсюда выходит, что нет сообщений вм таймер. Однако проверка мессадж боксами показала, что все и с таймером и с его сообщениями нормально... Может проблема с вм паинтом? Когда я поставил мессадж бокс в него, ничего не произошло, только колесо загрузки зачастило. ТОкда я убрал бреак из вм_таймер, но ничего не поменялось. Лажа в обработке паинта. Убрал из него invalidate rect. (насколько я понял, происходило зацикливание - инвалидайт вызывал помещение вм_паинта в очередь "в обход ее" из-за этого сообщения таймера глохли где-то сзади). Теперь началась ежесекундная обработка вм_паинт, но картинка не меняется
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
case WM_PAINT:
         // MessageBox(NULL, "wm_paint", "no error", MB_OK);
            hdc = BeginPaint(hwnd, &ps);//получение контекста
            hdcMemDC = CreateCompatibleDC(hdc);
 
 
 
            GetClientRect(hwnd,&r);//работа с рабочей областью
            cx=r.right;
            cy=r.bottom;
 
            background.top=0;//объявление фонового прямоугольника
            background.bottom=cy-1;
            background.right=cy-1;
            background.left=0;
 
            oldbm = SelectObject(hdcMemDC, CreateCompatibleBitmap(hdc, cx, cy));
 
          //  br = CreateSolidBrush(RGB(0,0,140));
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(0,0,140)));
 
            Rectangle(hdcMemDC, 0, 0, cy-1, cy-1);//рисуем фоновый прямоугольник
            //FillRect(hdc,&background,br);
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            oldbr = SelectObject(hdcMemDC,CreateSolidBrush(RGB(100,0,0)));
 
            Ellipse(hdcMemDC, cy/2 - _size, cy/2 - _size, cy/2 +_size, cy/2+_size);
 
            DeleteObject(SelectObject(hdcMemDC,oldbr));
 
            BitBlt(hdc, 0, 0, cx, cy, hdcMemDC, 0, 0, SRCCOPY);
 
            DeleteObject(SelectObject(hdcMemDC,oldbm));
 
            DeleteDC(hdcMemDC);
            EndPaint(hwnd, &ps);
         //   InvalidateRect(hwnd, NULL, NULL);
 
            break;
Что может быть не так? полагаю, лажа где-то в рисовании или какая-то особенность работы с двойной буферизацией
0
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
21.11.2018, 10:04
Наверное Вам нужно так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int _size;
    switch (msg)
    {
        case WM_CREATE:
        {
            _size = 10;
            SetTimer(hWnd, 1, 1000, NULL);
            return TRUE;
        }
        break;
        
        case WM_TIMER:
        {
            if (_size == 10)
                _size=20;
            else
                _size = 10;
            InvalidateRect(hWnd, NULL, FALSE);
        }
        break;
        
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hDC = BeginPaint(hWnd, &ps);
            RECT rc;
            GetClientRect(hWnd, &rc);
            const int iWindowWidth = rc.right - rc.left;
            const int iWindowHeight = rc.bottom - rc.top;
            HDC hMemDC = CreateCompatibleDC(hDC);
            HBITMAP hBitmap = CreateCompatibleBitmap(hDC, iWindowWidth, iWindowHeight);
            HBITMAP hOldBitmap = SelectBitmap(hMemDC, hBitmap);
            
            HBRUSH hBrush, hOldBrush;
            
            hBrush = CreateSolidBrush(RGB(0, 0, 140));
            FillRect(hMemDC, &ps.rcPaint, hBrush);
            DeleteBrush(hBrush);
            
            hOldBrush = SelectBrush(hMemDC, CreateSolidBrush(RGB(100, 0, 0)));
            Ellipse(hMemDC, iWindowWidth / 2 - _size, iWindowHeight / 2 - _size, iWindowWidth / 2 + _size, iWindowHeight / 2 + _size);
 
            DeleteObject(SelectObject(hMemDC, hOldBrush));
            
            BitBlt(hDC, 0, 0, iWindowWidth, iWindowHeight, hMemDC, 0, 0, SRCCOPY);
            SelectBitmap(hMemDC, hOldBitmap);
            DeleteBitmap(hBitmap);
            DeleteDC(hMemDC);
            EndPaint(hWnd, &ps);
        }
        break;
        
        case WM_DESTROY:
        {
            KillTimer(hWnd, 1);
            PostQuitMessage(0);
        }
        break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}
Добавлено через 1 минуту
Не знаю что в Вашем коде не так. Вы всё время кидаете код кусками и ждёте помощи. Здесь нет телепатов.
1
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151
21.11.2018, 10:08  [ТС]
Решил я чекнуть значение _size, в конце обработки поставил простую проверку с мессадж боксами. Выяснилось, что значение всегда 20....
0
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
21.11.2018, 10:11
Проверьте код, который я сбросил и сравните со своим.
0
...
4 / 4 / 1
Регистрация: 10.11.2017
Сообщений: 151
21.11.2018, 10:14  [ТС]
О ДА, ОНО РАБОТАЕТ)))))))) Спасибо большое! Глупая лажа получилась(

Добавлено через 2 минуты
я объявлял просто int переменную и присваивал ей значение в начале функции. Получается, она каждый раз пересоздавалась.
0
Software Developer
 Аватар для fastb1t
315 / 229 / 113
Регистрация: 03.05.2017
Сообщений: 1,336
21.11.2018, 10:16
Цитата Сообщение от sad_guy Посмотреть сообщение
я объявлял просто int переменную и присваивал ей значение в начале функции. Получается, она каждый раз пересоздавалась.
Вот видите, а нужно было просто объявить как static или сделать глобальной.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.11.2018, 10:16
Помогаю со студенческими работами здесь

Операция объединения для графических примитивов
Есть задача: создать систему классов, реализующих графические примитивы (круг, треугольник, квадрат) на плоскости с реализацией операций...

Что использовать для рисования примитивов
Ребят подскажите на чем можно программно порисовать? желательно на с++ в 12 визуалке для WinForm. находил учебники для 10 версии на...

Использование графических примитивов для создания статических и динамических изображений
Здравствуйте! А кто-то уже делал нечто подобное в Делфи? Лично у меня фантазии вообще нету, дабы придумать что-то.. Хотя примеры привели -...

Ускорение двойной буферизации
Недавно вычитал что при создании 2 буфера лучше использовать CreateDIBSection вместо CreateCompatibleBitmap. Как можно его заменить в этом...

Мерцание при двойной буферизации
Вот пытаюсь сделать что-то вроде игры. не могу убрать мерцание. двойную буферизацию пробовал, не помогло даже чуть-чуть. еще может...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru