Windows-Message wird bei Programm-Aktion ignoriert
-
Hallo @ll,
wie so mancher vieleicht schon gelesen hat, versuche ich mich an sowas wie Paint.
Doch da der aktuelle Fehler nun wirklich nicht mehr in das Topic past, mache ich ein neues auf.Jetzt passiert folgendes:
Ich male, und wechsele auf Farbe Weiß, oder eine andere Stiftbreite, was ungefähr so aussiehtLRESULT CALLBACK WndProc( HWND myWnd, UINT givenMessage, WPARAM wParam, LPARAM lParam ) /* This function recieves the Messages, wich are given from MS-Windows to the program. So the program can do message specific actions, if this message is incoming. */ { PAINTSTRUCT myPaint; BOOL visitMsg = FALSE; static POINT myPoint, mousePointForPaint; static RECT myRect, parent; static COORD mouseKoord; HANDLE backUp; char version[50]; struct paintHist *akt; BYTE kBuff[255]; switch( givenMessage ) { //SEHR viel code case WM_PAINT: myHdc = BeginPaint( myWnd, &myPaint ); //open device-context (paintplace) { backUp = SelectObject( myHdc, *aktPen ); akt = first; while( NULL != akt->next ) { if( akt->isBreak != TRUE ) { DeleteObject( aktPen ); *aktPen = CreatePen( PS_SOLID, akt->width, RGB( akt->cRed, akt->cYellow, akt->cBlue ) ); SelectObject( myHdc, *aktPen ); MoveToEx( myHdc, //Zeichenfläche akt->pointToPaint.x, //X-Koordinate akt->pointToPaint.y, //Y-Koordinate NULL //old-Koordinate ); LineTo( myHdc, //Zeichenfläche akt->next->pointToPaint.x, //X-Koordinate akt->next->pointToPaint.y //Y-Koordinate ); } akt = akt->next; } SelectObject( myHdc, backUp ); } EndPaint( myWnd, &myPaint ); visitMsg = TRUE; break; case WM_COMMAND: switch( LOWORD(wParam) ) { [...] case cWHITE: aktPen = &whitePen;//slect white pen R = 255; G = 255; B = 255; visitMsg = TRUE; break; case cBLACK: aktPen = &blackPen;//slect white pen R = 0; G = 0; B = 0; visitMsg = TRUE; break; case sSMALL: DeleteObject( aktPen ); *aktPen = CreatePen( PS_SOLID, 1, RGB( R, G, B ) ); aktWidth = 1; visitMsg = TRUE; break; case sMIDDLE: DeleteObject( aktPen ); *aktPen = CreatePen( PS_SOLID, 3, RGB( R, G, B ) ); aktWidth = 3; visitMsg = TRUE; break; case sBIG: DeleteObject( aktPen ); *aktPen = CreatePen( PS_SOLID, 5, RGB( R, G, B ) ); aktWidth = 5; visitMsg = TRUE; break; default: ; break; } break; case WM_KEYDOWN: GetKeyboardState( kBuff ); //get virtual keys if( kBuff[VK_CONTROL]&0x80 && kBuff['Z']&0x80 ) //STRG + Z { akt = first; if( akt->next != NULL ) { while( NULL != akt->next->next ) { akt = akt->next; } if( akt->next != NULL ) { free( akt->next ); akt->next = NULL; last = akt; akt->isBreak = TRUE; } } } InvalidateRect( myWnd, NULL, TRUE ); visitMsg = TRUE; break; //viel code default: break; } if( visitMsg ) return 0; else return DefWindowProc( myWnd, givenMessage, wParam, lParam ); }
aktPen = glob. HPEN*
aktWidth = glob. int
first = struct paintHist*
last = struct paintHist*
struct paintHist:struct paintHist { POINT pointToPaint; int cRed; int cYellow; int cBlue; int width; BOOL isBreak; struct paintHist *next; };
Standardmäßig ist die Farbe auf Schwarz und 1 px gesetzt.
Nun reicht es auch, auf pensize 1 px zu wechseln (was schon eingestellt ist) und schon reagiert er nicht mehr auf STRG+Z, kann mir da irgend wer eine plausible erklärung geben?
Ich denke es hängt mit ... ja keine ahnung,
denn wenn ich allles auf standardeinstellung lasse, und einfach STRG+Z drücke, funktionierts, und auch in Zeile 30 (WM_PAINT) wird DeleteObject und SelectObject benutzt...Die IDEE:
Damit ich sowas wie eine History habe, schreibe ich Koordinaten in eine einfach verkettete Liste, diese wird einfach "aufgezeichnet" wenn WM_PAINT aufgerufen wird.
Bei drücken der Kombination STRG + Z soll das letzte Element der Liste gelöscht werden, und dann alles neu gezeichnet werden.
Gezeichnet wird immer bis zu dem letzten Element.So sollte alles klappten, allerdings -wie beschrieben- gerät alles bei einem wechsel jeglicher Art, ausser Kontrolle.
Ach ja: Der Button Close -komischerweise- funktioniert zu 100%, auch wenn man die Farbe wechselt
-
Weiß keiner was, war ich zu ungenau?!
Sind noch offene Fragen?
Redet bitte mit mir
-
In deinem Code verwaltest du die aktuelle Stiftfarbe und -breite doppelt, einmal in aktPen und einmal in R, G, B und aktWidth.
Du brauchst keine globale Pen-Variable. Du benutzt doch den Pen sowieso nur in WM_PAINT, und da hast du alle Daten, die du brauchst, in deiner verketteten Liste. Ironischerweise ist dort ja auch das erste, das du mit aktPen machst, Wegwerfen und neu Erstellen
-
WHA.. ich habe Mousemove vergessen... tut mir leid...
case WM_MOUSEMOVE: myHdc = GetDC( myWnd ); //open device-context (paintplace) { if( wParam == MK_LBUTTON ) { if( myPoint.x != -1 ) { myPoint.x = mouseKoord.X; //set new coordinates myPoint.y = mouseKoord.Y; akt = last; if( NULL == first->next ) { akt = first; akt->pointToPaint.x = myPoint.x; akt->pointToPaint.y = myPoint.y; akt->cRed = R; akt->cYellow = G; akt->cBlue = B; akt->width = aktWidth; akt->next = NULL; last = akt; } if( NULL != ( akt->next = malloc( sizeof( struct paintHist ) ) ) ) { if( last->isBreak != TRUE ) { backUp = SelectObject( myHdc, *aktPen ); MoveToEx( myHdc, //Zeichenfläche last->pointToPaint.x, //X-Koordinate last->pointToPaint.y, //Y-Koordinate NULL //old-Koordinate ); LineTo( myHdc, //Zeichenfläche myPoint.x, //X-Koordinate myPoint.y //Y-Koordinate ); SelectObject( myHdc, backUp ); } akt = akt->next; akt->pointToPaint.x = myPoint.x; akt->pointToPaint.y = myPoint.y; akt->cRed = R; akt->cYellow = G; akt->cBlue = B; akt->width = aktWidth; akt->next = NULL; last = akt; } //InvalidateRect( myWnd, NULL, TRUE); } else { myPoint.x = mouseKoord.X;//The first coordinates myPoint.y = mouseKoord.Y; } } visitMsg = TRUE; } ReleaseDC( myWnd, myHdc ); break;
Besser währe auch
aktWidth = 3; *aktPen = CreatePen( PS_SOLID, aktWidth, RGB( R, G, B ) );
anstatt
*aktPen = CreatePen( PS_SOLID, 3, RGB( R, G, B ) ); aktWidth = 3;
richtig?
R, G, B und aktWidth brauhe ich also wirklich...
Ich würde den Pen nicht löschen und neu erzeugen wenn es sowas wie editPen gäbe !?
Habe zumindest nichts dergleichen gefunden.
-
lippoliv schrieb:
Besser währe auch
aktWidth = 3; *aktPen = CreatePen( PS_SOLID, aktWidth, RGB( R, G, B ) );
anstatt
*aktPen = CreatePen( PS_SOLID, 3, RGB( R, G, B ) ); aktWidth = 3;
richtig?
Besser wäre, wenn du an dieser Stelle überhaupt keinen Pen erzeugen würdest. Das ist komplett überflüssig.
lippoliv schrieb:
R, G, B und aktWidth brauhe ich also wirklich...
Das habe ich nie bestritten. Aber du brauchst keine globale HPEN-Variable. Warum malst du überhaupt in WM_MOUSEMOVE?
- Speichere in deinen Variablen, wenn der Benutzer die Stiftfarbe oder -breite ändert.
- Häng einen neuen Eintrag an deine Liste, wenn der Benutzer mit der Maus klickt, und ruf InvalidateRect auf.
- Zeichne den Inhalt deiner Liste in WM_PAINT. Nur hier brauchst du einen Pen.
-
Ich würd jetzt einfach sagen "Nein" aber das mache ich nicht, was du sagst ist richtig... Aber dermasen In-performant das man nicht flüssig malen kann.
Auf diese art und weise zuckt mein "Form" nicht zusammen, wenn ich male, sondern wird erst komplett neu dargestellt, wenn es benötigt wird.
Ich hatte es mal mit invalidate rect, da hat das dermaßen gezuckt + CPU belastet, dass ich das nicht mehr witzig fand.
So habe ich ein Form, was nie zuckt(oder wie auch immer man das bezeichnen will) und trotzdem bleibt meine Zeichnung vorhanden.
Könntest du(auch wenn du zu diesem Beitrag was schreibst) noch vlt. irgend etwas zu dem geposteten Problem sagen, nicht weil mir deine !konstruktive! kritik nicht gefällt -bin für sowas offen- sondern weil ich da auch gerne irgendwie nen anhaltspunkt haben würde :p
Ich verstehe diesen Fehler -wie gepostet- nämlich gar nicht
-
lippoliv schrieb:
Ich verstehe diesen Fehler -wie gepostet- nämlich gar nicht
Ich auch nicht. Dein Code ist nämlich ein ziemlich undurchsichtiges Kuddelmuddel, wenn ich mal so sagen darf. Da ist viel unnötiger Ballast drin, der die Fehlersuche erschwert. Wenn du das so lassen willst, bitte sehr.
Da der Code unvollständig ist, kann ich ihn auch nicht hier bei mir durch den Debugger laufen lassen. Das wirst du dann wohl selbst tun müssen.
Was mir noch auffällt: Du intialisierst isBreak nicht, wenn du eine neue paintHist in deine Liste hängst.
-
MFK schrieb:
Ich auch nicht. Dein Code ist nämlich ein ziemlich undurchsichtiges Kuddelmuddel, wenn ich mal so sagen darf. Da ist viel unnötiger Ballast drin, der die Fehlersuche erschwert. Wenn du das so lassen willst, bitte sehr.
Hab ich nie behauptet.. Immer her mit sachen wie "das kann raus... Weil," ich bin schließlich kein Profi sondern lerne lediglich, und will natürlich dem entsprechend besser werden.
Nur die sache mit dem WM_PAINT fand ich einfach inakzeptabel. Ich könnte mit viel aufwand alles wieder so hin bekommen, aber es ist halt echt schlecht, weil während des malens das Form ... ja "zuckt" oder so.... Schau dir GIMP oder Paint an, da zuckts nirgends.
Ich neige schnell dazu kuddelmuddel zu schreiben, liegt daran das das nie jemand anmerkt/ich noch nicht weiß wie manche sachen einfacher gehen, als z.B. mit einer Boolvariable.
MFG
[edit] ich habe keinen debugger....
#define WINVER 0x0600 #include <windows.h> //defines #define appName "myPaint" #define appTitle "myPaint, draw a Picture" #define WM_MOUSEPOS 2954 #define histLength 100 #define CLOSE 1 #define cBLACK 2 #define cWHITE 3 #define sSMALL 4 #define sMIDDLE 5 #define sBIG 6 #define VERSION "1.20.77.080131" //Globale Variablen HINSTANCE myHandleInst; HWND myConsole, myAppWnd, bClose, bBlack, bWhite, versionWnd, bSmall, bMiddle, bBig; HPEN whitePen, blackPen; HPEN *aktPen; HDC myHdc; int R, G, B, aktWidth; struct paintHist { POINT pointToPaint; int cRed; int cYellow; int cBlue; int width; BOOL isBreak; struct paintHist *next; }; struct paintHist *first; struct paintHist *last; //Funktionsprototypen void setGlobalVars( void ); BOOL regApp( void ); BOOL createMainWindow( int ); LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); //BeginOfProgramm int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) /* Autor: Oliver Lippert Begin: 2008-01-28 End: ============== Description: I want to make a program like Paint. You have colors, different sizes and you can delete your last step */ { MSG myWndMsg; //zur übermittlung von Messages die an mein programm gehen myHandleInst = hInstance; //das Handle der Instanz wird global benötigt, da es nicht mit parametern übergeben werden kann int returnValue = 1; myConsole = GetConsoleWindow(); setGlobalVars(); if( NULL != ( first = malloc( sizeof( struct paintHist ) ) ) ) { first->next = NULL; last = first; ShowWindow( myConsole, SW_HIDE ); if( !regApp() || !createMainWindow( nCmdShow ) ) //Fenster Registrieren und Hauptfenster erstellen returnValue = 0; while( GetMessage( &myWndMsg, NULL, 0, 0 ) ) //Auf Nachricht warten(muss in jedes Windows-Programm) { TranslateMessage( &myWndMsg ); //Übersetzt von "Virtual Key" zu "Character" message DispatchMessage( &myWndMsg ); //Bearbeitet die Message(std oder nach WndProc()) } } else returnValue = -1; DeleteObject( blackPen ); DeleteObject( whitePen ); if( 1 != returnValue ) return myWndMsg.wParam; else return returnValue; } void setGlobalVars( void ) { int i, j; whitePen = CreatePen( PS_SOLID, 1, RGB( 255, 255, 255 ) ); blackPen = CreatePen( PS_SOLID, 1, RGB( 0, 0, 0 ) ); R = 0; G = 0; B = 0; aktPen = &blackPen; aktWidth = 1; } BOOL regApp( void ) /* Register the Window-Class, so that you can Create a window. This function declares the 'details' of the program. */ { WNDCLASSEX myWnd; myWnd.cbSize = sizeof( WNDCLASSEX ); //size of the strucutre //Fensterstile (darsellungs-Modus) festlegen //HREDRAW = bei neuskalierung (breite) updaten //VREDRAW = bei neuskalierung (höhe) updaten myWnd.style = CS_HREDRAW | CS_VREDRAW; myWnd.lpfnWndProc = (WNDPROC)WndProc; //if there is an incomming message myWnd.cbClsExtra = 0; //extra memory for the class myWnd.cbWndExtra = 0; //extra memory for the window myWnd.hInstance = myHandleInst; //handle from that instance, wich the window belong to myWnd.hIcon = LoadIcon( NULL, IDI_APPLICATION ); //Program icon (set to std) myWnd.hCursor = LoadCursor( NULL, IDC_ARROW ); //the cursor, wich schould been used in this program myWnd.hbrBackground = (HBRUSH)COLOR_GRAYTEXT; //background of the window myWnd.lpszMenuName = NULL; //there is no menue myWnd.lpszClassName = appName; //application name myWnd.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); //smal Icon( eventually the tray-icon ) return RegisterClassEx( &myWnd ); //register the class, return the } BOOL createMainWindow( int cmdMod ) /* This function create und show the Window */ { HWND myWnd; BOOL returnValue; RECT parent; myWnd = CreateWindow( appName, //Name der Fensterklasse appTitle, //Titel des Fensters WS_VISIBLE, //Stil des Fensters CW_USEDEFAULT, //Position X CW_USEDEFAULT, //Position Y 800, //Breite 600, //Höhe NULL, //Parent NULL, //Menue myHandleInst, //Handle des Programms NULL //Zusätzliche Daten ); if( !myWnd ) returnValue = FALSE; else { myAppWnd = myWnd; //Fenster nazeigen ShowWindow( myWnd, SW_SHOWNORMAL ); //WM_PAINT message an Fenster senden UpdateWindow( myWnd ); } return returnValue; } LRESULT CALLBACK WndProc( HWND myWnd, UINT givenMessage, WPARAM wParam, LPARAM lParam ) /* This function recieves the Messages, wich are given from MS-Windows to the program. So the program can do message specific actions, if this message is incoming. */ { PAINTSTRUCT myPaint; //Handle für Gerätekontext(gültiger Zeichenbereich) BOOL visitMsg = FALSE; static POINT myPoint, mousePointForPaint; static RECT myRect, parent; static COORD mouseKoord; HANDLE backUp; char version[50]; struct paintHist *akt; BYTE kBuff[255]; if( LOWORD(lParam) != 0 || HIWORD(lParam) != 0) { mouseKoord.X = LOWORD(lParam); //took the mouse-coordinates into a COORD variable (perfomance) mouseKoord.Y = HIWORD(lParam); } switch( givenMessage ) { case WM_CREATE: myPoint.x = -1; myPoint.y = -1; GetClientRect( myAppWnd, &parent ); bClose = CreateWindow( "BUTTON", "Close", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top, 50, 20, myWnd, (HMENU)CLOSE, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); bBlack = CreateWindow( "BUTTON", "black", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top+30, 50, 20, myWnd, (HMENU)cBLACK, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); bWhite = CreateWindow( "BUTTON", "white", SS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top+50, 50, 20, myWnd, (HMENU)cWHITE, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); strcpy( version, "Version: " ); strcat( version, VERSION ); versionWnd = CreateWindow( "STATIC", version, WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left+630, parent.bottom+555, 165, 20, myWnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); bSmall = CreateWindow( "BUTTON", " 1px", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top+75, 40, 22, myWnd, (HMENU)sSMALL, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); bMiddle = CreateWindow( "BUTTON", " 3px", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top+97, 40, 22, myWnd, (HMENU)sMIDDLE, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); bBig = CreateWindow( "BUTTON", " 5px", WS_CHILD | WS_VISIBLE | WS_DLGFRAME , parent.left, parent.top+119, 40, 22, myWnd, (HMENU)sBIG, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); visitMsg = TRUE; break; case WM_SIZE: myRect.left = 0; myRect.top = 0; myRect.bottom = HIWORD( lParam ); myRect.right = LOWORD( lParam ); visitMsg = TRUE; break; case WM_PAINT: myHdc = BeginPaint( myWnd, &myPaint ); //open device-context (paintplace) { backUp = SelectObject( myHdc, *aktPen ); akt = first; while( NULL != akt->next ) { if( akt->isBreak != TRUE ) { DeleteObject( aktPen ); *aktPen = CreatePen( PS_SOLID, akt->width, RGB( akt->cRed, akt->cYellow, akt->cBlue ) ); SelectObject( myHdc, *aktPen ); MoveToEx( myHdc, //Zeichenfläche akt->pointToPaint.x, //X-Koordinate akt->pointToPaint.y, //Y-Koordinate NULL //old-Koordinate ); LineTo( myHdc, //Zeichenfläche akt->next->pointToPaint.x, //X-Koordinate akt->next->pointToPaint.y //Y-Koordinate ); } akt = akt->next; } SelectObject( myHdc, backUp ); } EndPaint( myWnd, &myPaint ); visitMsg = TRUE; break; case WM_MOUSEMOVE: myHdc = GetDC( myWnd ); //open device-context (paintplace) { if( wParam == MK_LBUTTON ) { if( myPoint.x != -1 ) { myPoint.x = mouseKoord.X; //set new coordinates myPoint.y = mouseKoord.Y; akt = last; if( NULL == first->next ) { akt = first; akt->pointToPaint.x = myPoint.x; akt->pointToPaint.y = myPoint.y; akt->cRed = R; akt->cYellow = G; akt->cBlue = B; akt->width = aktWidth; akt->isBreak = FALSE; akt->next = NULL; last = akt; } if( NULL != ( akt->next = malloc( sizeof( struct paintHist ) ) ) ) { if( last->isBreak != TRUE ) { backUp = SelectObject( myHdc, *aktPen ); MoveToEx( myHdc, //Zeichenfläche last->pointToPaint.x, //X-Koordinate last->pointToPaint.y, //Y-Koordinate NULL //old-Koordinate ); LineTo( myHdc, //Zeichenfläche myPoint.x, //X-Koordinate myPoint.y //Y-Koordinate ); SelectObject( myHdc, backUp ); } akt = akt->next; akt->pointToPaint.x = myPoint.x; akt->pointToPaint.y = myPoint.y; akt->cRed = R; akt->cYellow = G; akt->cBlue = B; akt->width = aktWidth; akt->isBreak = FALSE; akt->next = NULL; last = akt; } //InvalidateRect( myWnd, NULL, TRUE); } else { myPoint.x = mouseKoord.X;//The first coordinates myPoint.y = mouseKoord.Y; } } visitMsg = TRUE; } ReleaseDC( myWnd, myHdc ); break; case WM_LBUTTONUP: akt = last; if( NULL != ( akt->next = malloc( sizeof( struct paintHist ) ) ) ) { akt = akt->next; akt->pointToPaint.x = myPoint.x; akt->pointToPaint.y = myPoint.y; akt->cRed = R; akt->cYellow = G; akt->cBlue = B; akt->width = aktWidth; akt->next = NULL; akt->isBreak = TRUE; last = akt; } myPoint.y = -1; myPoint.x = -1; visitMsg = TRUE; break; case WM_RBUTTONDOWN: DeleteObject( whitePen ); DeleteObject( blackPen ); setGlobalVars(); InvalidateRect( myWnd, NULL, TRUE ); visitMsg = TRUE; break; case WM_COMMAND: switch( LOWORD(wParam) ) { case CLOSE: SendMessage( myAppWnd, WM_DESTROY, 0, 0 ); visitMsg = TRUE; break; case cWHITE: aktPen = &whitePen;//slect white pen R = 255; G = 255; B = 255; visitMsg = TRUE; break; case cBLACK: aktPen = &blackPen;//slect white pen R = 0; G = 0; B = 0; visitMsg = TRUE; break; case sSMALL: DeleteObject( aktPen ); aktWidth = 1; *aktPen = CreatePen( PS_SOLID, aktWidth, RGB( R, G, B ) ); visitMsg = TRUE; break; case sMIDDLE: DeleteObject( aktPen ); aktWidth = 3; *aktPen = CreatePen( PS_SOLID, aktWidth, RGB( R, G, B ) ); visitMsg = TRUE; break; case sBIG: DeleteObject( aktPen ); aktWidth = 5; *aktPen = CreatePen( PS_SOLID, aktWidth, RGB( R, G, B ) ); visitMsg = TRUE; break; default: ; break; } break; case WM_KEYDOWN: GetKeyboardState( kBuff ); //get virtual keys if( kBuff[VK_CONTROL]&0x80 && kBuff['Z']&0x80 ) //STRG + Z { akt = first; if( akt->next != NULL ) { while( NULL != akt->next->next ) akt = akt->next; if( akt->next != NULL ) { free( akt->next ); akt->next = NULL; last = akt; akt->isBreak = TRUE; } } } InvalidateRect( myWnd, NULL, TRUE ); visitMsg = TRUE; break; case WM_DESTROY: ShowWindow( myConsole, SW_SHOWNOACTIVATE ); //SendMessage( myConsole, WM_CLOSE, 0, 0 ); PostQuitMessage( 0 ); break; default: break; } if( visitMsg ) return 0; else return DefWindowProc( myWnd, givenMessage, wParam, lParam ); }