Форум программистов, компьютерный форум, киберфорум
Наши страницы

Visual C++

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 29, средняя оценка - 4.69
Sheppard
1 / 1 / 0
Регистрация: 27.05.2012
Сообщений: 48
#1

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

05.08.2012, 18:12. Просмотров 4289. Ответов 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++):

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

Двойная буферизация под Win на VC++ (MFC) - Visual C++
Двойная буферизация под Win на VC++(MFC) - кто-нибудь знает - это вообще возможно?? Или по-другому: можно-ли создать в MFC SDI копию...

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

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

Мерцание при Invalidate - Visual C++
(MFC) Вызываю в OnMouseMove MoveWindow(SetWindowPos (отключаю перерисовку)) и Invalidate Происходит мерцание, как избавиться? ...

Анимация огня. Мерцание - Visual C++
Собственно само задание выглядит так: Задание я вроде бы выполнил, но изображение сильно мерцает. Пробовал отрисовывать в память, а...

32
Sheppard
1 / 1 / 0
Регистрация: 27.05.2012
Сообщений: 48
05.08.2012, 23:24  [ТС] #16
Цитата Сообщение от lazybiz Посмотреть сообщение
Ну это как раз потому, что это не лучший вариант))
Дело в том, что я терпеть не могу GDI+, и как он работает я себе не представляю и представлять не хочу... поэтому большем мне тебе помочь не чем.

P.S.:
1. С 49-й по 54-ю строки замени на:
C
1
2
3
4
    while ( GetMessage( &msg, NULL, 0, 0 ) ) {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
PeekMessage (&msg, 0, 0, 0, 0x0001); там ни к чему.

2. Заместо 89-й и 90-й строки поставь: InvalidateRect( hWnd, NULL, FALSE );

Оппа.. что я нашел.
Ты в курсе, что функция GdiplusStartup() должна вызываться в самом начале программы, а не в WM_PAINT ?
И не забудь GdiplusShutdown() в конце программы.

Переделай все это, и, возможно, все встанет на свои места.
P.S. поисправлял, но результата нет.
Нужна двойная буферизация и мерцания не будет.

Добавлено через 1 минуту
Цитата Сообщение от Somebody Посмотреть сообщение
А если попробовать
C++
1
2
case WM_ERASEBKGND:
  return 1;
?
Тоже не прокатывает.
Я догадываюсь, то что я должен создавать из формы виртуальный bitmap, обновлять его,и выводить на экран, так по сути и работает двойная буферизация, но рабочего примера я так и не нашёл.
0
castaway
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
05.08.2012, 23:26 #17
Sheppard, покажи что получилось. (без WM_ERASEBKGND)
0
Sheppard
1 / 1 / 0
Регистрация: 27.05.2012
Сообщений: 48
05.08.2012, 23:29  [ТС] #18
Цитата Сообщение от lazybiz Посмотреть сообщение
Sheppard, покажи что получилось. (без WM_ERASEBKGND)
Да простая форма. Мерцает по интервалу таймера (т.е. по обновлению)
0
Миниатюры
Двойная буферизация, присутствует мерцание  
castaway
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
05.08.2012, 23:31 #19
Sheppard, я имел в виду код. Кстати, мерцает абсолютно все?

Добавлено через 58 секунд
Цитата Сообщение от Sheppard Посмотреть сообщение
но просто мерцают элементы
Кнопка "Press me!" ?
0
Sheppard
1 / 1 / 0
Регистрация: 27.05.2012
Сообщений: 48
05.08.2012, 23:32  [ТС] #20
Цитата Сообщение от lazybiz Посмотреть сообщение
Sheppard, я имел в виду код. Кстати, мерцает абсолютно все?
Нет, только текст и кнопка.
Код ты же видел, я его исправил как ты и сказал, большим изменениям он не подвергался.
0
castaway
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
05.08.2012, 23:35 #21
Цитата Сообщение от Sheppard Посмотреть сообщение
я его исправил как ты и всё, большим изменениям он не подвергался.
Я всегда предполагаю, что человек может меня не так понять и что-то сделать не так, именно поэтому и спрашиваю вновь показать код целиком. Крайне желательно в тэге CUT чтобы он не мозолил глаза лишний раз.
Плюс ко всему, мне намного удобнее будет выявить ошибку видя новый код перед глазами, нежели представлять его в уме.
0
Sheppard
1 / 1 / 0
Регистрация: 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
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 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 / 0
Регистрация: 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
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:17 #25
Ты меня без ножа режешь...
CreateCompatibleBitmap() тебе не нужна. Убирай. SelectObject() тоже.
Рисовать ты должен в memDC!!! А уже потом BitBlt.
Перенеси все кроме BeginPaint() и EndPaint() в OnPaint().
0
Sheppard
1 / 1 / 0
Регистрация: 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
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:39 #27
А как ты пробовал рисовать в memDC ?
Понимаешь, меня интересует код, который я тебе "навязываю", а не который ты исправил на свое усмотрение.
0
Игорь с++
437 / 460 / 16
Регистрация: 26.01.2011
Сообщений: 2,033
06.08.2012, 00:41 #28
Цитата Сообщение от Sheppard Посмотреть сообщение
код из "Нет мерцание.rar", не позволяет убрать мерцание, проверял на твоих же исходниках, текст отрисованный GDI+ мерцает.
я не знаю как и чего у тебя там моргает , возьми запусти exe-шник и посмотри , что у тебя будет творится !!!! Есть мерцание ??????
0
castaway
Эксперт С++
4920 / 3028 / 372
Регистрация: 10.11.2010
Сообщений: 11,085
Записей в блоге: 10
Завершенные тесты: 1
06.08.2012, 00:41 #29
Как я уже говорил, элементы (контроли) так и будут мерцать, в твоем случае от этого никуда не денешься.
0
Sheppard
1 / 1 / 0
Регистрация: 27.05.2012
Сообщений: 48
06.08.2012, 00:43  [ТС] #30
Цитата Сообщение от lazybiz Посмотреть сообщение
Как я уже говорил, элементы (контроли) так и будут мерцать, в твоем случае от этого никуда не денешься.
Текст мерцает также, но реже
0
06.08.2012, 00:43
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.08.2012, 00:43
Привет! Вот еще темы с ответами:

Мерцание при перерисовке (MFC) - Visual C++
Господа Программисты! Делаю Тетрис на MFC. При перерисовке игрового поля (сообщение ON_WM_PAINT), возникает мерцание. ...

Постоянное мерцание при прорисовке - Visual C++
создал класс, в котором реализованы методы для рисования графиков. есть маcсив sinys, где у меня сохранены все точки, который мне надо...

Как побороть мерцание при перерисовке строки контрола CListBox - Visual C++
Добрый день! Как побороть мерцание при перерисовке строки контрола CListBox. //Строку обновляю в void DrawItem(LPDRAWITEMSTRUCT...

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


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

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

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