PDA

Visualizza la versione completa : [c++] Windows API: oggetto HDC


senise
08-09-2008, 15:49
Salve a tutti.
Sto creando un programma in C++ che utilizza le librerie grafiche WxWidgets.
Ho trovato una libreria che implementa alcune funzioni che mi servono all'interno del mio programma. Tra queste funzioni, ce n'è una che richiede come argomento un oggetto di tipo HDC che credo sia un oggetto definito nelle Windows API, per disegnare un'immagine. Ecco la funzione:


void DrawBarcode(HDC hDC,int iX,int iY0,int iY10,int iY11,const COLORREF clrBar,const COLORREF clrSpace,const int iPenW)

Io sto utilizzando le librerie grafiche WxWidgets, ho creato un frame ed ho visto che esiste la funzione:


wxWindow::GetHandle
void* GetHandle() const
/*
Returns the platform-specific handle of the physical window.
Cast it to an appropriate handle, such as HWND for Windows, Widget for Motif, GtkWidget for GTK or WinHandle for PalmOS.
*/


Ho provato a fare una così:



HWND hwnd = (HWND) frame->GetHandle();

Ora, le mie domande sono queste:
1) E' corretto questo cast:
HWND hwnd = (HWND) frame->GetHandle();
tenendo conto che GetHandle ha questo prototipo:
void* GetHandle() const

2) Come uso l'oggetto di tipo HWND? E' possibile ottenere da questo un oggetto HDC?

Grazie mille, saluti

Vincenzo1968
08-09-2008, 18:56
Ciao,

si, è possibile ottenere un handle al device context, così:



HDC hdc = GetDC(hwnd); // ottengo l'handle al device context
... // utilizzo l'handle per disegnare
ReleaseDC(hwnd, hdc); // lo rilascio quando non mi serve più


Si utilizza la funzione API GetDC per ottenere l'handle al device context a partire da quello della finestra. Alla fine bisogna rilasciare l'HDC con la funzione API ReleaseDC.

senise
08-09-2008, 20:01
Ok, grazie mille per la risposta.
Forse sono riuscito a disegnare. Dico forse perchè in realtà non vedo niente e non capisco se ciò sia dovuto:
1) al pannello che sta all'interno del Frame o
2) perchè ho dato le coordinate sbagliate.

Esiste un modo per ottenere le coordinate che posso passare alla funzione LineTo?
Grazie mille.
Saluti

Vincenzo1968
08-09-2008, 22:07
Originariamente inviato da senise
Ok, grazie mille per la risposta.
Forse sono riuscito a disegnare. Dico forse perchè in realtà non vedo niente e non capisco se ciò sia dovuto:
1) al pannello che sta all'interno del Frame o
2) perchè ho dato le coordinate sbagliate.

Esiste un modo per ottenere le coordinate che posso passare alla funzione LineTo?
Grazie mille.
Saluti

Ciao Senise,

non so se ti riferisci alla libreria wxWidgets o alla API.
Nel primo caso non posso aiutarti(ché non me ne intendo). Se vuoi posso spiegarti come utilizzare le funzioni per il disegno nella Win API con un piccolo programma di esempio.

senise
08-09-2008, 22:27
No, io mi riferivo alle WINAPI!
Devo disegnare con quelle,in particolare con il metodo "LineTo" però il FRAME è stato creato con le WxWidgets da cui ho ricavato, tramite un'apposita funzione, l'oggetto HWND e poi con il metodo da te suggerito quello HDC.
Se saresti così gentile da farmi vedere un esempio, te ne sarei molto grato, dato che non ho mai usato le WinAPI e non mi sembrano abbastanza amichevoli.
Grazie!
Saluti

Vincenzo1968
08-09-2008, 23:44
Il programma seguente disegna una linea orizzontale che divide la finestra in due. Un po' al di sopra della linea, stampa la stringa "Ciao, Mondo":

http://www.guidealgoritmi.it/images/ImgForums/CiaoMondo.jpg



#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("CiaoMondo");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL,
TEXT ("Errore nella registrazione della classe di finestra!"),
szAppName,
MB_ICONERROR);
return 0;
}

hwnd = CreateWindow(szAppName, // Nome della window class
TEXT ("Il titolo"), // Stringa che appare sulla barra del titolo
WS_OVERLAPPEDWINDOW, // Stile window
CW_USEDEFAULT, // Questo e i successivi
CW_USEDEFAULT, // tre parametri definiscono
CW_USEDEFAULT, // la posizione iniziale
CW_USEDEFAULT, // della finestra.
NULL, // Handle alla finestra padre
NULL, // Handle al menu della finestra
hInstance, // Handle all'istanza del programma
NULL); // Parametri di creazione della finestra

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);

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

return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
static int cxClient, cyClient;

switch (message)
{
case WM_CREATE:
return 0;

case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;

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

GetClientRect (hwnd, &rect);

rect.top -= 20;

DrawText (hdc, TEXT ("Ciao, Mondo!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);

MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;


EndPaint (hwnd, &ps);
return 0;

case WM_DESTROY:
PostQuitMessage (0);
return 0;
}

return DefWindowProc (hwnd, message, wParam, lParam);
}


Come vedi, un programma winapi ha il suo punto di ingresso nella funzione WinMain(al contrario dei programmi console che hanno il punto di ingresso nella funzione main).
Nella WinMain si definisce una struttura WNDCLASS e si impostano i vari campi(fra i quali, importantissimo, il campo lpfnWndProc che è un puntatore alla Window Procedure).
La Window Procedure è la funzione che si occupa di gestire i messaggi che Windows invia al programma, come la creazione della finestra o, ed è il caso che più ci interessa, il messaggio WM_PAINT che serve per disegnare nella client area della finestra.
Successivamente vengono chiamate quattro funzioni:

RegisterClass
CreateWindow
ShowWindow
UpdateWindow

Il cui compito è bene illustrato dal loro nome(se qualcosa non ti è chiaro, chiedi pure).

Nella WinMain, infine, viene avviato il loop dei messaggi che consente al sistema operativo di inviare i messaggi alla nostra finestra/applicazione:



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


Nella Window Procedure:



LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)


Scriviamo il codice per la gestione dei messaggi che ci interessano(nel nostro caso siamo particolarmente interessati al messaggio WM_PAINT).
Come vedi, per ottenere un HDC all'interno del messaggio WM_PAINT non si usa la funzione GetDC ma BeginPaint. Per rilasciare l'HDC al termine delle operazioni di disegno, si utilizza invece la funzione EndPaint.
GetDC e ReleaseDC si utilizzano invece se si vuole ottenere un HDC all'esterno del messaggio WM_PAINT.

Per disegnare il testo si utilizza la funzione DrawText(ma ne esistono, nella API, anche altre con svariati compiti/finalità).
Per disegnare la linea, il codice è il seguente:



...
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
...


Le coordinate dell'area client delle finestra, cyClient e cxClient, vanno prese durante l'eleborazione del messaggio WM_SIZE in modo che vengano aggiornate quando l'utente ridimensiona la finestra.

:)

P.S.
Ripeto, chiedi pure in caso di dubbi.

senise
09-09-2008, 03:15
Vincenzo1968 grazie mille per l'esempio, che mi ha fatto capire che forse la strada che sto percorrendo è ripida e tortuosa. L'esempio è molto chiaro, ma credo sia molto difficile utilizzare le WinAPI dalle WxWidgets. Dalle prove che ho fatto, non ho accesso alla struttura WNDCLASS e non saprei come cambiare il ciclo dei messaggi. L'unico oggetto che ho a disposizione è l'handle ad HWND.
Forse a questo punto è meglio cercare un'altra libraria che si interfacci nativamente con le WxWidgets piuttosto che con le WinApi.
Ti ringrazio ancora.
Saluti

Loading