Тема: WinApi Робота з вікном
Добрий день. Одним із завдань є змусити вікно рухатися по периметру екрана проти годинникової стрілки після натискання Ентер, за годинниковою при натисканні пробілу і зупитини при Ескейп.
Все це діло реалізовано через таймери: коли потрібно створюється або убивається відповідний таймер,
Ескейп працює безвідмовно. З пробілом ніби все теж нормально, а от при натисканні Ентеру відбувається якесь дикунство: 1. екран може просто зупинитися в кутку, почати розширюватися, втікати за межі екрану, почати рухатися в два рази швидше, продовжити рух ЗА годинниковою стрілкою.
Ось код:
#include <iostream>
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int xWindowSize = GetSystemMetrics(SM_CXSCREEN); // ширина екрану у пікселях
int yWindowSize = GetSystemMetrics(SM_CYSCREEN); // висота екрану у пікселях
RECT rcWindow;
int cxWindowClient; // розмір клієнтської зони вікна у повноекранному режимі у пікселях
int cyWindowClient; // розмір клієнтської зони вікна у повноекранному режимі у пікселях
int cyWindowTitle; // висота заголовка
int cyWindowBorder; // ширина рамки вікна
int cxWindowBorder; // ширина рамки вікна
enum Direction
{
left, right, up, down
};
int move = 0;
static int dir = Direction::down;
void changeDirectionToOposite(int &dir)
{
if (dir == Direction::down)
{
dir = Direction::up;
}
if (dir == Direction::up)
{
dir = Direction::down;
}
if (dir == Direction::left)
{
dir = Direction::right;
}
if (dir == Direction::right)
{
dir = Direction::left;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static wchar_t szAppName[] = L"DemoFig";
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
HWND hwnd;
hwnd = CreateWindow(szAppName, L"Демонстрація таймерів", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
//UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}// int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
const UINT IDTIMER = 23454;
const UINT IDTIMERSHOW = 21123454;
const UINT IDTIMER_Reverse = 222;
const UINT IDTIMER_Clockwise = 111;
HDC hdc;
PAINTSTRUCT ps;
switch (iMsg)
{
case WM_CREATE:
SetTimer(hwnd, IDTIMER, 100, NULL);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_TIMER:
{
switch (wParam)
{
case IDTIMER:
wchar_t buf[444];
SYSTEMTIME st;
//GetSystemTime( &st );
GetLocalTime(&st);
wsprintf(buf, L" Сьогодні %02i.%02i.%i. Зараз %02i:%02i:%02i ", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond);
SetWindowText(hwnd, buf);
break;
case IDTIMER_Reverse: //проти часової стрілки
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
if (dir == Direction::down) //вниз && rcWindow.bottom != yWindowSize
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.bottom >= yWindowSize)
{
rcWindow.top = yWindowSize - (rcWindow.bottom - rcWindow.top);
MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::right;
}
}
else if (dir == Direction::right) //вправо && rcWindow.right != xWindowSize
{
MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.right >= xWindowSize)
{
rcWindow.left = xWindowSize - (rcWindow.right - rcWindow.left);
MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::up;
}
}
else if (dir == Direction::up) //вверх && rcWindow.top != 0
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.top <= 0)
{
MoveWindow(hwnd, rcWindow.left, 0, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::left;
}
}
else if (dir == Direction::left) //вліво && rcWindow.left != 0
{
MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.left <= 0)
{
MoveWindow(hwnd, 0, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::down;
}
}
}
case IDTIMER_Clockwise: // за годинниковою стрілкою
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
if (dir == Direction::down) //вниз && rcWindow.bottom != yWindowSize
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.bottom >= yWindowSize)
{
rcWindow.top = yWindowSize - (rcWindow.bottom - rcWindow.top);
MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::left;
}
}
else if (dir == Direction::right) //вправо && rcWindow.right != xWindowSize
{
MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.right >= xWindowSize)
{
rcWindow.left = xWindowSize - (rcWindow.right - rcWindow.left);
MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::down;
}
}
else if (dir == Direction::up) //вверх && rcWindow.top != 0
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.top <= 0)
{
MoveWindow(hwnd, rcWindow.left, 0, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::right;
}
}
else if (dir == Direction::left) //вліво && rcWindow.left != 0
{
MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
if (rcWindow.left <= 0)
{
MoveWindow(hwnd, 0, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
dir = Direction::up;
}
}
}
case IDTIMERSHOW: // показуємо приховане вікно
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
KillTimer(hwnd, IDTIMERSHOW);
break;
}
}
break;
#pragma region MOVE
case WM_KEYDOWN:
{
switch (wParam)
{
case L'Q': // ставить вікно у лівий верхній кут
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE);
break;
case L'Z': // ставить вікно у правий нижній кут
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
int dx = cxWindowClient + cxWindowBorder - rcWindow.right; // на скільки змістити праворуч
int dy = cyWindowClient + cyWindowBorder + cyWindowTitle - rcWindow.bottom; // на скільки зсунути донизу
OffsetRect(&rcWindow, dx, dy);
//SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
MoveWindow(hwnd, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
break;
case L'H': // Згортає вікно
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
SetTimer(hwnd, IDTIMERSHOW, 3000, NULL);
break;
case L'R': // Розгортає вікно
{
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
SetWindowPos(hwnd, NULL, 0, 0, cxWindowClient + cxWindowBorder * 2, cyWindowClient + cyWindowBorder + cyWindowTitle, SWP_SHOWWINDOW);
}
case VK_LEFT:
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
if (rcWindow.left != 0)
{
if (GetAsyncKeyState(VK_SHIFT))
{
MoveWindow(hwnd, rcWindow.left - 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else if (GetAsyncKeyState(VK_CONTROL))
{
MoveWindow(hwnd, rcWindow.left - 20, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else
{
MoveWindow(hwnd, rcWindow.left - 1, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
}
break;
}
case VK_RIGHT:
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
if (rcWindow.right != xWindowSize)
{
if (GetAsyncKeyState(VK_SHIFT))
{
MoveWindow(hwnd, rcWindow.left + 10, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else if (GetAsyncKeyState(VK_CONTROL))
{
MoveWindow(hwnd, rcWindow.left + 20, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else
{
MoveWindow(hwnd, rcWindow.left + 1, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
}
break;
}
case VK_UP:
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
//int dx = cxWindowClient + cxWindowBorder - rcWindow.right; // на скільки змістити праворуч
//int dy = 0; // на скільки зсунути донизу
//OffsetRect(&rcWindow, dx, dy);
//SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
if (rcWindow.top != 0)
{
if (GetAsyncKeyState(VK_SHIFT))
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top - 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else if (GetAsyncKeyState(VK_CONTROL))
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top - 20, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top - 1, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
}
break;
}
case VK_DOWN:
{
GetWindowRect(hwnd, &rcWindow); // отримує положення і розміри вікна
cxWindowClient = GetSystemMetrics(SM_CXFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowClient = GetSystemMetrics(SM_CYFULLSCREEN); // розмір клієнтської зони вікна у повноекранному режимі у пікселях
cyWindowTitle = GetSystemMetrics(SM_CYCAPTION); // висота заголовка
cyWindowBorder = GetSystemMetrics(SM_CYBORDER); // ширина рамки вікна
cxWindowBorder = GetSystemMetrics(SM_CXBORDER); // ширина рамки вікна
//int dx = cxWindowClient + cxWindowBorder - rcWindow.right; // на скільки змістити праворуч
//int dy = 0; // на скільки зсунути донизу
//OffsetRect(&rcWindow, dx, dy);
//SetWindowPos( hwnd, NULL, rcWindow.left, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW );
if (rcWindow.bottom != yWindowSize)
{
if (GetAsyncKeyState(VK_SHIFT))
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top + 10, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else if (GetAsyncKeyState(VK_CONTROL))
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top + 20, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
else
{
MoveWindow(hwnd, rcWindow.left, rcWindow.top + 1, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
}
}
break;
}
#pragma endregion
case VK_RETURN: // при натисканні Ентер
{
KillTimer(hwnd, IDTIMER_Clockwise); // вбиваємо таймер за годинниковою
changeDirectionToOposite(dir); // змінюємо напрямок на протилежний
SetTimer(hwnd, IDTIMER_Reverse, 100, NULL); // запускаємо таймер проти годинникової стрілки по клавіші ENTER
break;
}
case VK_SPACE: // при натисканні пробілу Space bar
{
KillTimer(hwnd, IDTIMER_Reverse);
changeDirectionToOposite(dir);
SetTimer(hwnd, IDTIMER_Clockwise, 100, NULL);// запускаємо таймер за годинниковою стрілкою
break;
}
case VK_ESCAPE: // при натисканні Escape
{
KillTimer(hwnd, IDTIMER_Reverse);
KillTimer(hwnd, IDTIMER_Clockwise);
dir = Direction::down;
break;
}
break;
}
}
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
} // LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
звернути увагу, думаю, треба на case VK_RETURN:, case IDTIMER_Reverse: