Hintergrund Textfeld ändern
-
Hi,
ich probiere gerade meine erste Anwenung mit der WinApi zu programmieren. Dabei hangel ich mich an einem Beispiel lang, welches ich für meine Zwecke modifiziert habe. Auf Knopfdruck wird hier etwas berechnet, und das Ergebnis in einem Textfeld ausgegeben. Abhängig von dem Ergebnis möchte ich nun die Hintregrundfarbe des Textfelds ändern (Ergebnis kann nur OK/NOK sein). Allerdings stehe ich dabei komplett auf dem Schlauch. In der .rc-Datei ist das Feld als "EDITTEXT" mit der ID "100" und dem Zusatz "WS_DISABLED" angelegt. Wie kann ich nun dieses Element umfärben, wenn ich mit der Berechnung durch bin?
Vielen Dank im Voraus
Ozzy
-
-
Hi,
danke für Deine Antwort; ich habe das mal genau so eingefügt (nur WM_CTLCOLORSTATIC in WM_CTLCOLOREDIT: geändert), allerdings ändert sich nichts. Muss ich das denn noch aufrufen?
MfG, Ozzy
P.S. Das ganze soll in einem Dialogfenster geschehen, falls das einen Unterschied macht...
-
Ozzy schrieb:
(nur WM_CTLCOLORSTATIC in WM_CTLCOLOREDIT: geändert)
Dann lese noch einmal den ersten Satz unter der Überschrift aus Bellis Link:
MSDN schrieb:
A static control, or an edit control that is read-only or disabled, ...
Bedenke, das Du WS_DISABLED gesetzt hast!
-
Hi,
habe es wieder in WM_CTLCOLORSTATIC geändert, aber trotzdem ändert sich die Farbe nicht. Deshalb für mich noch einmal die Verständnisfrage: wie rufe ich das Farbwechseln denn auf?
MfG, Ozzy
-
Wie hast Du das denn eingebaut?
Das Parent-Window Deines Controls bekommt diese Nachricht, muss sie bearbeiten und ein Handle zu einem Brush als return - Wert liefern.Du musst es also in die Nachrichtenbehandlung des Parents einbauen.
Hier ist doch auch Beispielcode:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb787524(v=vs.85).aspx
-
Der einfachheitshalber hier einmal der Quellcode (ohne Berechnung)
#include <windows.h> #include <BaseTsd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> char WorkString [80]; HANDLE hActInstance; static HBRUSH hbrBkgnd; int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { MSG msg; HWND hwnd; WNDCLASS wndclass; hActInstance = hInstance ; if (!hPrevInstance) { wndclass.style = NULL; 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 = GetStockObject (GRAY_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = "WndClassName" ; RegisterClass (&wndclass) ; } hwnd = CreateWindow ( "WndClassName" , NULL , WS_OVERLAPPEDWINDOW , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , CW_USEDEFAULT , NULL , NULL , hInstance , NULL) ; while (GetMessage (&msg , NULL , 0 , 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LONG FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) { switch (message) { case WM_CREATE: { DialogBox (hActInstance, "HptokwinDialog", hwnd, MakeProcInstance (DialogProc, hActInstance)) ; SendMessage (hwnd , WM_CLOSE , 0 , 0L) ; return 0 ; } case WM_DESTROY: { PostQuitMessage (0) ; return 0 ; } } return DefWindowProc (hwnd, message, wParam, lParam) ; } BOOL FAR PASCAL DialogProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) { switch (message) { case WM_INITDIALOG: { sprintf(WorkString, "Wait for start..."); SetDlgItemText(hwnd, 100, WorkString); return TRUE ; } case WM_CTLCOLORSTATIC: { HDC hdcStatic = (HDC) wParam; MessageBox(NULL, "WM_CTLCOLORSTATIC", "Info", MB_ICONINFORMATION); SetTextColor(hdcStatic, RGB(0,255,255)); SetBkColor(hdcStatic, RGB(255,0,0)); if (hbrBkgnd == NULL) { hbrBkgnd = CreateSolidBrush(RGB(0,0,0)); } return (INT_PTR)hbrBkgnd; } case WM_COMMAND: { switch (wParam) { case IDOK: { // Calculate return TRUE ; } case IDCANCEL: { EndDialog (hwnd , 0) ; return TRUE ; } } } } return FALSE ; }
Ich habe noch eine Messagebox eingebaut die sich eigentlich melden sollte; tut sie aber nicht...
MfG, Ozzy
-
Du musst Deinem Control auch irgendwo sagen, dass es sich neu zeichnen soll ... das sehe ich in Deinem Code nicht?
-
Moin,
ich stehe glaube ich gerade auf dem Schlauch... Noch einmal die Frage: wie schaffe ich es abhängig vom Berechnungsergebnis (im Case IDOK) das Textfeld z.B. grün oder rot zu färben? Mit dem WM_CTLCOLORSTATIC hätte ich doch auch nur eine Farbe, oder kann ich die irgendwie mitgeben? Und wie zeichne ich das Textfeld hinterher erneut?
Vielen Dank im Voraus
Ozzy
-
Ein einfaches Beispiel, bei jedem Betätigen des Knopfes wechselt das Editfeld seine Hintergrundfarbe:
#include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { 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 = "FensterKlasse"; RegisterClass (&wndclass); //Ein einfaches Fenster erstellen hwnd = CreateWindow ("FensterKlasse", "Fenster", WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME, CW_USEDEFAULT, CW_USEDEFAULT, 200, 100, NULL, NULL, hInstance, NULL); 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) { //Zwei Brushes für zwei verschiedene Hintergrundfarben static HBRUSH brush0 = CreateSolidBrush(RGB(255, 0, 0)); static HBRUSH brush1 = CreateSolidBrush(RGB(0, 255, 0)); //ein Editfeld static HWND editFeld; //Status der Hintergrundfarbe, kann 0 oder 1 annehmen static int brushNr = 0; switch (message) { case WM_CREATE : //ein Editfeld mit dem Attribut WS_DISABLED erstellen editFeld = CreateWindowEx (WS_EX_CLIENTEDGE, "edit", NULL, WS_CHILD | WS_VISIBLE | WS_DISABLED | ES_LEFT, 3, 3, 80, 20, hwnd, (HMENU) 1, ((LPCREATESTRUCT) lParam) -> hInstance, NULL); //Einen Button erstellen CreateWindow ("button", "Knopp", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 3, 33, 80, 20, hwnd, (HMENU) 2, ((LPCREATESTRUCT) lParam) -> hInstance, NULL); return 0; case WM_CTLCOLORSTATIC: //Hintergrundfarbe für das disabled Editfeld abhängig vom Status der Hintergrundfarbe zurückgeben if(brushNr) return (LRESULT)brush1; else return (LRESULT)brush0; case WM_COMMAND : //Auf Knopfdruck den Status der Hintergrundfarbe toggeln brushNr = !brushNr; //Neuzeichnen des Editfeldes veranlassen InvalidateRect(editFeld, 0, TRUE); return 0; case WM_DESTROY : DeleteObject(brush0); DeleteObject(brush1); PostQuitMessage (0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam); }
-
Hi,
vielen Dank für Dein ausführliches Beispiel. Allerdings funktioniert es immer noch nicht; ich habe noch einmal eine Messagebox eingebaut, wenn das WM_CTLCOLORSTATIC aufgerufen wird. Allerdings wird die auch nicht gezeigt. In meiner Entwicklungsumgebung Watcom unter WinXP für ein 16bit Programm für Win 3.11 (fragt nicht!!!) kennt er das WM_CTLCOLORSTATIC auch nicht, so dass ich hier den Wert 0x0138 definieren musste. Aber liegt es wirklich an der Umgebung?
MfG, Ozzy
-
Ich stelle gerade selbst erstaunt fest, dass mein Beispielprogramm unter WinXP erstellt mit VS 2010 einwandfrei läuft, unter Win7 aber nicht.
Weder die exe, die unter XP läuft, noch eine unter Win7 aus dem geposteten Quelltext mit VS 2012 erstellte Version ...Das Programm läuft zwar, aber von dem disableten Editfeld wird nur ganz rechts und links am Rand eine dünne Linie wie gewünscht gefärbt.
Eine Erklärung dafür habe ich leider nicht ...
-
Hi,
aber bei Dir wird das WM_CTLCOLORSTATIC wenigstens aufgerufen, oder?
-
Wie gesagt, unter XP läuft es einwandfrei. Unter Win7 gehe ich davon aus, dass die Message kommt, weil ich am rechten und linken Rand des Edit-Controls den gewünschten Effekt sehe.
Läuft das Beispiel bei Dir unter XP etwa auch nicht? Oder hast Du keine Möglichkeit, es auf XP zu testen?
-
Also: ich habe unter meinem Win7 64-Bit den Windows Virtual PC laufen (XP-Mode). Hier verwende ich den Watcom compiler. Ist also alles etwas kompliziert...
-
Ich habe es in einem virtuellen XP (VMWare) auf Win7 64 mit VS 2010 erstellt, da läuft es einwandfrei.
Auf dem Win7 leider nicht, und ich hab keine Ahnung, warum nicht
-
Belli schrieb:
Ich habe es in einem virtuellen XP (VMWare) auf Win7 64 mit VS 2010 erstellt, da läuft es einwandfrei.
Auf dem Win7 leider nicht, und ich hab keine Ahnung, warum nichtNaja, unter läuft einwandfrei verstehe ich was anderes ...
Hab das Programm gerade unter XP getestet - das Editfeld wird auch hier nur
eingefärbt, solange das Feld mit WS_DISABLED nicht editierbar ist.Wenn man mit SetWindowText(editFeld, "test") einen Text reinschreibt hat dieser einen weissen Hintergrund.
Wenn man das Flag WS_DISABLED weglässt ist der Text editierbar, der Hintergrund aber nicht in der
gewünschten Farbe - egal wie of man den Knopf drückt.Setzt man einen Breakpoint auf WM_CTLCOLORSTATIC wird dieser nicht ausgelöst.
Verbesserungsvorschlag:
Die Message WM_CTLCOLORSTATIC wird nur bei readonly edit controls angesprungen -ansonsten WM_CTLCOLOREDIT.
Die Textfarbe sollte sich von der Hintergrundfarbe unterscheiden und Text sollte mit transparenter
Hintergrundfarbe geschrieben werden.Das könnte insgesammt so aussehen:
case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { if((HWND)lParam == editFeld) { HDC hdcStatic = (HDC)wParam; SetTextColor(hdcStatic, RGB(0, 0, 0)); SetBkMode(hdcStatic, TRANSPARENT); if(brushNr) return (LRESULT)brush1; else return (LRESULT)brush0; } return (INT_PTR)GetStockObject(WHITE_BRUSH); }
Auch die Kommentare unter
http://msdn.microsoft.com/de-de/library/windows/desktop/bb787524(v=vs.85).aspx
geben weitere Verbesserungsvorschläge ...
// (as an aside, you should call DefWindowProc here) SetDCBrushColor(hdc, 0xFF00FF); // select some color into the DC brush return (LPARAM)GetStockBrush(DC_BRUSH); // return the DC brush -- no need to release it!
-
Natürlich wird es nur eingefärbt, solange es disabled ist, darum geht es hier ja. Für ein editierbares Feld muss WM_CTLCOLOREDIT bearbeitet werden, ich glaube, das wurde im Verlauf des Threads schon erwähnt.
Auch das klappt übrigens unter Win7 mit dem geposteten Testprogramm, wenn man es entsprechend ändert, nicht.
Du hast nicht zufällig auch eine Idee, warum das unter Win7 anders läuft, als unter XP, bzw. wie man es unter Win7 so anpassen muss, damit es sich so verhält, wie unter XP?
-
Belli schrieb:
Du hast nicht zufällig auch eine Idee, warum das unter Win7 anders läuft, als unter XP, bzw. wie man es unter Win7 so anpassen muss, damit es sich so verhält, wie unter XP?
Bei mir läuft das Programm unter Win7 exakt genau so wie unter XP. Ich habe mit und ohne WS_DISABLED getestet.
Hier die optimierte Version:
case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: if((HWND)lParam == editFeld) { HDC hdc = (HDC)wParam; SetTextColor(hdc, RGB(0, 0, 0)); SetBkMode(hdc, TRANSPARENT); if(brushNr) SetDCBrushColor(hdc, 0x00FF00); // select some color else SetDCBrushColor(hdc, 0x0000FF); // select some color return (LPARAM)GetStockObject(DC_BRUSH); // return the DC brush } break;
Einzige Änderung im Code ist die oben genannte Stelle, das Einbinden von tchar.h sowie die Umstellung aller Texte auf Unicode (Projektdefault bei VS).
Wen die vielen Werbepopups nicht abschrecken - hier eine Version zum Testen.