WIN API DrawLine, einfach ansteuern?



  • Hallo,
    ich habe das Problem, dass mir keine einfache Möglichkeit einfällt eine Linie zu zeichnen und gleichzeitig Struktur im Code zu erhalten.
    Entweder ich zeichne in WM_PAINT, dann jedoch, weiß ich nicht wie ich die Positionen für diese Linien sinnvoll wieder zu dieser Stelle Trasportiere, da der eigentliche code ja schließlich in

    while (GetMessage(&msg, NULL, 0, 0))
    {}
    

    stattfinden soll, wo nur eine Funktion aufgerufen werden soll, um etwas Ordnung zu schaffen.
    Was jedoch schwierig ist, wenn man in WM_PAINT zeichnen will.

    Zeichne ich außerhalb von WM_PAINT, lässt sich sich die Funktionen viel leichter ansteuern, jedoch fehlt mir dann eine gewisse Kontinuität des zeichnen sowie die message aus

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

    ,da die main Funktion schließlich nur einmal in der loop ausgeführt wird.

    Mag sich einer von euch niederlassen und mir grob erklären, wie man sowas strukturiert. Entweder alles ist super unübersichtlich oder verbuggt, Ich will doch nur eine blöde Linie ziehen und die Tatstatur auslesen können.



  • Keine Ahnung was du willst, aber ich vermute, dir fehlen eh komplett sinnvolle Abstraktionen und Codestrukturen, wenn du solche Fragen stellst.



  • wie kommst du darauf, dass der eigentliche code in der WinMain ausgeführt werden soll?



  • also ganz primitiv:

    #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("Aufgäbe 1");
    	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(0, IDI_APPLICATION);
    	wndclass.hCursor = LoadCursor(0, IDC_HAND);
    	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	wndclass.lpszMenuName = 0;
    	wndclass.lpszClassName = szAppName;
    	
    
    	if (!RegisterClass(&wndclass))
    	{
    		MessageBox(0, TEXT("Fehler!"), szAppName, MB_ICONERROR);
    		return 0;
    	}
    
    	hwnd = CreateWindow(szAppName, TEXT("Aufgabe 1"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0);
    
    	ShowWindow(hwnd, iCmdShow);
    	UpdateWindow(hwnd);
    
    	while (GetMessage(&msg, 0, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
            static POINT linepoints[4];
    	HDC hdc;
    	PAINTSTRUCT ps;
    	RECT rect;	
    
    	switch (message) 
    	{
    	case WM_CREATE:
    //linie von (10; 10) nach (20; 20) festlegen
                    linepoints[0].x = 10;
                    linepoints[0].y = 10;
                    linepoints[1].x = 20;
                    linepoints[1].y = 20;
    
    //linie von (30; 30) nach (40; 40) festlegen
                    linepoints[2].x = 30;
                    linepoints[2].y = 30;
                    linepoints[3].x = 40;
                    linepoints[3].y = 40;
    
    		return 0;
    	case WM_PAINT:
    		hdc = BeginPaint(hwnd, &ps);
    
    //linie von (10; 10) nach (20; 20) zeichnen
                    MoveToEx(hdc, linepoints[0], NULL);
                    LineTo(hdc, linepoints[1]);
    
    //linie von (30; 30) nach (40; 40) zeichnen
                    MoveToEx(hdc, linepoints[2], NULL);
                    LineTo(hdc, linepoints[3]);
    
    		EndPaint(hwnd, &ps);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }
    


  • Wo schreibt das denn rein?

    Wie ich eine Linie zeichne ist mir schon klar, aber ich kann auf die Funktion ja nicht außerhalb zu greifen.



  • naja in den device-context (hdc)

    WM_PAINT wird immer aufgerufen, wenn du
    a) InvalidateRect oder
    b) InvalidateRgn oder
    c) UpdateWindow aufruft oder
    d) die größe des fensters änderst oder
    e) das fenster nach dem minimieren wieder anzeigen lässt.

    aber du kannst den device-context auch mittels GetDC(hwnd) abrufen und dann aus der WinMain direkt zeichnen.



  • @Yue sagte in WIN API DrawLine, einfach ansteuern?:

    Wie ich eine Linie zeichne ist mir schon klar, aber ich kann auf die Funktion ja nicht außerhalb zu greifen.

    Ich weiß immer noch nicht, was du genau willst (warum willst du von außerhalb darauf zugreifen?), aber ich würde mal vermuten, du brauchst irgendwelche Datenstrukturen, die den Status deines Programms abbilden. Woher weißt du irgendwo, dass du irgendwelche Linien zeichnen willst? Nehmen wir mal an, du willst eine Art Chart-Control umsetzen, das Liniendiagramme zeichnet. Dann braucht das einen Zustand, irgendwelche Daten. z.B. eine Liste von Linienkoordinaten (oder meinetwegen erstmal eine Linie). Im WM_PAINT Eventhandler wird es dann gezeichnet. Von außerhalb wird der Zustand geändert. z.B. du weiß igendwo (sagen wir, Mausklick), dass du die Linie woanders zeichnen willst. Dann rufst du was auf, um den Zustand zu aktualisieren, der beim nächsten mal gezeichnet wird. Dann evtl. noch InvalidateRect, um gleich neuzeichnen zu lassen.



  • Ich habe es bisher immer so gemacht, dass ich den hwnd einer Funktion übergeben habe, welche in eine andere andere cpp führt, in der dann der hdc als globale variable vorliegt, sodass ich durch eine simple Funktion mit 4 Parametern eine Linie ziehen kann.

    Was auch sehr gut funktioniert, bis auf ein paar Macken, mit der Ausnahme, dass ich so nicht auf die message zugreifen kann, um die Tastatur auszulesen, da mein Zeugs idealerweise in gelinkter cpp schleife läuft, damit ich Listen etc. speichern kann, ohne diese jedesmal als return in die while (GetMessage(&msg, 0, 0, 0)) schleife zurückzugeben.

    Wenn ich in WM_PAINT zeichne muss ich doch jedes mal meine Liste aus der Main des Programms zurück nach WM_PAINT bringen, sodass meine main Funktion in gelinkter cpp nicht schleife laufen, kann wodurch ich bei jedem Durchgang den Datensatz neu einlesen und auswerten müsste.

    Ich verstehe nicht, wie ich die zu zeichnenden Punkte, ohne großen Mehraufwand und Umstände übergeben soll.



  • @Yue sagte in WIN API DrawLine, einfach ansteuern?:

    Wenn ich in WM_PAINT zeichne muss ich doch jedes mal meine Liste aus der Main des Programms zurück nach WM_PAINT bringen

    Nein... Du musst etwas über Programmdesign usw. lernen. Ist kein einfaches Thema und da gehören normalerweise Jahre Erfahrung dazu.
    Aber ich würde dir auf jeden Fall schon mal raten aufzuhören, in solchen Kategorien zu denken, und etwas Struktur in dein Programm bringen 😉



  • @Mechanics Woher weiß der denn, was er zeichnen muss? Das wirft mehr Fragen auf, als es beantwortet 😃



  • Wie ich geschrieben habe, brauchst du Datenstrukturen, die dein "Datenmodell" abbilden. Das ist auch kein schlechtes Stichwort, das kommt recht häufig vor. Man versucht grundsätzlich möglichst die Logik von der Darstellung zu trennen. Irgendwas mit globalen Variablen, Nachrichten, Main usw... hört sich ziemlich verkehrt an.
    Du solltest versuchen, dein Programm in sinnvolle Komponenten zu gliedern und zu kapseln.
    Da du eine Linie zeichnen willst, würde ich dafür auch ein entsprechendes Objekt definieren. Das gehört evtl. (bzw. wahrscheinlich) in ein weiteres Objekt rein, sowas wie DOM, SceneGraph, Chart oder was für deine Anwendung eben Sinn macht.
    Dann könntest du eine Komponente wie xyzVizalizer oder wie auch immer haben, die Zugriff auf die Daten hat und weiß, wie die darzustellen sind. An der Stelle sollte man eigentlich auch weiter abstrahieren, aber es kommt dann drauf an... WinAPI ist eigentlich nicht so zukunftsfähig. Sehr unwahrscheinlich, dass irgendein ernsthaftes Programm direkt auf der WinApi aufbauen würde. Wenn man das z.B. mit Qt macht, hätte das mit großer Wahrscheinlichkeit schon Einfluß auf die Designentscheidungen.
    Jedenfalls sieht man hier schon einen Vorteil - es ist erstmal egal, wie die Linie (und hoffentlich gehört da noch mehr dazu, als nur eine Linie) gezeichnet wird. Ob das WinApi ist, oder Qt, GTK, Web, Konsole, whatever... Es ändert sich nur eine Komponente, die Daten (und später Logik) sind davon nicht betroffen. Deswegen sollte man nie anfangen, sowas höchst spezielles wie Windows Nachrichten als etwas zentrales in seinem Programm zu betrachten.



  • @Yue sagte in WIN API DrawLine, einfach ansteuern?:

    Wo schreibt das denn rein?

    Wie ich eine Linie zeichne ist mir schon klar, aber ich kann auf die Funktion ja nicht außerhalb zu greifen.

    Auf welche Funktion willst Du denn zugreifen?
    Du kannst doch mittelbar in WM_PAINT zeichnen, indem Du eine Funktion zum Zeichnen aufrufst, und der das Device Handle weiterreichst ...


Log in to reply