Страница 1 из 1
Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 12 май 2010, 00:20
Praid
Задали написать программу выводящую на экран изображение работающих часов, у которых есть секунудная и минутная стрелка. Нашел bmp изображение часов (без стрелок) создал по нему регион, вывел изображение часов (без стрелок), добавил обработчики событий что бы можно было перетаскивать часы левой кнопкой мыши, а выключать правой.
В общем не знаю как реализовать движение стрелок, у меня получается что стрелки вы водятся на не исчезают при изменение координат. Как сделать так что бы казалось что стрелка движется ? И что бы когда часы были закрыты другим окном они не сбивались ?
Вот сам проект.
http://rghost.ru/1594117
А вот код СPP:
Код: Выделить всё
// Clock-3.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Clock-3.h"
#include <math.h>
#include <conio.h>
#include <windows.h>
#define MAX_LOADSTRING 100
.............
............
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HDC hdcBits;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
hdcBits=::CreateCompatibleDC(hdc);
SelectObject(hdcBits, maskBitmap);
BitBlt(hdc, 0, 0, 280, 280, hdcBits, 0, 0, SRCCOPY);
// SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// SetLayeredWindowAttributes(hWnd, 0, 220, LWA_ALPHA);
{ // секундная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,2,RGB(255,100,100));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,119,35);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // минутная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(80,80,80));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,155,65);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // заглушка в центре циферблата
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(170,170,170));
hPenOld = (HPEN)SelectObject(hdc,hpen);
HBRUSH hBrush,hBrushOld;
hBrush = CreateSolidBrush(RGB(80,0,0));
hBrushOld = (HBRUSH)SelectObject(hdc,hBrush);
Ellipse(hdc,113,113,125,125);
SelectObject(hdc,hBrushOld);
DeleteObject(hBrush);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
return WM_PAINT;
}
DeleteDC(hdcBits);
EndPaint(hWnd, &ps);
break;
case WM_NCHITTEST:
{
return HTCAPTION;
}
case WM_NCRBUTTONUP:
{
PostQuitMessage(0);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
WinAPI изучаю всего две недели.
Спасибо за ответ !
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 12 май 2010, 00:33
Romeo
1. return WM_PAINT зачем делаешь?
2. Для того, чтобы обрабатывать сообщения от мышки, нужно ловить сообщения WM_LBUTTONUP и WM_RBUTTONUP, а ты пытаешься перехватить клик мышки по неклиентской части окна (NC - это non-client).
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 12 май 2010, 15:58
Praid
Romeo писал(а):1. return WM_PAINT зачем делаешь?
2. Для того, чтобы обрабатывать сообщения от мышки, нужно ловить сообщения WM_LBUTTONUP и WM_RBUTTONUP, а ты пытаешься перехватить клик мышки по неклиентской части окна (NC - это non-client).
1. Это случайно, не удалил.
2. Я же написал: что бы можно было перетаскивать часы левой кнопкой мыши, а выключать правой. Получается когда щелкаю левой кнопкой мыши я как бы обманываю и говоря что кликнул по заголовку тогда то и мое самодельное окно и перетаскивается.
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 12 май 2010, 21:24
Romeo
А, всё, я понял сакральный смысл. Теперь нужно сделать, чтобы часы шли, правильно? Всё очень просто.
1. Делаем таймер, вызывающийся раз в секунду.
2. В таймере увеличиваем две переменные. Угол секундной стрелки увеличиваем на PI/30. Проверяем, если угол секундной стрелки стал большим, чем 2*PI, то сбрасываем его в ноль у увеличиваем угол минутной стрелки на PI/30.
3. После увеличения переменных вызываем инвалидацию окна (InvalidateRect).
4. Поправляем код WM_PAINT. Рисуем стрелки о точки (Xcenter, Ycenter) до точки (Xcenter + Radius*sin(углаСтрелки), Ycenter + Radius*cos(углаСтрелки)).
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 12 май 2010, 23:53
Praid
Romeo писал(а):А, всё, я понял сакральный смысл. Теперь нужно сделать, чтобы часы шли, правильно?
Именно !
Romeo писал(а):
1. Делаем таймер, вызывающийся раз в секунду.
2. В таймере увеличиваем две переменные. Угол секундной стрелки увеличиваем на PI/30. Проверяем, если угол секундной стрелки стал большим, чем 2*PI, то сбрасываем его в ноль у увеличиваем угол минутной стрелки на PI/30.
3. После увеличения переменных вызываем инвалидацию окна (InvalidateRect).
4. Поправляем код WM_PAINT. Рисуем стрелки о точки (Xcenter, Ycenter) до точки (Xcenter + Radius*sin(углаСтрелки), Ycenter + Radius*cos(углаСтрелки)).
Вот как-то так наверно но все равно что то не хочет работать:
Код: Выделить всё
int nTimerID; // error C2086: 'int nTimerID' : redefinition
int nTimerID = SetTimer(hWnd, FIRST_TIMER, 1000, NULL); // таймер посылает сообщения с кодом WM_TIMER каждую секунду
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HDC hdcBits;
double alpha=0,beta=0;
switch (message)
{
case WM_PAINT:
for (int i=0; i<5; i++)
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
hdcBits=::CreateCompatibleDC(hdc);
SelectObject(hdcBits, maskBitmap);
BitBlt(hdc, 0, 0, 280, 280, hdcBits, 0, 0, SRCCOPY);
// SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// SetLayeredWindowAttributes(hWnd, 0, 220, LWA_ALPHA);
{ // секундная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,2,RGB(255,100,100));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,119,35);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // минутная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(80,80,80));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,119+65*sin(alpha),119+65*cos(alpha));//x,y);//155,65);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // заглушка в центре циферблата
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(170,170,170));
hPenOld = (HPEN)SelectObject(hdc,hpen);
HBRUSH hBrush,hBrushOld;
hBrush = CreateSolidBrush(RGB(80,0,0));
hBrushOld = (HBRUSH)SelectObject(hdc,hBrush);
Ellipse(hdc,113,113,125,125);
SelectObject(hdc,hBrushOld);
DeleteObject(hBrush);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
DeleteDC(hdcBits);
EndPaint(hWnd, &ps);
}
break;
case WM_TIMER:
{
alpha+=180/30;
beta+=180/30;
InvalidateRect(hWnd,0,NULL);
}
break;
case WM_NCHITTEST:
{
return HTCAPTION;
}
case WM_NCRBUTTONUP:
{
PostQuitMessage(0);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
KillTimer(hWnd, FIRST_TIMER); // уничтожения таймера
}
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 13 май 2010, 03:29
IceFlame
Дык у тебя секундная стрелка как рисовалась по жестко заданным координатам, так и рисуется дальше. Вообще лучше получай локальное время из системы и рисуй по нему часы.
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 13 май 2010, 14:36
Romeo
А ещё у тебя неверно создаётся, убивается и обрабатывается таймер. Он должен создаваться по WM_CREATE и убиваться по WM_QUIT. Обработчика для WM_TIMER я вообще не вижу.
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 13 май 2010, 18:27
Praid
IceFlame писал(а):Дык у тебя секундная стрелка как рисовалась по жестко заданным координатам, так и рисуется дальше.
Мне хотябы одну запустить, а с остальными я сам разберусь.
IceFlame писал(а):Дык у тебя секундная стрелка как рисовалась по жестко заданным координатам, так и рисуется дальше. Вообще лучше получай локальное время из системы и рисуй по нему часы.
Именно так и собирался сделать, когда получится заставить стрелки двигаться.
Romeo писал(а):А ещё у тебя неверно создаётся, убивается и обрабатывается таймер. Он должен создаваться по WM_CREATE и убиваться по WM_QUIT. Обработчика для WM_TIMER я вообще не вижу.
Вот, сделал как ты сказал, но изображение по прежнему статично:
Код: Выделить всё
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HDC hdcBits;
double alpha=0,beta=0;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
hdcBits=::CreateCompatibleDC(hdc);
SelectObject(hdcBits, maskBitmap);
BitBlt(hdc, 0, 0, 280, 280, hdcBits, 0, 0, SRCCOPY);
// SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// SetLayeredWindowAttributes(hWnd, 0, 220, LWA_ALPHA);
{ // секундная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,2,RGB(255,100,100));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,119,35);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // минутная стрелка
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(80,80,80));
hPenOld = (HPEN)SelectObject(hdc,hpen);
MoveToEx(hdc,119,119,NULL);
LineTo(hdc,119+65*sin(alpha),119+65*cos(alpha));//x,y);//155,65);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
{ // заглушка в центре циферблата
HPEN hpen,hPenOld;
hpen = CreatePen(PS_SOLID,3,RGB(170,170,170));
hPenOld = (HPEN)SelectObject(hdc,hpen);
HBRUSH hBrush,hBrushOld;
hBrush = CreateSolidBrush(RGB(80,0,0));
hBrushOld = (HBRUSH)SelectObject(hdc,hBrush);
Ellipse(hdc,113,113,125,125);
SelectObject(hdc,hBrushOld);
DeleteObject(hBrush);
SelectObject(hdc,hPenOld);
DeleteObject(hpen);
}
DeleteDC(hdcBits);
EndPaint(hWnd, &ps);
break;
// ----------------------TIMER-------------------------------
case WM_CREATE: // обработка таймера, у которого нет своей процедуры таймера
SetTimer(hWnd,1,1000,NULL); // таймер срабатывает каждые две секунды
break;
case WM_TIMER: // обработка сообщения WM_TIMER
{
alpha+=180/30;
beta+=180/30;
InvalidateRect(hWnd,0,NULL);
return FALSE;
}
break;
case WM_QUIT:
KillTimer(hWnd,1); // уничтожение таймера
break;
// ---------------------END TIMER-----------------------------
case WM_NCHITTEST:
{
return HTCAPTION;
}
case WM_NCRBUTTONUP:
{
PostQuitMessage(0);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 13 май 2010, 23:53
Romeo
sin и cos принимают угол в радианах. А ты в градусах тулишь. Аргумент у обоих функций должен быть таким: 3.1415*alpha/180.
Re: Аналоговые часы (WinAPI + GDI + C++) ?
Добавлено: 15 май 2010, 00:06
Praid
Вот сделал свой таймер:
Код: Выделить всё
int sec=0,sec2=0;
SYSTEMTIME st;
GetSystemTime(&st);
sec2 = st.wSecond;
do
{
SYSTEMTIME st;
GetSystemTime(&st);
sec = st.wSecond;
}
while (sec!=sec2+1);
Но он сильно грузит проц и часы подлагивают когда пытаешься их переместить.
Можно ли заменить SetTimer другим таймеров без отправки сообщений?