C++ WinAPI Fenster nach Knopfdruck neu zeichnen

i!i!i!i!i!i!i!i

Cadet 2nd Year
Registriert
Dez. 2008
Beiträge
23
Hallo,
Ich habe jetzt mit der WinAPI angefangen komme aber nicht weiter, wenn ich einen Knopf drücke. Da soll nämlich das ganze Fenster neu gezeuchnet werden und nicht nur irgendeine MessageBox soll erscheinen.
Hier mal aus dem Code:
Code:
hwndButton3 = CreateWindow ( "button", "Test", 
                                   WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
                                   200, 200, 100, 40, hwnd, (HMENU)4, 
                                   (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL);

    //DIESER KNOPF LÖST IN            case WM_COMMAND:  das aus:
                     case WM_COMMAND: 

         if(LOWORD(wParam) == 4) 
   {    

  MessageBox(hwnd,"BlaBla","Message...",0); 
          

            break; 
                   }
Das ist schön und gut, aber ich will, dass das Fenster auf dem der Knopf selber ist, neu gezeichnet wird; also neue Buttons drauf sind, neuer Text usw.

Ich habe das schön mit einer If schleife Versucht:
Code:
int ZustandDesFensters = 0;

if( ZustandDesFensters = 0)
{

hwndButton3 = CreateWindow ( "button", "Test", 
                                   WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
                                   200, 200, 100, 40, hwnd, (HMENU)4, 
                                   (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL);

}

if( ZustandDesFensters = 1)
{

hwndButton3 = CreateWindow ( "button", "anderer Zustand", 
                                   WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
                                   4200, 300, 1000, 440, hwnd, (HMENU)4, 
                                   (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL);

}

                     case WM_COMMAND: 

         if(LOWORD(wParam) == 4) 
   {    

  MessageBox(hwnd,"Zustand geändert!","Message...",0); 
          ZustandDesFensters = 1;

            break; 
                   }
Das funktioniert allerdings nicht, der Zustand ändert sich gar nicht, wenn ich den Kopf drücke; es bleibt einfach so.

Ich benutze DevC++...

Ich hoffe ich habe mein Problem verständlich erklärt; wenn ihr mehr Code braucht sagt das. Ich wollte aber nur das reinbrígnen, worum es geht, weil den Rest habe ich verstanden, nur eben dieses neu zeichnen nicht...

Ich freue mich auf Hilfe.

MfG

P.S. ich kann c++ schon ganz gut, nur in der WinAPI bin ich ein n00b ;)
 
hi,

wenn du die Position von child-controls verändern willst, benutze einfach MoveWindow().
Den Text kannst du mit SetWindowText() ändern. Wenn dir das nicht zu sagt, kannst du die alten controls mit DestroyWindow() löschen und dann dem entsprechend neu controls erstellen. Wenn noch was unklar ist, zeig einfach mal deine code.

PS: statt GetWindowLong (hwnd, GWL_HINSTANCE) kannst du auch GetModuleHandle(0) verwenden - oder noch besser: benutz eine globale Variable die zu Beginn deines Prog. befüllt wird.
 
Hallo,
Danke für deine Hilfe, das läuft wie geschmiert!

Jetzt brauch ich nur noch etwas, was mir das Hauptfenster größer macht.

Code:
    hwnd = CreateWindowEx (0, szClassName, szClassName, 
           WS_POPUPWINDOW,
           cxScreen/3, 
           cyScreen/3,
           501,400,HWND_DESKTOP, 
           NULL,hThisInstance,NULL);
Damit erstell ich mein Popupwindow was sich automatisch in die Bilschirmmitte setzt.

Aber wie vergrößere ich es auf Knopfdruck?
Ach ja; Ich habe es inzwischen hinbekommen ein BMP bild auf das fenster zu zeichnen, kann ich das auch per Knopfdruck wechseln?

MfG und danke für die Hilfe! hat mir sehr weitergeholfen!
 
i!i!i!i!i!i!i!i schrieb:
Hallo,
Aber wie vergrößere ich es auf Knopfdruck?
Zum ändern der größe kannst du ebenfalls MoveWindow() verwenden. Die Koordinaten sind dann halt relativ zur Bildschirmecke links oben.

i!i!i!i!i!i!i!i schrieb:
Hallo,
Ach ja; Ich habe es inzwischen hinbekommen ein BMP bild auf das fenster zu zeichnen, kann ich das auch per Knopfdruck wechseln?

Ich nehem mal an das du die BMP bei der verabeitung von WM_PAINT zeichnest. In diesem fall würde ich empfehlen die Bildquelle (Datei, Resource oder wie auch immer du das machst) variabel zu machen, d.h. du kannst z.B. den Dateinamen/pfad ändern. Wenn also der button gedrückt wird, änderst du die Quell und veranlästt dein Fenster sich neu zu zeichnen (z.B. mit UpdateWindow()).
 
Hallo,
Ich habe mal ein wenig damit herumgebastelt.
Danke für deine Hilfe, vieles funktioniert jetz schon sehr gut!

Nur folgende Sachen verstehe ich noch nicht:
Woey schrieb:
Den Text kannst du mit SetWindowText() ändern.
Wie das? Ich habe in der msdn nachgeschaut werde daraus aber nicht schlau.
Momentan mach ich das mit dem Text so (und das BitmapBild):

Code:
       case WM_PAINT: 
         hdc = BeginPaint (hwnd, &ps) ; 
         hdcMem = CreateCompatibleDC (hdc) ; 
         SelectObject (hdcMem, hBitMap) ; 
         BitBlt (hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight,  
                                    hdcMem, 0, 0, SRCCOPY) ; 
       
       SetTextColor(hdc, RGB(255,255,255) ); 
       SetBkColor(hdc, RGB(139,69,19) );                         
                                    
         TextOut (hdc, 340, 380, "BlaBla mein Text", 16);
   
         
         
         DeleteDC (hdcMem) ; 
         EndPaint (hwnd, &ps) ;         
         return 0 ;

Und noch was: Ich hätte gerne ein Icon für das Prog. Die .exe hat im explorer ein Icon (das funktioniert), aber nicht in der Taskleiste wenn es gestartet ist, da is das windows standard icon.

Aber das mit dem Text ist jetzt erst mal wichtiger.

Danke für deine Hilfe soweit!
 
hi,

"Wie das? Ich habe in der msdn nachgeschaut werde daraus aber nicht schlau.
Momentan mach ich das mit dem Text so (und das BitmapBild):.."
Wenn das funktioniert ist es ja gut ;)
SetWindowText ist dazu da den Text von Controls/Fenstern zu ändern. Bei einem normalen Fenster änderst du damit den Fenstertitel , bei einem button den button-text("caption")....

"Ich hätte gerne ein Icon für das Prog.."
-> WNDCLASSEX.hIcon und WNDCLASSEX.hIconSm mit dem Rückgabewert von LoadIcon() befüllen.
 
Das mit dem Icon geht, danke.


Aber das mit dem Text....?

Wenn ich einen Knopf drücke soll statt
Code:
 TextOut (hdc, 340, 380, "BlaBla mein Text", 16);
was anderes dastehen. z.B
Code:
 TextOut (hdc, 360, 140, "So gehts weiter", 15);
Ich habe auch das wieder per if schleife und UpdateWindow probiert, was aber nicht funktioniert.

Woey schrieb:
Wenn das funktioniert ist es ja gut
Das ich zumindest text zeichnen kann, der überhaupt dasteht freut mich schon, aber ändern wäre jetzt auch mal ganz toll...

Muss ich diese Änderung in WM_PAINT: oder in WM_COMMAND: beschreiben?

Ich glaube ich habe als Problem in meiner Gedankenführung, dass ich es in WM_COMMAND: beschreiben will, da es ja durch einen Knopf ausgeführt werden soll, es aber in der WinAPI immer in WM_PAINT beschrieben werden muss....?

Wie du sicher gemerkt hast blicke ich beim Text gar nicht mehr durch ;) Im Dos-Fenster war das wesentlich einfacher...

Wie zeige ich denn eigentlich Variablen an, wenn ich z.B. die Bildschirmauflösung ermittelt habe?

Code:
int bildschirmaufloesungX = 1024;
TextOut (hdc, 10, 10, "X-Auflösung:"bildschirmaufloesungX, 12);
geht nicht...

Ich hoffe du kannst meiner Flutwelle an Fragen Herr werden ;)

MfG und danke für deine Hilfe
 
i!i!i!i!i!i!i!i schrieb:
Ich habe auch das wieder per if schleife und UpdateWindow probiert, was aber nicht funktioniert.

sorry, hab leider etwas Misst erzählt :eek: : Um das client area (teilweise oder ganz) neu zu zeichnen, muss man den entsprechenden Bereich ungültig machen -> InvalidateRect() oder InvalidateRgn().

Hab mal schnell noch ein kleines Beispielprogramm geschrieben, das die ganze Sache etwas verständlicher macht:
Code:
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#include <time.h>

HINSTANCE hInst;
HWND hWin;
HWND Btn[3];
int iCurrentText=0; // index in szArray

// unicode-strings
TCHAR szTitle[] = L"bla bla";			
TCHAR szWindowClass[] = L"MainClass";
TCHAR szArray[3][32]={L"Text_1",L"Text_2",L"Text_3"};

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

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
	WNDCLASSEX wcex;
	MSG msg;

	hInst = GetModuleHandle(NULL);

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInst;
	wcex.hIcon			= 0;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= 0;
	RegisterClassEx(&wcex);

	hWin = CreateWindow(szWindowClass,szTitle,WS_SYSMENU,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

	ShowWindow(hWin, nCmdShow);
    UpdateWindow(hWin);

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

	return (int) msg.wParam;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	RECT rect;
	DWORD color;
	TCHAR buffer[256];

	switch (message)
	{
	case WM_CREATE:
		srand ((unsigned int)time(NULL)); // Zufallsgenerator initialisieren
		Btn[0] = CreateWindow(L"button",L"Button_1",WS_CHILD+WS_VISIBLE,0,0,100,20,hWnd,0,hInst,0);
		Btn[1] = CreateWindow(L"button",L"Button_2",WS_CHILD+WS_VISIBLE,101,0,100,20,hWnd,0,hInst,0);
		Btn[2] = CreateWindow(L"button",L"Button_3",WS_CHILD+WS_VISIBLE,202,0,100,20,hWnd,0,hInst,0);

		break;
	case WM_COMMAND:
		if ((HWND)lParam == Btn[0])
		{	iCurrentText = 0;
		}
		else if ((HWND)lParam == Btn[1])
		{	iCurrentText = 1;
		}
		else if ((HWND)lParam == Btn[2])
		{   iCurrentText = 2;
		}
		InvalidateRect(hWnd,NULL,TRUE); // "client area" neu zeichnen -> msdn
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		color = (0xff << (rand()%3)*8); // zufällig: rot,grün oder blau
		SetTextColor(hdc,(COLORREF) color);

		TextOut(hdc,10,30,szArray[iCurrentText],wcslen(szArray[iCurrentText]));
		
		// gib den aktuelle Farbwert aus: 
		wsprintf(buffer,L"Farbwert:\n\tHex:\t\t0x%X\n\tDezimal:\t%i",color,color);	// -> msdn 		
		rect.top = 50;
		rect.left = 10;
		rect.bottom = 100;
		rect.right = 300;
		DrawText(hdc,buffer,wcslen(buffer),&rect,DT_WORDBREAK|DT_EXPANDTABS|DT_TABSTOP|(0x400)); // 0x400 == 4 Zeichen pro tabstop -> msdn

		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

hab dafür die C++ 2008 Express Edition benutzt: Win32-Projekt -> Option "Leeres Projekt" -> Quelldatei hinzufügen -> Str+C ;)

EDIT: -> http://msdn.microsoft.com/en-us/library/ms534858(VS.85).aspx
 
Zuletzt bearbeitet:
Hallo,
Danke das mit dem Text läuft gut und ne Scrollbar habe ich auch hinbekommen.

Allerdings habe ich noch Probleme mit verschiedenen Bitmaps:
Wenn ich einen Knopf drücke, sollen andere Knöpfe erscheinen und das Hintergrundbild geändert werden.
Die Knöpfe funktionieren, aber das Bild bleibt gleich, obwohl ich das Fenster neu zeichnen lasse.
Hier mein Code:
Code:
.
.
.
static HBITMAP      hBitMap, hBitMap_2, hBitMap_3; // Verschiedene Bitmaps

  int wich_picture = 1; 
  
    switch (message)                  
    {    
        case WM_CREATE: 
          hBitMap = (HBITMAP)LoadImage(0,"1.bmp",IMAGE_BITMAP, 0, 0, 
                 LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_CREATEDIBSECTION);  
                 
          hBitMap_3 = (HBITMAP)LoadImage(0,"2.bmp",IMAGE_BITMAP, 0, 0,
                 LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_CREATEDIBSECTION); 


			//Buttons....
                        //Command:

		 case WM_COMMAND: 
		.
		.
		.
                                         //// Bild Tauschen
                                        wich_picture = 3;
                                         
                                         /////Buttons Weg
                                          MoveWindow( hwndButton10, 4800, 100, 100, 40, TRUE );
                                          MoveWindow( hwndButton11, 4800, 100, 100, 40, TRUE );
                                          MoveWindow( hwndButton12, 4800, 100, 100, 40, TRUE );
                                          MoveWindow( hwndButton13, 4800, 100, 100, 40, TRUE );
                                        
                                          
                        //FENSTER NEU ZEICHNEN
                        InvalidateRect(hwnd, NULL, TRUE);
...

       case WM_PAINT: 

            
         hdc = BeginPaint (hwnd, &ps) ; 
         
         ///WELCHES BILD:
         if (wich_picture == 1) ////Bild 1
         {
         hdcMem = CreateCompatibleDC (hdc) ; 
         SelectObject (hdcMem, hBitMap );
         
                      
                     cxScreen = GetSystemMetrics(SM_CXSCREEN); 
                     cyScreen = GetSystemMetrics(SM_CYSCREEN); 
               
          
         StretchBlt (hdc, cxScreen/5.5, cyScreen/5.5, 800, 600,                        
                                    hdcMem, 0, 0, 800, 600, SRCCOPY) ; 
         }  //ENDE DER Bild1-Schleife
         
                  if (wich_picture == 3) ////Bild2-Schleife
         {
         hdcMem = CreateCompatibleDC (hdc) ; 
         SelectObject (hdcMem, hBitMap_3 );
         
                      
                     cxScreen = GetSystemMetrics(SM_CXSCREEN); 
                     cyScreen = GetSystemMetrics(SM_CYSCREEN); 
               
          
         StretchBlt (hdc, cxScreen/5.5, cyScreen/5.5, 800, 600,                        
                                    hdcMem, 0, 0, 800, 600, SRCCOPY) ; 
         }  //ENDE DER Bild2-Schleife

Wie geht es richtig?

Grüße

i!i!i!i!i!i!i!i
 
Ich verfolge den Thread schon von Anfang an (und ich verstehe nichts von dem Quelltext).
Dabei frage ich mich die ganze Zeit schon warum man sich denn noch diese alte WinAPI antut?
Bitte nicht böse sein, aber eine gewisse masochistische Ader muss man da schon haben.
Es gibt Unmengen von moderneren GUI-Toolkits.
Wenn ich mir Quellcode mit WinAPI anschaue sehe ich irgendwie fast nur GROSSBUCHSTABEN, hwnd, lpr und sonst noch seltsame Präfixe bei allen möglichen Identifiern (Ungarische Notation).

Ignoriert meinen Beitrag. Der ist mir aus den Fingern geflutscht, bevor ich nachgedacht habe :).
 
Vermute mahl, das es nicht klappt, da du den DC (hdcMem) nicht mit DeleteDC() löscht. Aus der Dokumentation geht hervor, dass eine Bitmap immer nur in einem DC residieren kann - d.h. SelectObject() funktioniert nur beim ersten Mal für die entsprechende Bitmap. Nicht nur aus diesem Grund solltest du Objekte löschen, sobald sie nicht mehr gebraucht werden.

Eine zusätzliche Fehlermöglichkeit währen die X und Y Parameter bei StrechBlt(hdc,x,y..). Wenn das Fenster sehr klein ist und dein Bildschirm sehr groß ist, wird dein Bild eventuell außer halb des clientarea gezeichnet (die Koordinaten sind hier relativ zum Clientarea, nicht zum Bildschirm).
---

Die Buttons mit MoveWindow() ins Nirgendwo zu verschieben funktioniert zwar, ist aber nicht die konventionelle Art: -> ShowWindow(hWnd, SW_HIDE / SW_SHOW).

hier nochmals ein kleines Beispielprog.:
Code:
#include <windows.h>

HINSTANCE hInst;
HWND hWin;

HWND Btn[3];
HANDLE hBmp[3];
int iCurrBmp=0;

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

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
	WNDCLASSEX wcex;
	MSG msg;
	hInst = GetModuleHandle(NULL);
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInst;
	wcex.hIcon			= 0;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= "BmpWin";
	wcex.hIconSm		= 0;
	RegisterClassEx(&wcex);
	hWin = CreateWindow("BmpWin","Was wieß ich",WS_SYSMENU,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
	ShowWindow(hWin, nCmdShow);
	UpdateWindow(hWin);
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	HANDLE hTmpDC;

	switch (message)
	{
	case WM_CREATE:
		Btn[0] = CreateWindow("button","Bild 1",WS_CHILD+WS_VISIBLE,0,0,100,20,hWnd,0,hInst,0);
		Btn[1] = CreateWindow("button","Bild 2",WS_CHILD+WS_VISIBLE,101,0,100,20,hWnd,0,hInst,0);
		Btn[2] = CreateWindow("button","Bild 3",WS_CHILD+WS_VISIBLE,202,0,100,20,hWnd,0,hInst,0);

		hBmp[0] = LoadImage(0,"1.bmp",IMAGE_BITMAP, 0, 0,LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_CREATEDIBSECTION);
		hBmp[1] = LoadImage(0,"2.bmp",IMAGE_BITMAP, 0, 0,LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_CREATEDIBSECTION);
		hBmp[2] = LoadImage(0,"3.bmp",IMAGE_BITMAP, 0, 0,LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_CREATEDIBSECTION);

		ShowWindow(Btn[0],SW_HIDE);	// konvetionelle Methode um Controls aus zu blenden
		break;
	case WM_COMMAND:
		ShowWindow(Btn[iCurrBmp],SW_SHOW);	// einbelenden
		if ((HWND)lParam == Btn[0])
		{	iCurrBmp = 0;
		}
		else if ((HWND)lParam == Btn[1])
		{	iCurrBmp = 1;
		}
		else if ((HWND)lParam == Btn[2])
		{	iCurrBmp = 2;
		}
		ShowWindow(Btn[iCurrBmp],SW_HIDE);	// button für aktuelle bmp ausblenden
		InvalidateRect(hWnd,NULL,TRUE);
		break;
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);

		hTmpDC=CreateCompatibleDC(hdc);
		SelectObject(hTmpDC,hBmp[iCurrBmp]);
		StretchBlt (hdc,40,40, 800, 600,hTmpDC, 0, 0, 800, 600, SRCCOPY);
		DeleteDC(hTmpDC);	// nicht Vergesen !!

		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

EDIT: Nicht nur für Anfänger sehr nützlich: win32.hlp
Vista-Nutzer müssen noch ein kleines Update Aufspielen um *.hlp-Datein öffnen zu können: http://www.microsoft.com/downloads/...FamilyID=6ebcfad9-d3f5-4365-8070-334cd175d4bb
 
Zuletzt bearbeitet:
Hallo,
Man muss das
Code:
HANDLE hTmpDC;
in deinem Code durch
Code:
HDC hTmpDC;
ersetzen; dann funktioniert es.

Vielen Dank für deine Hilfe! Hat mir alles sehr weitergeholfen!


MfG
 
Zurück
Oben