Форум программистов, компьютерный форум, киберфорум
Наши страницы
Visual C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 29, средняя оценка - 4.69
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
#1

Двойная буферизация, присутствует мерцание - Visual C++

05.08.2012, 18:12. Просмотров 4439. Ответов 32
Метки нет (Все метки)

Здравствуйте!
Если форма на C++ (чистый WinAPI), на ней рисуется графика с помощью GDI+.
Форма обновляется каждые 100мс., но вот беда она мерцает.
Код отрисовки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
VOID OnPaint(HDC hdc)
{
   Graphics     graphics(hdc);
   SolidBrush  brush(Color(255, 0, 0, 255));
   FontFamily  fontFamily(L"Times New Roman");
   Font         font(&fontFamily, 24, FontStyleRegular, UnitPixel);
   PointF         pointF(10.0f, 20.0f);
   Bitmap* picture = Bitmap::FromResource(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDB_BITMAP1));
   graphics.DrawImage(picture, 0, 0);
   if (is_game)
        graphics.DrawString(L"Game is running!", -1, &font, pointF, &brush);
   else graphics.DrawString(L"Game is'nt running!", -1, &font, pointF, &brush);
}
Само рисование формы и применение буферизации:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
case WM_PAINT:
  {
   HDC hdc;
   PAINTSTRUCT ps;
   ULONG_PTR gdiplusToken;
   HDC mdc = CreateCompatibleDC(NULL);
   HBITMAP mbmp =  CreateBitmap(420,320,1,8,NULL);
   HBITMAP moldbmp = (HBITMAP)SelectObject(mdc,mbmp);
   hdc = BeginPaint(hWnd, &ps);
   GdiplusStartupInput gdiplusStartupInput;
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
   {
        OnPaint(hdc);
   }
   SelectObject(mdc,moldbmp);
   DeleteObject(mbmp);
   DeleteDC(mdc);
   EndPaint(hWnd, &ps);
  }
  break;
И собственно говоря код, который вызывает обновление:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case WM_TIMER:
  {
   if (ME->GetProcessByName() != 0)
   {
        is_game = true;
        RECT rect = {0, 0, 420, 320};
        InvalidateRect(hWnd, &rect, false);
   }
   else
   {
        is_game = false;
        RECT rect = {0, 0, 420, 320};
        InvalidateRect(hWnd, &rect, false);
   }
  }
  break;
Как я могу устранить мерцание элементов формы? Может что-то не так с буферизацией?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.08.2012, 18:12
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Двойная буферизация, присутствует мерцание (Visual C++):

Двойная буферизация!
Пишу очень облегченное и просто подобие старого Пеинта, но столкнулся с одной...

Двойная буферизация под Win на VC++ (MFC)
Двойная буферизация под Win на VC++(MFC) - кто-нибудь знает - это вообще...

Двойная компиляция
Всем привет! При компиляции на VS2010 происходит двойной запуск программы. ...

Мерцание консоли
Пишу RPG. Но возникла такая проблема: когда персонаж двигается, начинает...

Мерцание при Invalidate
(MFC) Вызываю в OnMouseMove MoveWindow(SetWindowPos (отключаю перерисовку))...

Анимация огня. Мерцание
Собственно само задание выглядит так: Задание я вроде бы выполнил, но...

32
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
05.08.2012, 23:35 #21
Цитата Сообщение от Sheppard Посмотреть сообщение
я его исправил как ты и всё, большим изменениям он не подвергался.
Я всегда предполагаю, что человек может меня не так понять и что-то сделать не так, именно поэтому и спрашиваю вновь показать код целиком. Крайне желательно в тэге CUT чтобы он не мозолил глаза лишний раз.
Плюс ко всему, мне намного удобнее будет выявить ошибку видя новый код перед глазами, нежели представлять его в уме.
0
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
05.08.2012, 23:38  [ТС] #22
Цитата Сообщение от lazybiz Посмотреть сообщение
Я всегда предполагаю, что человек может меня не так понять и что-то сделать не так, именно поэтому и спрашиваю вновь показать код целиком. Крайне желательно в тэге CUT чтобы он не мозолил глаза лишний раз.
C++ source code

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <Windows.h>
#include <GdiPlus.h>
#include "resource.h"
#include <iostream>
 
#pragma comment (lib, "gdiplus.lib")
using namespace Gdiplus;
 
bool is_game = false;
wchar_t ammo[16];
 
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // прототип WndProc
 
VOID OnPaint(HDC hdc)
{
   Graphics    graphics(hdc);
   SolidBrush  brush(Color(255, 0, 0, 255));
   FontFamily  fontFamily(L"Times New Roman");
   Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel);
   PointF      pointF(10.0f, 20.0f);
   PointF      pointF2(10.0f, 45.0f);
   Bitmap* picture = Bitmap::FromResource(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDB_BITMAP1));
   graphics.DrawImage(picture, 0, 0);
   if (is_game)
   {
       graphics.DrawString(L"Game is running!", -1, &font, pointF, &brush);
       graphics.DrawString(ammo, -1, &font, pointF2, &brush);
   }
   else graphics.DrawString(L"Game is'nt running!", -1, &font, pointF, &brush);
}
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
{
    HWND hWnd;
    MSG msg;
    WNDCLASS w;
    memset(&w, 0, sizeof(WNDCLASS)); // зарезервировали место под наш класс окна
    w.style = 0;
    w.lpfnWndProc = WndProc; // задали процессс окна
    w.hInstance = hInstance;
    //w.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH); // задали белый цвет как фон формы
    w.lpszClassName = "Windows Form"; // Задали класс окна
    RegisterClass(&w); // зарегистрировали наше будующее окно
    hWnd = CreateWindow( w.lpszClassName, "Windows Form", WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
        CW_USEDEFAULT, CW_USEDEFAULT, 420, 300, NULL, NULL, hInstance, NULL); // создаём форму
    CreateWindow( "button", "Press me!", WS_CHILD | WS_VISIBLE | BS_CENTER,
        40, 90,
        70, 30,
        hWnd, (HMENU)1, hInstance, 0); // создали кнопку
 
    SetTimer(hWnd, NULL, 100, NULL); // сделали таймер
 
    ShowWindow( hWnd, CmdShow); // показываем наше окно
 
    UpdateWindow (hWnd); // обновляем содержимое окна
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
 
    while (GetMessage ( &msg, NULL, 0, 0) )
    {
        TranslateMessage (&msg);
        DispatchMessage(&msg);
    }// настроили отправку сообщений формы, о сообщениях формы можете почитать на MSDN
    return msg.wParam;
}
 
LONG WINAPI WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch (msg)
    {
    case WM_DESTROY:  // обработчик закрытия формы
        PostQuitMessage(0);
    case WM_PAINT:
        {
            hdc = BeginPaint(hWnd, &ps);
            OnPaint(hdc);
            EndPaint(hWnd, &ps);
        }
        break;
 
    case WM_COMMAND: //обработчик разных действий формы, нажатие на кнопку и т.д.
        switch (wParam)
        {
        case 1: // 1 - это HMENU нашей кнопки
            MessageBox(hWnd, "Button pressed", "All right!", MB_OK);
            break;
        }
    case WM_TIMER:
        {
            GetClientRect(hWnd, &rect);
            InvalidateRect(hWnd, &rect, false);
                is_game = true;
                ammo = L"Ammo: 42";
        }
        break;
    default:
        return DefWindowProc (hWnd, msg, wParam, lParam);
    }
    return 0;
}
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
05.08.2012, 23:55 #23
А говоришь все поправил.
1. Поставь GdiplusStartup() между 41-й и 42-й строками. UpdateWindow() посылает WM_PAINT, что уже не правильно.
2. После 79-й строки ( PostQuitMessage(0); ) поставь break;
3. Про 97-ю и 98-ю ты меня не послушал. Это не столь критично, но тем не менее.
4. После 94-й должен стоять break;

Кнопка у тебя будет моргать в любом случае, т.к. изображение закрашивает её.
С текстом та же самая фигня, но как это правильно делается в GDI+ понятия не имею.

Кстати, никакой двойной буферизацией у тебя тут даже и не пахнет. Тебе следует использовать CreateCompatibleDC(), для того чтобы создать back-buffer, рисовать в него, а потом с помощью BitBlt() выводить все на hDC, полученный BeginPaint().
Возможно в GDI+ есть какой-то другой вариант, но он мне не известен.
0
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
06.08.2012, 00:08  [ТС] #24
Цитата Сообщение от lazybiz Посмотреть сообщение
А говоришь все поправил.
1. Поставь GdiplusStartup() между 41-й и 42-й строками. UpdateWindow() посылает WM_PAINT, что уже не правильно.
2. После 79-й строки ( PostQuitMessage(0); ) поставь break;
3. Про 97-ю и 98-ю ты меня не послушал. Это не столь критично, но тем не менее.
4. После 94-й должен стоять break;

Кнопка у тебя будет моргать в любом случае, т.к. изображение закрашивает её.
С текстом та же самая фигня, но как это правильно делается в GDI+ понятия не имею.

Кстати, никакой двойной буферизацией у тебя тут даже и не пахнет. Тебе следует использовать CreateCompatibleDC(), для того чтобы создать back-buffer, рисовать в него, а потом с помощью BitBlt() выводить все на hDC, полученный BeginPaint().
Возможно в GDI+ есть какой-то другой вариант, но он мне не известен.
Знаю что всё в Paint это пихать не надо, но после попытки сделать двойную буферизацию, форма мерцает чёрным цветом.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    case WM_PAINT:
        {
            hdc = BeginPaint(hWnd, &ps);
            HDC memDC = CreateCompatibleDC(NULL);
            HBITMAP hMemBmp = CreateCompatibleBitmap(hdc, 420, 320);
            HGDIOBJ old_object = SelectObject(memDC, hMemBmp);
            BitBlt(hdc, 0, 0, 420, 320, memDC, 0, 0, SRCCOPY);
            OnPaint(hdc);
            SelectObject(memDC, old_object);
            DeleteObject(hMemBmp);
            DeleteDC(memDC);
            EndPaint(hWnd, &ps);
        }
        break;
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:17 #25
Ты меня без ножа режешь...
CreateCompatibleBitmap() тебе не нужна. Убирай. SelectObject() тоже.
Рисовать ты должен в memDC!!! А уже потом BitBlt.
Перенеси все кроме BeginPaint() и EndPaint() в OnPaint().
0
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
06.08.2012, 00:25  [ТС] #26
Цитата Сообщение от lazybiz Посмотреть сообщение
Ты меня без ножа режешь...
CreateCompatibleBitmap() тебе не нужна. Убирай. SelectObject() тоже.
Рисовать ты должен в memDC!!! А уже потом BitBlt.
Перенеси все кроме BeginPaint() и EndPaint() в OnPaint().
С++ source code
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
VOID OnPaint(HDC hdc)
{
   HDC memDC = CreateCompatibleDC(NULL);
   Graphics    graphics(hdc);
   SolidBrush  brush(Color(255, 0, 0, 255));
   FontFamily  fontFamily(L"Times New Roman");
   Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel);
   PointF      pointF(10.0f, 20.0f);
   PointF      pointF2(10.0f, 45.0f);
   Bitmap* picture = Bitmap::FromResource(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDB_BITMAP1));
   graphics.DrawImage(picture, 0, 0);
   if (is_game)
   {
       graphics.DrawString(L"Game is running!", -1, &font, pointF, &brush);
       graphics.DrawString(ammo, -1, &font, pointF2, &brush);
   }
   else graphics.DrawString(L"Game is'nt running!", -1, &font, pointF, &brush);
   BitBlt(hdc, 0, 0, 420, 320, memDC, 0, 0, SRCCOPY);
   DeleteDC(memDC);
}

Элементы формы уже мерцают не всегда.
Но всё равно мерцают, пробовал рисовать в memDC, но тогда просто чёрная форма получается.
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:39 #27
А как ты пробовал рисовать в memDC ?
Понимаешь, меня интересует код, который я тебе "навязываю", а не который ты исправил на свое усмотрение.
0
Игорь с++
472 / 464 / 63
Регистрация: 26.01.2011
Сообщений: 2,033
06.08.2012, 00:41 #28
Цитата Сообщение от Sheppard Посмотреть сообщение
код из "Нет мерцание.rar", не позволяет убрать мерцание, проверял на твоих же исходниках, текст отрисованный GDI+ мерцает.
я не знаю как и чего у тебя там моргает , возьми запусти exe-шник и посмотри , что у тебя будет творится !!!! Есть мерцание ??????
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:41 #29
Как я уже говорил, элементы (контроли) так и будут мерцать, в твоем случае от этого никуда не денешься.
0
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
06.08.2012, 00:43  [ТС] #30
Цитата Сообщение от lazybiz Посмотреть сообщение
Как я уже говорил, элементы (контроли) так и будут мерцать, в твоем случае от этого никуда не денешься.
Текст мерцает также, но реже
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:52 #31
Цитата Сообщение от Sheppard Посмотреть сообщение
Текст мерцает также
Если ты все сделал так как я тебе говорил, то мне верится в это с трудом. Показывай код в CUT.
0
Sheppard
1 / 1 / 3
Регистрация: 27.05.2012
Сообщений: 48
06.08.2012, 01:00  [ТС] #32
Цитата Сообщение от lazybiz Посмотреть сообщение
Если ты все сделал так как я тебе говорил, то мне верится в это с трудом. Показывай код в CUT.
С++ source code
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
VOID OnPaint(HDC hdc)
{
   HDC memDC = CreateCompatibleDC(NULL);
   Graphics    graphics(hdc);
   SolidBrush  brush(Color(255, 0, 0, 255));
   FontFamily  fontFamily(L"Times New Roman");
   Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel);
   PointF      pointF(10.0f, 20.0f);
   PointF      pointF2(10.0f, 45.0f);
   Bitmap* picture = Bitmap::FromResource(GetModuleHandle(NULL), MAKEINTRESOURCEW(IDB_BITMAP1));
   graphics.DrawImage(picture, 0, 0);
   if (is_game)
   {
       graphics.DrawString(L"Game is running!", -1, &font, pointF, &brush);
       graphics.DrawString(ammo, -1, &font, pointF2, &brush);
   }
   else graphics.DrawString(L"Game is'nt running!", -1, &font, pointF, &brush);
   BitBlt(hdc, 0, 0, 420, 320, memDC, 0, 0, SRCCOPY);
   DeleteDC(memDC);
}

Только не говори, что я что-то перепутал
0
castaway
Эксперт С++
4926 / 3033 / 453
Регистрация: 10.11.2010
Сообщений: 11,089
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 01:21 #33
Опять ты кое-что перепутал, а точнее не доделал. Кстати, ты заметил что с прошлого раза этот код не изменился!? Обрати на это внимание.

Я спать. Сделай как я говорил, и, если не будет работать выложи код целиком, завтра посмотрим...
0
06.08.2012, 01:21
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.08.2012, 01:21
Привет! Вот еще темы с решениями:

Постоянное мерцание при прорисовке
создал класс, в котором реализованы методы для рисования графиков. есть маcсив...

Мерцание при перерисовке (MFC)
Господа Программисты! Делаю Тетрис на MFC. При перерисовке игрового поля...

Как побороть мерцание при перерисовке строки контрола CListBox
Добрый день! Как побороть мерцание при перерисовке строки контрола CListBox....

Двойная буферизация, мерцание
Всем привет! Пишу просто графическое приложение на чистом WinApi и никак не...


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

Или воспользуйтесь поиском по форуму:
33
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru