WinAPI

soundag

вопрос элементарный, но мне как человеку никогда не работавшего с винапи сложный
как выглядит обработка сообщений для написаний движения объекта в окне?
конкретно: прямоугольник движется по экрану.

kokoc88

Там никаких сообщений, разве что WM_TIMER и WM_PAINT. Я бы на твоём месте написал это под MFC, если ничего большего, чем двигать прямоугольник не требуется.

soundag

нет. это нужно только на апи сделать

lenasoleil76

вообще-то если нужно только прямоугольник двигать, то MFC на х. не нужен, лучше Win32 project там все прозрачно два case'а на два сообщения и привет, а MFC у человека по первому впечатлению вызывает рвотную реакцию... но вероятно эти два сообщения и будут необходимыми и достаточными.

soundag

ну как... нифина не получается
вот пример:
case WM_TIMER:
if (f==1)
{

InvalidateRect(hwnd,NULL,1);

if (x>maxX) x=0;
else x+=dx;
}
break;

case WM_PAINT:
hdc=BeginPaint(hwnd,&paintstruct);
Rectangle(hdc,x-BOX_LENGTH,y-BOX_WIDTH,x+BOX_LENGTH,y+BOX_WIDTH);
//BitBlt(hdc,0,0,maxX,maxY, memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct);
break;

lenasoleil76

ты таймер то включил ? тчо от него сообщений ждешь ?

evgen5555

Маза таймер завести предварительно SetTimer'ом

soundag

таймер включен
из меня устанавливаем флаг=1 и после этого должен начать рисовать
как рисовать?
создаем виртуальное окно и в него рисуеи. но сейчас после выполнения программы ничего нет...
нужно ли виртуальное окно и из него обновлять контекст. или нет?

lenasoleil76

че такое виртуальное окно ? что есть, чего нет ? ты брики поставь посмотри получаешь ли ты сообщение или нет .. и если получаешь, то какие..
окно то само есть ?

clea_al

в wm_timer рисуешь в виртуальное окно и вызываешь инвалидейт, а в паинт просто битблт виртуального на реальное окно ...

evgen5555

А это как-то по-другому делаться может?

lenasoleil76

под виртуальным окном видимо понимается DC в памяти ?
на вопрос по другому: можно сразу рисовать в окно без BitBlt...
( возможно прямоугольник твой вне видимоя части, если все остально в порядке ).

clea_al

Можно конечно и без memdc, но тогда если на картинке есть статические обьекты (например стенка) то каждый раз надо будет рисовать заново. Плюс при стирании предыдущей,используя PatBlt, будет мигание....

rosali

ну как... нифина не получается

Ты цвета правильные выбрал (видные )? FillMode еще или чего там?..

lenasoleil76

еще самая очевидная ошибка : создавая CompatibleDC не забудь в него выбрать нормальную битмапу, а то она от рождения : 1х1 ЧБ !

kokoc88

Попросите у человека полный проект.

kokoc88

Сдаётся мне, что на МФЦ я это сделаю на порядок быстрее, чем кто-то на ВИНАПИ. Хотя, тут надо именно на ВИНАПИ.

rosali

в wm_timer рисуешь в виртуальное окно и вызываешь инвалидейт, а в паинт просто битблт виртуального на реальное окно ...

С буффером действительно лучше, чтоб не мигало, но можно в принципе это все на PAINT поставить и заполнение буффера, и flush.
Ладно, вопрос не в этом, написанный код тоже должен по идее работать!..

rosali

Не сцать, щас сделаю на WINAPI, -- у меня свой MFC есть

soundag

до этого в winmain есть и settimer синтрвалом в 1 с. и в конце killtimer
LRESULT CALLBACK WindowFunc(HWND hwnd,UINT message,
WPARAM wParam,LPARAM lParam)
{



HDC hdc;

int x, y, dx,dy;

PAINTSTRUCT paintstruct;
switch (message)
{
case WM_CREATE:
maxX = GetSystemMetrics (SM_CXSCREEN);
maxY = GetSystemMetrics (SM_CYSCREEN);
x_c=maxX/2
y_c=maxY/2;
x=BOX_WIDTH;y=y_c; dx=STEP;

hdc = GetDC(hwnd);
memdc = CreateCompatibleDC(hdc);
hbit = CreateCompatibleBitmap (hdc,maxX,maxY); SelectObject (memdc, hbit);
hbrush = (HBRUSH)GetStockObject (BKGROUND_COLOR);
SelectObject (memdc, hbrush);
PatBlt (memdc, 0,0, maxX,maxY,PATCOPY);
hMyPen=CreatePen(PS_SOLID,5, RGB(255,255,0;
SelectObject(memdc,hMyPen);
ReleaseDC(hwnd, hdc);

break;


case WM_TIMER:
if (f)
{
if (x>maxX) x=0;
else x+=dx;
Rectangle(memdc,x-BOX_LENGTH,y-BOX_WIDTH,x+BOX_LENGTH,y+BOX_WIDTH);

InvalidateRect(hwnd,NULL,1);

}
break;

case WM_PAINT:
hdc=BeginPaint(hwnd,&paintstruct);

BitBlt(hdc,0,0,maxX,maxY, memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct);
break;

case WM_COMMAND:
switch (LOWORD(wParam
{

case IDM_DRAW:
f=1
break;
case IDM_EXIT: DestroyWindow(hwnd);
break;

}
break;

case WM_DESTROY:
DeleteDC (memdc);
DeleteObject(hMyPen);
PostQuitMessage(0);
break;

default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}

soundag

вот вся функция окна

kokoc88

Я создал тебе HelloWorld на WinApi. Вот моя функция окна, она работает:


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
static bool bDrawing = false;
static int nTimer;
static int nX = 0;
#define MAX_X 640
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_START:
if (bDrawing)
{
bDrawing = false;
KillTimer(hWnd, nTimer);
}
else
{
bDrawing = true;
nTimer = SetTimer(hWnd, 1, 50, NULL);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
Rectangle(hdc, nX-80, 240, nX, 240+40);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
case WM_TIMER:
if (bDrawing)
{
InvalidateRect(hWnd, NULL, 1);
nX++;
if (nX > MAX_X)
nX = 0;
}
break;
}
return 0;
}

kokoc88

В своём коде попробуй

int x, y, dx,dy;


заменить на

static int x, y, dx,dy;

soundag

спасибо, большое...работает..
хотя не могу понять почему мой вариант не работал..

kokoc88

Например, потому что у тебя переменные не статические. Ты их при WM_CREATE устанавливаешь, но при повторном вызове этой функции они вообще-то неопределены.
Плюс, BitBlt почему-то выдаёт ошибку.

kokoc88

Впрочем, вот твоя версия этого дела, исправленная:


LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
static HDC memdc = NULL;
static int x = 0, y = 0, dx = 0;
PAINTSTRUCT paintstruct;
#define STEP 5
#define BOX_HEIGHT 40
#define BOX_LENGTH 80
static bool bDrawing = false;
static int maxX = 0;
static int maxY = 0;
static int x_c, y_c;
static int nTimer;
static HBRUSH hbrush = NULL;
static HPEN hMyPen = NULL;
static HBITMAP hbit = NULL;
switch (message)
{
case WM_CREATE:
maxX = GetSystemMetrics (SM_CXSCREEN);
maxY = GetSystemMetrics (SM_CYSCREEN);
x_c = maxX/2;
y_c = maxY/2;
x = BOX_LENGTH;
y = y_c;
dx = STEP;
hdc = GetDC(hwnd);
memdc = CreateCompatibleDC(hdc);
hbit = CreateCompatibleBitmap (hdc, maxX, maxY);
SelectObject (memdc, hbit);
hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
SelectObject(memdc, hbrush);
PatBlt (memdc, 0, 0, maxX, maxY, PATCOPY);
hMyPen = CreatePen(PS_SOLID, 5, RGB(255,255,0;
SelectObject(memdc, hMyPen);
ReleaseDC(hwnd, hdc);
break;
case WM_TIMER:
if (bDrawing)
{
if (x > maxX + BOX_LENGTH)
x = 0;
else
x += dx;
PatBlt (memdc, 0, 0, maxX, maxY, PATCOPY);
Rectangle(memdc, x, y, x-BOX_LENGTH, y-BOX_HEIGHT);
InvalidateRect(hwnd,NULL,1);
}
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &paintstruct);
BitBlt(hdc, 0, 0, maxX, maxY, memdc, 0, 0, SRCCOPY);
EndPaint(hwnd, &paintstruct);
break;
case WM_COMMAND:
switch (LOWORD(wParam
{
case IDM_START:
if (bDrawing)
{
bDrawing = false;
KillTimer(hwnd, nTimer);
}
else
{
bDrawing = true;
nTimer = SetTimer(hwnd, 1, 50, NULL);
}
break;
case IDM_EXIT:
DestroyWindow(hwnd);
break;
}
break;
case WM_DESTROY:
DeleteDC (memdc);
DeleteObject(hMyPen);
DeleteObject(hbit);
PostQuitMessage(0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}

rosali

Плюс, BitBlt почему-то выдаёт ошибку.

Еще бы не выдавать, HDC memdc тоже ведь поначалу не static был...

rosali

Не сцать, щас сделаю на WINAPI, -- у меня свой MFC есть

Эх опаздал Тяжко на моем MFC писать

bastii

На таймер плохо, особенно в 9х виндах (там вроде таймер чаще 18 раз в сек не сигналит). Лучше рисовать в отдельном потоке.

bastii

А WM_TIMER постится или сендтится?

bastii

А зачем битблитать в WM_PAINT и для этого инвалидейтить в WM_TIMER. Почему бы не заменить инвалидайт в WM_TIMER на битблит из WM_PAINT, а WM_PAINT удалить. Все равно не используешь paintstruct, Просто GetMessage пропускает WM_PAINT, если в очереди есть другие сообщения, поэтому при большом загрузе системы WM_TIMER будет выполняться, а WM_PAINT нет. Тогда вообще лучше перенести все из WM_TIMER в WM_PAINT, только оставить инвалидайт в WM_TIMER.

zontik

и вообще все перенести


... WinMain (...)
{
while (running)
{
if (PeekMessage(...
{
}
//!сюда
}
}


а за временем следить через QueryPerformanceCounter / QueryPerformanceFrequency

bastii

ага
Оставить комментарий
Имя или ник:
Комментарий: