WM_SETFONT funktioniert nicht
-
Hi an alle,
ich möchte in einem Fenster die Schriftart, die Windows als Standard verwendet, für Text, und für alle weiteren Texte (Text von Checkbox, Text auf Button) verwenden.Also habe ich in der WM_CREATE-Nachricht mit folgenden Code den Handle zur Schriftart erzeugt:
static LOGFONT LogFont; NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) memcpy(&LogFont, &(ncm.lfMessageFont), sizeof(LogFont)); HFONT hFont = CreateFontIndirect(&LogFont);
Dann habe die WM_SETFONT gesendet:
SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0));
Aber warum auch immer, sehe ich nur die verpixelte Schriftart, die ich von der Eingabeaufforderung kenne.
Kann mir bitte jemand helfen, den Fehler zu finden, warum es nicht geht?
bin echt am verzweifeln
-
Hi,
zu wenig Code und/oder zu wenig Beschreibung.
Hast Du überprüft ob das Fonthandle gültig ist ?
An welches Fenster sendest Du die WM_SETFONT ?BTW, brauchst Du die LOGFONT, die Du als static erzeugst später noch einmal ?
Wenn nicht, dann kannst Du den Font auch so erzeugen:NONCLIENTMETRICS ncm; HFONT hFont ncm.cbSize = sizeof(NONCLIENTMETRICS); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) hFont = CreateFontIndirect(&ncm.lfMessageFont);
-
erst mal vielen Dank für deine Hilfe...
Also, ich habe ein Hauptfenster, in dem ich ein Childfenster habe. Im Childfenster befinded sich eine CheckBox, ein Button, und freistehender Text.
Zuerst habe ich die WM_SETFONT-Nachricht an das Childfenster gesendet, damit alle Inhalte diese Schrift bekommen. Aber das funktionierte ja nicht. Nach vielen weiteren Probieren und anordnen und zuordnen der Nachricht, habe ich dann mal deinen geposteten Code probiert, an die CheckBox und den Button gesendet, und es funktionierte. Dann habe ich den ganzen Spaß nochmal mit der LOGFONT probiert, und es ging auch.
Vermutlich lag mein Fehler darin, dass ich die WM_SETFONT-Nachricht an einer falschen Stelle eingefügt habe.
Was allerdings noch nicht so richtig will, ist der Text im Childfenster.
Ich erzeuge den Text in der WM_PAINT-Nachricht des Childfensters.
So wie ich es jetzt verstanden habe, muss ich dort die Schrift mit SelectObject(HDC, HFONT) zuweisen. Und danach mit DeleteObject(HFONT) löschen.
Wie kann ich da jedoch den Handle für die, in der CheckBox verwendeten, Schriftart verwenden, ohne bei der CheckBox Probleme zu kriegen, wenn ich den Handle mit DeleteObject lösche?
Muss ich die Schriftart nochmal erzeugen - oder geht es auch effektiver?
-
In Deinem Child-Fenster musst Du natürlich die WM_SETFONT bearbeiten und das Fonthandle irgendwo speichern.
Wenn Du das Fonthandle erzeugt hast, dann darfst Du das GDI-Objekt natürlich nicht gleich wieder löschen, sondern erst, wenn Du es nicht mehr brauchst. Also entweder wenn Du einen neuen Font erzeugst oder wenn Du dein Programm beendest.Leider ist das Buch "Windows Programmierung" von Charles Petzold vergriffen, aber wenn Du es noch irgendwo zu einem anständigen Preis auftreiben kannst, dann würde ich es Dir wärmstens ans Herz legen. Du wirst es nicht bereuen.
Edith sagt mir gerade: http://www.c-plusplus.net/cms/modules.php?op=modload&name=mbBooks&file=index&func=isbn&isbn=3860631888
-
Jo danke erst mal für deine Tipps.
Doch ganz so wie ich denke, wie es sein müsste ist es noch nicht.Hier der Code zu den Nachrichten vom Childfenster:
LRESULT CALLBACK ChildProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hCkBx1; static HWND hButton1; static RECT rectWnd; static RECT rectTxt1; static RECT rectTxt2; static HFONT hFont; static HPEN hPen1; /*Bereich für den Text anpassen*/ rectTxt1.left = 18; rectTxt1.top = 59; rectTxt1.right = 306; rectTxt1.bottom = 90; rectTxt2.left = 18; rectTxt2.top = 308; rectTxt2.right = 306; rectTxt2.bottom = 323; switch (message) { case WM_CREATE: { NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(NONCLIENTMETRICS); if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)) hFont = CreateFontIndirect(&ncm.lfMessageFont); hPen1 = CreatePen(PS_SOLID, 1, RGB(213,223,229)); hButton1 = CreateWindowEx( NULL, "BUTTON", "push me", WS_CHILD | WS_VISIBLE, 266, 11, 47, 23, hwnd, NULL, ((LPCREATESTRUCT) lParam)->hInstance, NULL); SendMessage(hButton1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); hCkBx1 = CreateWindowEx( NULL, "BUTTON", "aktivieren", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 12, 15, 213, 16, hwnd, NULL, ((LPCREATESTRUCT) lParam)->hInstance, NULL ); SendMessage(hCkBx1, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); return 0; } case WM_SIZE: { /*Bereich für das Fenster anpassen*/ rectWnd.right = LOWORD(lParam); rectWnd.bottom = HIWORD(lParam); return 0; } case WM_PAINT: { PAINTSTRUCT ps; HDC hDC; const char szText1[] = "Hier steht ein Text"; const char szText2[] = "Hier steht auch ein Text"; hDC = BeginPaint (hwnd, &ps); { /*Schrift ausgeben*/ SelectObject(hDC, hFont); SetTextColor (hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkMode (hDC, TRANSPARENT); DrawText(hDC, szText1, lstrlen(szText1), &rectTxt1, DT_BOTTOM | DT_WORDBREAK); DrawText(hDC, szText2, lstrlen(szText2), &rectTxt2, DT_BOTTOM); /*Linie am rechten Rand zeichnen*/ SelectObject(hDC, hPen1); MoveToEx(hDC, rectWnd.right - 1, 0, NULL); LineTo(hDC, rectWnd.right - 1, rectWnd.bottom); } EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: { DeleteObject(hFont); DeleteObject(hPen1); return 0; } default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; }
Zum einen funktioniert die Sache mit dem Text nur, wenn ich SelectObject zwischen BeginPaint und EndPaint setze. Und weil damit die SelectObject Funktion in der WM_PAINT Nachricht steckt, wird sie jedes mal neu aufgerufen, was ziemlich oft sein kann. Gelöscht wird sie aber nur einmal.
Ich frag mich überhaupt, warum man den Text zeichnen in die WM_PAINT stecken soll. Der Text wird doch während der Laufzeit nicht mehr verändert. (jedenfalls in diesem Fall)
Dazu habe ich noch solche Probleme, dass der Fensterinhalt beim Größe ändern ganz schön flackert - und beim Wiederherstellen nach dem Minimieren ist das Fenster erst mal schwarz.
-
SendMessage (child, WM_SETFONT, (WPARAM) GetStockObject (DEFAULT_GUI_FONT), (LPARAM) 0);
?
-
Habe mir jetzt auch mal die Posts durchgelesen ^^
Und wollte dann noch ein paar Antworten geben ..winapi starter schrieb:
Zum einen funktioniert die Sache mit dem Text nur, wenn ich SelectObject zwischen BeginPaint und EndPaint setze.
Mit BeginPaint erzeugst du einen gültigen Device Context. Wenn der nicht vorhanden ist, schlägt SelectObject entweder fehl, oder schreibt das in einen vordefinierten DC, der mit dem DC das zu deinem Fenster gehört recht wenig zu tun hat. Wenn du SelectObject vor BeginPaint aufrufst, wird der DC, und somit die gewählte Schriftart, sowieso zurückgesetzt und mit einem neuen, gültigen DC befüllt. Deshalb soll man auch seine Zeichenoperationen mit BeginPaint einleiten und mit EndPaint schließen, weil so ein korrektes Zeichnen ermöglicht wird. EndPaint schließt die Zeichenoperationen auf den DC ab, und gibt den wieder frei. Würdest du das nicht tun, erzeugst du GDI Leaks, wodurch sich dein Fenster (und andere Anwendungen unter Umständen auch !) nicht mehr neu gezeichnet werden können. Mit GetDCEx könntest du auch selbst ein gültigen Device Context erstellen, aber auch den müsstest du mit wieder freigeben (dann aber mit ReleaseDC/DeleteDC). Das ist aber nur selten sinnvoll, weil BeginPaint dir diese Arbeit an sich komplett abnimmt.
winapi starter schrieb:
Und weil damit die SelectObject Funktion in der WM_PAINT Nachricht steckt, wird sie jedes mal neu aufgerufen, was ziemlich oft sein kann. Gelöscht wird sie aber nur einmal.
Erstmal, SelectObject wird überhaupt nicht gelöscht .. Höchstens die GDI-Handles, die du damit benutzt. Und dann versteh ich dein Problem daran nicht. Der Device Context wird auch jedesmal während WM_PAINT erstellt und wieder freigegeben. Und irgendwoher muss der (erneut) erstellte DC ja wissen, welche Schriftart er benutzen soll, das macht SelectObject.
winapi starter schrieb:
Ich frag mich überhaupt, warum man den Text zeichnen in die WM_PAINT stecken soll. Der Text wird doch während der Laufzeit nicht mehr verändert.
Der Text an sich vllt nicht (also die Zeichenkette), aber sobald z.B. das Fenster verschoben wird, muss auch der Text wieder neu gezeichnet werden. Du kannst ja mal einen Counter in WM_PAINT einbauen und den dir ausgeben lassen, dann siehst du, wie oft das System das Fenster neu zeichnen lässt. Und - glücklicherweise - entscheidet das System auch wann das passiert, und nicht der Programmierer (der kann natürlich auch das Neuzeichnen anfordern, aber er muss es nicht generell machen).
winapi starter schrieb:
Dazu habe ich noch solche Probleme, dass der Fensterinhalt beim Größe ändern ganz schön flackert - und beim Wiederherstellen nach dem Minimieren ist das Fenster erst mal schwarz.
Dann schaue dir mal WM_ERASEBKGND an ..
-
Moin,
case WM_PAINT: { PAINTSTRUCT ps; HDC hDC; HGDIOBJ hFontOld, hPenOld ; const char szText1[] = "Hier steht ein Text"; const char szText2[] = "Hier steht auch ein Text"; hDC = BeginPaint (hwnd, &ps); /*Schrift ausgeben*/ // Schriftart in den Gerätekontext wählen hFontOld = SelectObject(hDC, hFont); SetTextColor (hDC, GetSysColor(COLOR_WINDOWTEXT)); SetBkMode (hDC, TRANSPARENT); DrawText(hDC, szText1, lstrlen(szText1), &rectTxt1, DT_BOTTOM | DT_WORDBREAK); DrawText(hDC, szText2, lstrlen(szText2), &rectTxt2, DT_BOTTOM); /*Linie am rechten Rand zeichnen*/ hPenOld = SelectObject(hDC, hPen1); MoveToEx(hDC, rectWnd.right - 1, 0, NULL); LineTo(hDC, rectWnd.right - 1, rectWnd.bottom); // Ursprüngliche GDI-Objekte zurück in den Gerätekontext SelectObject (hDC, hPenOld) ; SelectObject (hDC, hFontOld) ; EndPaint(hwnd, &ps); return 0; }
winapi starter schrieb:
Dazu habe ich noch solche Probleme, dass der Fensterinhalt beim Größe ändern ganz schön flackert - und beim Wiederherstellen nach dem Minimieren ist das Fenster erst mal schwarz.
case WM_ERASEBKGND: return 1 ;
oder in der WNDCLASSEX
wcx.style = 0 ;