Рисование по таймеру Win32api

Тема в разделе "Общие вопросы по С и С++", создана пользователем sergg, 30 ноя 2010.

  1. sergg

    sergg Member

    Регистрация:
    9 май 2010
    Сообщения:
    20
    Симпатии:
    0
    Всем привет.
    Как мне на WM_TIMER написать текст в главном окне? роблема вся в том, что выполнение функции TextOut должно происходить если WndProc ловит WM_PAINT. А WM_PAINT может посылаться виндой в разных случаях, а значит нет гарантии что и код который будет выполняться в случае WM_PAINT выполнится только по таймеру.
     
  2. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.580
    Симпатии:
    0
    В обработчике WM_TIMER устанавливайте некоторый флаг, а в обработчике WM_PAINT проверяйте значение этого флага и решайте что именно будете рисовать
     
  3. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Не уверен что это сработает. Сообщение WM_PAINT посылается не постоянно.

    А вот так работать будет:
    Код (C++):
    #include <windows.h>
    #include <math.h>

    #define     W               320
    #define     H               240

    char            g_szWindowName[]    = "dib";
    char            g_szWindowClass[]   = "dib32";
    HWND        g_hWnd;
    char *      p_str               = "Hello!";

    static LRESULT CALLBACK wnd_proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
    switch ( uMsg ) {
    case WM_NCHITTEST: return HTCAPTION;

    case WM_TIMER: {
    int     i;

    char    a;
    a = p_str[0];
    for ( i = 0; i < strlen( p_str ) - 1; i++ ) p_str[i] = p_str[i + 1];
    p_str[strlen( p_str ) - 1] = a;

    InvalidateRect( hWnd, NULL, FALSE );
    } break;

    case WM_PAINT: {
    PAINTSTRUCT ps;
    BeginPaint( hWnd, &ps );

    TextOut( ps.hdc, 120, 120, p_str, strlen( p_str ) );

    EndPaint( hWnd, &ps );
    } return 0;

    case WM_KEYDOWN: if ( (int)wParam != VK_ESCAPE ) break;
    case WM_DESTROY:
    PostQuitMessage( 0 );
    return 0;
    }
    return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }

    int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
    {
    MSG         msg;
    WNDCLASS    wc;

    memset( &wc, 0, sizeof( WNDCLASS ) );
    wc.style            = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc      = wnd_proc;
    wc.hInstance        = hInst;
    wc.lpszClassName    = g_szWindowClass;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)GetStockObject( WHITE_BRUSH );
    RegisterClass( &wc );

    g_hWnd = CreateWindowEx( WS_EX_TOPMOST,
    g_szWindowClass, g_szWindowName, WS_POPUP | WS_VISIBLE,
    (GetSystemMetrics( SM_CXSCREEN ) >> 1) - (W >> 1),
    (GetSystemMetrics( SM_CYSCREEN ) >> 1) - (H >> 1),
    W, H, NULL, NULL, hInst, NULL );

    SetTimer( g_hWnd, 1000, 200, NULL );

    while ( GetMessage( &msg, NULL, 0, 0 ) ) {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }

    DestroyWindow( g_hWnd );
    UnregisterClass( g_szWindowClass, hInst );
    return 0;
    }
     
  4. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.580
    Симпатии:
    0
    В чём именно вы не уверены?
    Рисовать, то будет. Но обратите внимание на требование:
    Где в вашем коде гарантии?
     
  5. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    European
    Я не вижу в этом смысла. Если ему надо рисовать текст 1 раз в каждые 200 миллисекунд то ему нужно просто воткнуть TextOut в WM_TIMER и WM_PAINT будет здесь вообще не при чем.
    Формулировка автора построена не верно. Я заранее предусмотрел этот вариант. Пускай либо переформулирует, либо берет то что дают.
    Может конечно поставить флаг но это будет не правильный подход. WM_PAINT вызывается только тогда, когда необходимо обновить часть окна или все окно целиком, больше никак.

    Не то что не уверен, я знаю что это не сработает.
     
  6. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.580
    Симпатии:
    0
    А если верно? Автору нужно вывести текст только на WM_TIMER, все остальные инициаторы перирисовки должны быть проигнорированы.
    На пальцах объясните, что не сработает

    Добавлено:
    Следующим шагом вы пошлете автора?
     
  7. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Ну тогда мой вариант подойдет ему идеально!!!)))

    Объясняю:
    Установили.

    MSDN: The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window.
    Как вы думаете, сколько раз сработает таймер перед тем как окно получит сообщение WM_PAINT ? Правильно! Сколько угодно.
     
  8. European

    Регистрация:
    4 сен 2006
    Сообщения:
    2.580
    Симпатии:
    0
    Ай, да при чем здесь МСДН? А прекрасно знаю, когда окно может быть перерисовано. А прекрасно понимаю ваше решение, но оно никак не коррелирует с требованиями топикстартера. Ладно, без прояснения требований спорить бесполезно

    Добавлено:
    Ничего он не подходит. После первого же обработчика WM_TIMER строка будет выводится постоянно, а нужно только 1 раз
     
  9. sergg

    sergg Member

    Регистрация:
    9 май 2010
    Сообщения:
    20
    Симпатии:
    0
    Парни, извиняюсь. Я неправильно сформулировал вопрос, точнее то что я хочу.
    Попробую снова:
    При нажатии на кнопку у меня должен сработать таймер. Каждую секунду у меня должен меняться текст на форме, при этом прошлый текст должен удалятся. Правда для этого я еще ничего не предпринимал, т.к. возможно он сам удаляется, а я этого не вижу.
    Вот мои попытки:
    Код (C++):
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR Txt1[] = _T("Txt1");
    TCHAR Text[] = _T("Text");
    switch (message)
    {
    case WM_COMMAND:
    if(LOWORD(wParam)==10001)
    {
    if(tmrEnbld)
    {
    KillTimer(hWnd,1);
    tmrEnbld=false;
    }
    PostQuitMessage(0);
    }
    if(LOWORD(wParam)==10000) //запускаю таймер
    {
    tmrEnbld=SetTimer(hWnd, 1, 1000, NULL); //tmrEnbld значит что таймер запущен
    }
    break;
    case WM_TIMER:
    isChanged=!isChanged; //просто флаг, означающий, что прошла секунда
    UpdateWindow(hWnd);
    case WM_PAINT:
    if(tmrEnbld) //если таймер запущен
    {
    hdc = BeginPaint(hWnd, &ps); //определяем контекст устройства
    if(isChanged)
    {
    TextOut(hdc, 5, 5, Txt1, _tcslen(Txt1)); //выводим тхт1
    }
    if(!isChanged)
    {
    TextOut(hdc, 15, 15, Text, _tcslen(Text)); //вводим текст
    }
    EndPaint(hWnd, &ps);
    }
    break;
    В итоге при нажатии на кнопку появляется слово "текст", а вот слова "тхт" я не вижу, хоть и вызываю updatewindow. Но, если форму передвинуть за рамки экрана (надеюсь вы поняли о чем я), а потом вернуть обратно, то будет нужный текст. И если так делать ежесекундно, то текст на самом деле будет меняться. Значит код работает верно но не до конца. Подскажите где и что надо дописать, что бы все было ок.
     
  10. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    UpdateWindow обновляет только те области, которые помечены как те, которые нужно обновить, а они таковыми не помечены ни разу...

    Все объяснение цитатой выше.

    А ты вообще смотрел тот код что я тебе писал?

    Да что вы говорите))) А где про это написано?.. что-то никак не найду.. Даже если и нужно один раз тогда возникает вопрос зачем вообще нужен таймер?

    Похоже что не знаете.
    На пальцах объяснил. Что не понятно?

    Из новых объяснений автора я понял что именно ему нужно.
    Код (C++):
    #include <windows.h>

    #define     W       320
    #define     H       240

    char        g_szWindowName[]    = "test";
    char        g_szWindowClass[]   = "test32";
    HWND        g_hWnd;

    int         p_i                 = 0;
    char *      p[]                 = { "privet!", "poka!" };

    static LRESULT CALLBACK wnd_proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
    {
    switch ( uMsg ) {
    case WM_COMMAND: {
    switch ( LOWORD( wParam ) ) {
    case 10000: {
    SetTimer( g_hWnd, 1000, 1000, NULL );
    } break;
    }
    } break;

    case WM_TIMER: {
    p_i ^= 1;
    InvalidateRect( hWnd, NULL, TRUE );
    } break;

    case WM_PAINT: {
    PAINTSTRUCT ps;
    BeginPaint( hWnd, &ps );
    TextOut( ps.hdc, 120, 120, p[p_i], strlen( p[p_i] ) );
    EndPaint( hWnd, &ps );
    } return 0;

    case WM_KEYDOWN: if ( (int)wParam != VK_ESCAPE ) break;
    case WM_DESTROY:
    PostQuitMessage( 0 );
    return 0;
    }
    return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }

    int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
    {
    MSG         msg;
    WNDCLASS    wc;

    memset( &wc, 0, sizeof( WNDCLASS ) );
    wc.style            = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc      = wnd_proc;
    wc.hInstance        = hInst;
    wc.lpszClassName    = g_szWindowClass;
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground    = (HBRUSH)GetStockObject( WHITE_BRUSH );
    RegisterClass( &wc );

    g_hWnd = CreateWindowEx( WS_EX_TOPMOST,
    g_szWindowClass, g_szWindowName, WS_POPUP | WS_VISIBLE,
    (GetSystemMetrics( SM_CXSCREEN ) >> 1) - (W >> 1),
    (GetSystemMetrics( SM_CYSCREEN ) >> 1) - (H >> 1),
    W, H, NULL, NULL, hInst, NULL );

    // Симулирую нажатие клавиши...
    SendMessage( g_hWnd, WM_COMMAND, 10000, 0 );

    while ( GetMessage( &msg, NULL, 0, 0 ) ) {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }

    DestroyWindow( g_hWnd );
    UnregisterClass( g_szWindowClass, hInst );
    return 0;
    }
    Это тебя беспокоить не должно. В противном случае подход будет не верным.
     
  11. sergg

    sergg Member

    Регистрация:
    9 май 2010
    Сообщения:
    20
    Симпатии:
    0
    Спасибо. Понял. Т.е. все дело в InvalidateRect( hWnd, NULL, TRUE ), так?
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Да!

    Добавлено: Альтернатива: InvalidateRgn(...). В данном случае может выполнить ту же функцию.
     
Загрузка...
Похожие Темы - Рисование по таймеру
  1. ilya00
    Ответов:
    17
    Просмотров:
    1.785
  2. vladden
    Ответов:
    1
    Просмотров:
    1.846
  3. 123456789igor
    Ответов:
    1
    Просмотров:
    1.394
  4. bearpaw
    Ответов:
    6
    Просмотров:
    3.778
  5. ezus
    Ответов:
    3
    Просмотров:
    4.885

Поделиться этой страницей