С Новым годом! Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
0 / 0 / 0
Регистрация: 10.07.2015
Сообщений: 16

Странное поведение (анимация)

25.03.2018, 21:14. Показов 1644. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, задача простая и я ее когда то решал успешно. Вывести эллипс, двигающийся по экрану (анимация) с помощью WinAPI.

Есть код, кривой, но рабочий. Я решил переделать его. Первым делом, я хочу рисовать не сразу в hdc, а в памяти (использовать контекст памяти для ускорения рисования), а потом при наступлении WM_PAINT из памяти копировать на экран. Второе: убрать весь код рисования по максимому из обработчика WM_PAINT.

Сейчас приведу фрагменты 2 кодов, А потом будут вопросы.

Вот код кривой, но худо бедно работающий, хотя непонятно как (код в спойлере):
Кликните здесь для просмотра всего текста

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
// tryone.cpp: определ¤ет точку входа дл¤ приложени¤.
//
 
#include "stdafx.h"
#include "tryone.h"
 
#define MAX_LOADSTRING 100
 
// √лобальные переменные:
HINSTANCE hInst;                                // текущий экземпл¤р
TCHAR szTitle[MAX_LOADSTRING];                  // “екст строки заголовка
TCHAR szWindowClass[MAX_LOADSTRING];            // им¤ класса главного окна
HDC hdc,memdc;
HBITMAP hbit;
int x,xnew,y,ynew,R;
double t,dt;
bool send = true;
 
// ќтправить объ¤влени¤ функций, включенных в этот модуль кода:
ATOM                MyRegisterClass(HINSTANCE hInstance); //описание оконного класса
BOOL                InitInstance(HINSTANCE, int);// сама программа, что нужно сделать при еЄ запуске
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);// функци¤ обработчик сообщений
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);//
 
//====задание констант
 
 
 
 
int APIENTRY _tWinMain(HINSTANCE hInstance,// точка входа в любую виндовс программу
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: разместите код здесь.
    MSG msg;
    HACCEL hAccelTable;// таблица гор¤чих клавиш
 
    // »нициализаци¤ глобальных строк
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_TRYONE, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
 
    // ¬ыполнить инициализацию приложени¤:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TRYONE));
 
    // ÷икл основного сообщени¤:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int) msg.wParam;
}
 
 
 
//
//  ‘”Ќ*÷»я: MyRegisterClass()
//
//  Ќј«Ќј„≈Ќ»≈: регистрирует класс окна.
//
//  *ќћћ≈Ќ“ј–»»:
//
//    Ёта функци¤ и ее использование необходимы только в случае, если нужно, чтобы данный код
//    был совместим с системами Win32, не имеющими функции RegisterClassEx'
//    котора¤ была добавлена в Windows 95. ¬ызов этой функции важен дл¤ того,
//    чтобы приложение получило "качественные" мелкие значки и установило св¤зь
//    с ними.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TRYONE));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_TRYONE);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassEx(&wcex);
}
 
//
//   ‘”Ќ*÷»я: InitInstance(HINSTANCE, int)
//
//   Ќј«Ќј„≈Ќ»≈: сохран¤ет обработку экземпл¤ра и создает главное окно.
//
//   *ќћћ≈Ќ“ј–»»:
//
//        ¬ данной функции дескриптор экземпл¤ра сохран¤етс¤ в глобальной переменной, а также
//        создаетс¤ и выводитс¤ на экран главное окно программы.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
 
   hInst = hInstance; // —охранить дескриптор экземпл¤ра в глобальной переменной
 
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
 
   if (!hWnd)
   {
      return FALSE;
   }
 
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
 
   return TRUE;
}
 
//
//  ‘”Ќ*÷»я: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  Ќј«Ќј„≈Ќ»≈:  обрабатывает сообщени¤ в главном окне.
//
//  WM_COMMAND  - обработка меню приложени¤
//  WM_PAINT    -«акрасить главное окно
//  WM_DESTROY   - ввести сообщение о выходе и вернутьс¤.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    int lines = 10;
    int step = 50;
    float v = 10;
    float d ;
 
    BOOL abc;
    int vert = 6;//вершин
    POINT *points = new POINT [vert];
    points[0].x =400 ;
    points[0].y =0 ;
    points[1].x = 700;
    points[1].y =0 ;
    points[5].x = 250;
    points[5].y =225 ;
    points[2].x = 850;
    points[2].y = 225;
    points[4].x = 400;
    points[4].y = 450;
    points[3].x = 700;
    points[3].y = 450;
 
    
 
    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // –азобрать выбор в меню:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_CREATE:
    hdc=GetDC(hWnd);
    memdc=CreateCompatibleDC(hdc);
    hbit=CreateCompatibleBitmap(hdc,1000,800);
    SelectObject(memdc,hbit);
    PatBlt(memdc,0,0,1000,800,PATCOPY);
    ReleaseDC(hWnd,hdc);
    
    dt=0.01;
    t=0;
    R=20;
    x=0;
    y=0;
    xnew=x;
    ynew=y;
 
 
    break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: добавьте любой код отрисовки...
        //Rectangle(hdc, 10,10,200,200);
        //MoveTo(hdc, 500,500);
       // LineTo(hdc, 20,50);
        //LineTo(hdc, 20,100);
        
        //line(hdc,5,5);
        //Ellipse(hdc,120,120,350,470);
        
        HPEN pen;
        pen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
        HBRUSH hbrush;
        hbrush = CreateSolidBrush(RGB(0,0,0));
        HBRUSH hbrush2;
        hbrush2 = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
 
 
        //DrawLine(&pen,0,0,200,200);
        
        SelectObject(hdc,pen);
        //SetBkMode(hdc,TRANSPARENT);
        //Ellipse(hdc,100,100,170,170);
        SetBkMode(hdc,TRANSPARENT);
        //Rectangle(hdc,50,50,200,200);
        //Polygon(hdc,points,vert);
        Ellipse(hdc,x, y, x+R, y+R);
        if (send)
            SetTimer(hWnd,1,1,NULL);
        
 
 
 
        /*MoveToEx(hdc,300,300,RGB(0,0,0));
        LineTo(hdc,600,300);
        LineTo(hdc,450,83);
        LineTo(hdc,300,300);
        LineTo(hdc,450,225);
        LineTo(hdc,600,300);
        LineTo(hdc,450,225);
        LineTo(hdc,450,83);
        */
        //SelectObject(hdc,hbrush2); //рисование контуром
        //Polygon(hdc,points,vert);
 
        /*for(int t=0; t<100;t++)
        {
            d= v*t;
            SetPixel(hdc,d,500,RGB(0,0,0));
            //SetPixel(hdc,d-10,500,RGB(225,225,225));
        }*/
        /*for(int t=0; t<50;t++)
        {
            for(int x=200; x<=500;x++)
                {
                    if (x<500) 
                    {
                         SetPixel(hdc,x,500,RGB(0,0,0));
                         SetPixel(hdc,x-5,500,RGB(225,225,225));
                    }
                     if(x=500)
                     {
 
                     }
            
                     
 
 
                }
        }
 
        */
        
        
 
        //SelectObject(hdc,hbrush);
        /*SetTextColor(hdc,RGB(0,0,225));
        SetBkColor(hdc,RGB(0,225,225));
        for(int k=0;k<=lines;k++)
        
            {
                MoveToEx(hdc,(k+1)*step,0,RGB(0,0,0));
                LineTo(hdc,(k+1)*step,600);
            }
        
        //
        for(int k=0;k<=lines;k++)
        
            {
                MoveToEx(hdc,0,(k+1)*step,RGB(0,0,0));
                LineTo(hdc,600,(k+1)*step);
            }
        
        //
        SelectObject(hdc,pen);
            for(int i=0;i<2000;i++)
            {
                for(int k=0;k<629;k++)
                {
                    float x;
                    float y;
                    x = k;
                    y = i;
                    y = 100*sin(x*0.01)+300;
                    SetPixel(hdc,x,y,RGB(0,0,0));
                    }
            }
 
        SelectObject(hdc, pen);
        abc =ExtFloodFill(hdc,60,60,RGB(0,255,0),FLOODFILLBORDER);
 
        TextOutW(hdc,30,70,_T("123"),strlen("123"));*/
        EndPaint(hWnd, &ps);
        break;
    case WM_TIMER:
        xnew=x+1;
        ynew=y;
        Ellipse(memdc,xnew,ynew,xnew+R,ynew+R);
        x=xnew;
        y=ynew;
        t=t+dt;
        InvalidateRect(hWnd,NULL,TRUE);
        KillTimer(hWnd,1);
        //if (t <= 0.06)
        if (x+R <= 600)
        {
            SetTimer(hWnd,1,1,NULL);
        }
        else
        {
            send = false;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
// ќбработчик сообщений дл¤ окна "ќ программе".
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


Теперь новый код, в котором убрал лишнее из WM_PAINT и рисую в памяти:
Кликните здесь для просмотра всего текста

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// tryone.cpp: определ¤ет точку входа дл¤ приложени¤.
//
 
#include "stdafx.h"
#include "gas.h"
 
#define MAX_LOADSTRING 100
 
// √лобальные переменные:
HINSTANCE hInst;                                // текущий экземпл¤р
TCHAR szTitle[MAX_LOADSTRING];                  // “екст строки заголовка
TCHAR szWindowClass[MAX_LOADSTRING];            // им¤ класса главного окна
 
// ќтправить объ¤влени¤ функций, включенных в этот модуль кода:
ATOM                MyRegisterClass(HINSTANCE hInstance); //описание оконного класса
BOOL                InitInstance(HINSTANCE, int);// сама программа, что нужно сделать при еЄ запуске
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);// функци¤ обработчик сообщений
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);//
 
//====задание констант
int maxX, maxY;
HDC hdc,memdc;
HBITMAP hbit;
double x,xnew,y,ynew,R;
double t,dt;
int fps = 100;
double timer = 1000./fps;
double V, v;// V скорость в пиксел¤х в секунду, v - вспомогательна¤ величина
 
int APIENTRY _tWinMain(HINSTANCE hInstance,// точка входа в любую виндовс программу
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: разместите код здесь.
    MSG msg;
    HACCEL hAccelTable;// таблица гор¤чих клавиш
 
    // »нициализаци¤ глобальных строк
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_GAS, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
 
    // ¬ыполнить инициализацию приложени¤:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GAS));
 
    // ÷икл основного сообщени¤:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int) msg.wParam;
}
 
 
 
//
//  ‘”Ќ*÷»я: MyRegisterClass()
//
//  Ќј«Ќј„≈Ќ»≈: регистрирует класс окна.
//
//  *ќћћ≈Ќ“ј–»»:
//
//    Ёта функци¤ и ее использование необходимы только в случае, если нужно, чтобы данный код
//    был совместим с системами Win32, не имеющими функции RegisterClassEx'
//    котора¤ была добавлена в Windows 95. ¬ызов этой функции важен дл¤ того,
//    чтобы приложение получило "качественные" мелкие значки и установило св¤зь
//    с ними.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAS));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_GAS);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassEx(&wcex);
}
 
//
//   ‘”Ќ*÷»я: InitInstance(HINSTANCE, int)
//
//   Ќј«Ќј„≈Ќ»≈: сохран¤ет обработку экземпл¤ра и создает главное окно.
//
//   *ќћћ≈Ќ“ј–»»:
//
//        ¬ данной функции дескриптор экземпл¤ра сохран¤етс¤ в глобальной переменной, а также
//        создаетс¤ и выводитс¤ на экран главное окно программы.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
 
   hInst = hInstance; // —охранить дескриптор экземпл¤ра в глобальной переменной
 
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
 
   if (!hWnd)
   {
      return FALSE;
   }
 
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
 
   return TRUE;
}
 
//
//  ‘”Ќ*÷»я: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  Ќј«Ќј„≈Ќ»≈:  обрабатывает сообщени¤ в главном окне.
//
//  WM_COMMAND  - обработка меню приложени¤
//  WM_PAINT    -«акрасить главное окно
//  WM_DESTROY   - ввести сообщение о выходе и вернутьс¤.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
 
    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // –азобрать выбор в меню:
        switch (wmId)
        {
        case IDM_START:     
            Ellipse(memdc,x, y, x+2*R, y+2*R);
            InvalidateRect(hWnd,NULL,TRUE);
            
            SetTimer(hWnd, 1, (int)timer, NULL);
    
            break;
        case IDM_STOP:
            KillTimer(hWnd, 1);
            MessageBox(hWnd,"ќстановлено!","*урсова¤",MB_OK);
            break;
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, (DLGPROC) About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_CREATE:
        maxX= GetSystemMetrics(SM_CXSCREEN);
        maxY= GetSystemMetrics(SM_CYSCREEN);
        hdc=GetDC(hWnd);
        memdc=CreateCompatibleDC(hdc);
        hbit=CreateCompatibleBitmap(hdc,maxX,maxY);
        SelectObject(memdc,hbit);
        PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
        ReleaseDC(hWnd,hdc);
    
        dt = timer * 0.001;//dt в миллисекундах
        t=0;
        R=20;
        x=0;
        y=0;
        xnew=x;
        ynew=y;     
 
        V = 2;//ѕусть V равно 20 пкс/сек
        v = V/dt;       
 
    break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        BitBlt(hdc,0,0,maxX,maxY, memdc,0,0,SRCCOPY);
        EndPaint(hWnd, &ps);
        break;
    case WM_TIMER:
        
        KillTimer(hWnd,1);
        
        t = t + dt;
        xnew = x + v*t;
        ynew = y;
        Ellipse(memdc,xnew,ynew,xnew+2*R,ynew+2*R);
        InvalidateRect(hWnd,NULL,TRUE);
        UpdateWindow(hWnd);
        
        if(xnew<=620)
            SetTimer(hWnd,1,(int)timer,NULL);
        
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
// ќбработчик сообщений дл¤ окна "ќ программе".
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


Теперь вопросы:
1. Если убрать из WM_TIMER старого кода команду Ellipse, то он все равно будет рисовать. Почему?
2. Если убрать из WM_PAINT старого кода Ellipse, но оставить Ellipse в WM_TIMER, то рисоваться ничего не будет вообще. Почему? По идее он должен рисоваться в памяти, а потом обновляться с помощью InvalidateRect. При наступлении WM_PAINT там стоит функция BitBlt, которая должна из памяти перекидывать на экран, но ничего не происходит.
3. и главное: в новом коде не могу добиться, чтобы эллипс рисовался без шлейфа. При каждом WM_TIMER, я пересчитываю координаты и делаю InvalidateRect с последним параметром что TRUE, что FALSE - программа все равно не стирает старые положения эллипса, получается некрасивый шлейф. Ожидалось, что при установке TRUE он будет стирать прошлый эллипс и рисовать эллипс в новом положении, то есть анимация.

Раньше не думая использовал InvalidateRect и анимация работала без казусов. Объясните, пожалуйста, чего я не понимаю?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.03.2018, 21:14
Ответы с готовыми решениями:

Странное поведение
#include &lt;windows.h&gt; LRESULT CALLBACK WndProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance,...

Странное поведение CreateWindowEx
Просто невероятное нежелание создавать окно. Уже неоднократно так писал, сравнивал с рабочими вариантами у себя и в msdn. Всё должно...

Странное поведение именованного канала
#include &quot;stdafx.h&quot; /* Код внутри stdafx.h: #pragma once #include &quot;targetver.h&quot; #include &lt;iostream&gt; #include &lt;string&gt; ...

3
1130 / 789 / 232
Регистрация: 12.04.2010
Сообщений: 2,012
26.03.2018, 00:13
Лучший ответ Сообщение было отмечено Fireball как решение

Решение

Цитата Сообщение от Fireball Посмотреть сообщение
в новом коде не могу добиться, чтобы эллипс рисовался без шлейфа. программа все равно не стирает старые положения эллипса
Откуда же программа знает, что надо стирать.

Есть такой способ, рисуем эллипс в режиме xor ( xor, "exclusive or", "исключающее или", сложение по модулю 2). Y =A+X mod 2. Если еще раз прибавить X, получим начальное значение. Y+X = A + X + X = A (mod 2 ).

Что будет, если два раза нарисовать эллипс в том же самом положении в режиме xor?
A - произвольный разряд какой-то точки исходного изображения на экране, X - разряд (бит) изображения эллипса.
A+X (mod 2) - после того, как первый раз нарисовали эллипс в режиме xor
A+X+X = A (mod 2) - второй раз нарисовали
Результат: получилось исходное значение A.

C++
1
2
3
4
    case WM_CREATE:
        // ...
        memdc=CreateCompatibleDC(hdc);
        SetROP2( memdc, R2_XORPEN );  // Изменим режим рисования
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    case WM_TIMER:
        
        //KillTimer(hWnd,1);
 
        Ellipse(memdc,xnew,ynew,xnew+2*R,ynew+2*R);
    // еще раз нарисуем эллипс в том же самом месте,  где он был нарисован в последний раз
 
        
        t = t + dt;
        xnew = x + v*t;
        ynew = y;
        Ellipse(memdc,xnew,ynew,xnew+2*R,ynew+2*R);
        InvalidateRect(hWnd,NULL,TRUE);
        //UpdateWindow(hWnd);
        
        //if(xnew<=620)
        //    SetTimer(hWnd,1,(int)timer,NULL);
        
        if(xnew  > 620)
            KillTimer(hWnd,1);
        
        break;
1
0 / 0 / 0
Регистрация: 10.07.2015
Сообщений: 16
26.03.2018, 00:24  [ТС]
Цитата Сообщение от Alex5 Посмотреть сообщение
Откуда же программа знает, что надо стирать.
А как же InvalidateRect с параметром TRUE? да и в старом коде, если ничего не делать, то там шлейфа нет - эллипс просто перемещается по экрану.

Цитата Сообщение от Alex5 Посмотреть сообщение
Есть такой способ
а за это спасибо
0
0 / 0 / 0
Регистрация: 10.07.2015
Сообщений: 16
27.03.2018, 18:06  [ТС]
Ну раз никто не ответил на остальные вопросы, то сам отвечу. Разобрался. Честно скажу, что пришлось перелопатить много информации. В официальной MSDN очень мутно написано и во многих ссылках в интернете просто перепечатка из MSDN.

Прочитав официальную документацию, я думал, что эта функция стирает с экрана перед обновлением в зависимости от последнего параметра. Оказалось хитрее. Алгоритм кратко такой: 1. помечает область, как требующую перерисовки (Сама не перерисовывает ничего, только помечает!), 2. посылает сообщение WM_PAINT, перед BeginPaint (или в нем) внутри WM_PAINT сначала стирает, если написано TRUE. Причем стирает до фона окна. 3. А потом выполняет код, написанный в WM_PAINT.

Но что такое фон окна? Казалось бы я в WM_CREATE указал залить все окно синим. Эту инфу пришлось покопать. Но это не считается фоном окна. Фоном окна считается
C++
1
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
в функции ATOM MyRegisterClass(HINSTANCE hInstance)

Но, если рисуешь в памяти и потом делаешь BitBlt в WM_PAINT, то после стирания эллипса на экране он снова появляется в добавок к новому из памяти. В памяти то InvalidateRect не стирает (я об этом не задумывался)! Я прочитав MSDN и подумал, что она стирает фон, то есть мой эллипс.

Как только я понял, что он отображает первоначальный фон окна, заданный в классе окна, я понял, что это практически бесполезная функция с TRUE: 1. вызывает мерцание при перерисовке, 2. зачем вообще отображать фон окна снова, если можно перекрашивать кистью, созданной для раскраски фона, делая Rectangle(). Тем более он показывает его на доли секунды(то есть как бы стирает), а потом (внимание!) снова отображает, то что там было! то есть стирать лучше, казалось бы, просто делая Rectangle на все окно цветом фона (в моем случае белым).

Но если рисуешь сразу на экране в hdc без буфера memdc, то InvalidateRect с параметром TRUE становится полезным. Нарисовал эллипс, потом послал InvalidateRect с TRUE (только не из WM_PAINT, иначе будет цикл), он стер эллипс, а потом сработал TIMER, который пересчитал положение и снова послал Invalidate с TRUE и так далее. Создается иллюзия движения. Но врядли хорошо часто без memdc использовать.

Назначение. То есть я использовал функцию не по назначению. Основное назначение - сообщить системе, что надо бы после рисования обновить окно. А я использовал еще и для стирания. Как было отмечено выше стирать лучше, рисуя белый эллипс на белом фоне заместо прошлого.

Ответы на мои вопросы. На номер 3 уже ответили.
1. Если убрать Ellipse в WM_TIMER старого кода, то программа все равно рисует эллипс, так как там стоит InvalidateRect с TRUE, который стирает предыдущий эллипс и вызывает код WM_PAINT, который рисует уже на экране на прямую без BitBlt. А потом расчет новых координат идет в WM_TIMER, и вызов снова InvalidateRect, который стирает старый эллипс и отображает на экране новый в hdc. Код плохой, так как задумка была рисовать в памяти и при WM_PAINT отображать память на экран и все (это видно по коду в WM_TIMER). Но тут действительно InvalidateRect стирает экран без способа, который предложил Alex5. Я поэтому и думал раньше, что Invalidate для удобного стирания и движения хорошо годится.

2. Если убрать из WM_PAINT старого кода Ellipse, но оставить Ellipse в WM_TIMER, то рисоваться ничего не будет вообще. Потому, что WM_PAINT рисовал на экране в hdc, а BitBlt там нет. А в WM_TIMER рисование только в memdc, а потом Invalidate, который стирает только на экране, а не в памяти, как я думал сначала. То есть в памяти остается прошлый эллипс нестертым и новый, который я нарисовал, а потом обновляем, но WM_PAINT ничего не рисует. Все нарисовано со шлейфом, но в памяти.

Для себя решил, что буду рисовать по возможности методом, предложенным Alex5. Но если надо на экране напрямую, то можно и с помощью InvalidateRect с TRUE.

Ссылки:
P.S. Уже сегодня, когда разобрался в этом нашел еще одно полезное сообщение из соседней темы.
вопрос об отличии InvalidateRect FALSE и TRUE, который я вначале тоже неправильно понял из документации MSDN
MSDN описание функции InvalidateRect
что такое фон окна на самом деле
и тут
полезная тема по InvalidateRect

Всем спасибо! Вопрос решен и понят
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
27.03.2018, 18:06
Помогаю со студенческими работами здесь

Странное поведение функции с переменным количеством аргументов
Честно говоря даже не знаю где проблема, надеюсь вы поможете разобраться. Есть функция LinkStr для соединения нескольких строк: //...

Странное поведение при работе с List Box
Здравствуйте! Столкнулась со странной проблемой... Пишу программу, которая при выборе файла, скидывает путь к файлу в вектор, при условии...

Странное поведение окна при нажатии VK_ALT
У меня есть обычное окно, в центр которого с помощью SetCursorPos() постоянно перемещается курсор. Когда я нажимаю клавишу ALT курсор...

Странное поведение указателя
class XMLDocument { public: char *xml; XMLDocument() { }; void NewXML()

Странное поведение bool
Помогал отлаживать код и мы наткнулись на удивительное. Кодер скрыл отображение варнингов в VS2010. Метод М1 не всегда возвращал...


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru