Wie am besten grafische Oberfläche umsetzen?



  • Ich plane in meinem Programm eine grafische Oberfläche für den Benutzer einzubauen (ist vielleicht ein schlechter Begriff - mir fällt kein besserer ein). Das soll eine Fläche werden (die ungefähr so aussehen soll, wie ein leeres List-View oder Tree-View Control, also so als ob es ein wenig tiefer liegen würde als der Des Fensters. Innerhalb dieser Fläche werden dann Rechtecke erzeugt, die der User herumschieben und anwählen sollen kann.

    Mir ist klar, dass ich dazu die GDI benutzen muss. Allerdings weiß ich nicht genau, wie ich das ganze handhaben soll. Ich könnte natürlich ganz brachial per GDI mit einigen Rechtecken den Hintergrund zeichnen und dann auch die verschiebbaren kleineren Rechtecke so anlegen, und mit einer Klasse im Hintergrund alles verwalten.
    Nun habe ich aber in einigen Online-Tutorials immer wieder gesehen, dass für solche oder ähnliche Zwecke die Leute gerne ihre eigenen Controls schreiben. Mir ist noch völlig unklar, wie das geht, ich würde mich dann aber in das Thema einlesen können.

    Die Frage ist: Lohnt sich das denn überhaupt in diesem Fall? Wenn ja, wie mache ich sowas? Wenn nein, was mache ich stattdessen?

    Mit eigenen Controls habe ich noch keine Erfahrung und ich weiß auch ehrlich gesagt noch nicht so richtig, was hinter den Kulissen in den vorgefertigten Controls vor sich geht, wenn man sie mit Messages oder Makros anspricht, und das ist hier denke ich mal ein wenig hinderlich. Also bin ich über jede Hilfe froh.



  • Naja ... also ich würde dein komplettes Control in nen eigenes Fenster packen ^^ Und die Rechtecke darin dann einfach nur Zeichnen und aufn Userinput verschieben ... für jedes Rechteck kannst du natürlich auch nen eigenes HWND nehmen ... allerdings geht das nicht so gut von wegen nicht rechteckige Form usw da du da schnell mit Regions usw arbeiten musst .(



  • Wenn mit "eigenes Fenster" ein komplettes sich öffnendes Fenster gemeint ist, dann bin ich dagegen. Wenn damit gemeint ist, in einem schon bestehenden Fenster irgendwie diese neue Oberfläche abzugrenzen, dann würde ich gerne wissen, wie das geht. 😃

    Aber trotz allem klärt deine Antwort ja die Frage nicht, ob ich ein Control dazu schreiben sollte, oder nicht, und wenn, wie. 😉



  • Ja ein Control ist ncihts anderes als ein "Child-Window". Und das ist auch nur ein Fenster mit dem WS_CHILD Flag gesetz 😉 Und damit ist es deinem Fenster untergeordnet.



  • Sniffman schrieb:

    [...]ob ich ein Control dazu schreiben sollte, oder nicht, und wenn, wie. 😉

    google.de, Codeproject.com, koders.com, Forumsuche, FAQ ...



  • Und wie erreiche ich die Organisation als besagtes Child-Window? Sollte ich mir einfach ein paar Tutorials zum Thema "Creating Custom Controls" anschauen?

    Mir war merkwürdigerweise noch nicht direkt klar, dass Controls auch ganz normale Windows sind. Wenn dem so ist, dann sollte ich aber eine ungefähre Ahnung haben, was hier zu tun ist.



  • Sniffman schrieb:

    Und wie erreiche ich die Organisation als besagtes Child-Window?

    ➡

    (D)Evil schrieb:

    Und das ist auch nur ein Fenster mit dem WS_CHILD Flag gesetz 😉 Und damit ist es deinem Fenster untergeordnet.

    Sniffman schrieb:

    Sollte ich mir einfach ein paar Tutorials zum Thema "Creating Custom Controls" anschauen?

    Joar, anscheind sinnvoll. Allerdings ist das mit den Child-Windows elementar.

    Sniffman schrieb:

    Mir war merkwürdigerweise noch nicht direkt klar, dass Controls auch ganz normale Windows sind.

    So ist es aber 😉 .

    Sniffman schrieb:

    Wenn dem so ist, dann sollte ich aber eine ungefähre Ahnung haben, was hier zu tun ist.

    👍



  • Ach, Mist. Ich habe mir jetzt nach diesem Tutorial eine Custom Control erstellt, die Klasse wird dann auch in der DllMain erfolgreich registriert, aber wenn ich den Dialog öffnen will, in dem dann diese Control eingebaut ist, dann ist das zurückgegebene HWND immer NULL und das Fenster wird nicht erzeugt.

    Hier ein paar Codeschnipsel:

    BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved)
    {
    	// Register event view class
    	WNDCLASSEX wc;
    	wc.cbSize         = sizeof(wc);
    	wc.lpszClassName  = _T("EventViewCtrl");
    	wc.hInstance      = GetModuleHandle(NULL);
    	wc.lpfnWndProc    = EventView::EventViewProc;
    	wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
    	wc.hIcon          = 0;
    	wc.lpszMenuName   = 0;
    	wc.hbrBackground  = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
    	wc.style          = 0;
    	wc.cbClsExtra     = 0;
    	wc.cbWndExtra     = sizeof(EventView*);
    	wc.hIconSm        = 0;
    	ATOM returned = RegisterClassEx(&wc);
    	if (returned != NULL)
    		MessageBox(NULL, "EventViewCtrl registered!", "Debug", MB_OK);
    }
    
    LRESULT CALLBACK EventView::EventViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    	// retrieve the custom structure POINTER for THIS window
    	EventView *view = (EventView *)GetWindowLong(hwnd, 0);
    
    	MessageBox(NULL, "EventViewProc called!", "Debug", MB_OK);
    
    	switch (msg)
    	{
    		case WM_NCCREATE:
    			view = new EventView(hwnd);
    			SetWindowLong(hwnd, 0, (LONG)view);
    			return true/*(view != NULL)*/;
    
    		case WM_NCDESTROY:
    			delete view;
    		break;
    	}
    
    	return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    
    HWND hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MAIN), ip->GetMAXHWnd(), MainDlgProc);
    	if (hwnd == NULL)
    		MessageBox(NULL, "hwnd == NULL", "Debug", MB_OK); //immer NULL
    	ShowWindow(hwnd, SW_SHOW);
    	UpdateWindow(hwnd);
    

    Kennt jemand typische Fehler, die man hier als Anfänger hätte machen können? Oder geht aus dem Code was als falsch hervor?



  • Was fürn Müll 😃 Hmm und dll main ist auch außergewöhnlich ... um es so zu sagen ^^

    bool register_my_control()
    {
        // Register event view class
        WNDCLASSEX wc;
        ZeroMemory(&wc, sizeof(WNDCLASSEX));
        wc.cbSize         = sizeof(wc);
        wc.lpszClassName  = _T("EventViewCtrl");
        wc.hInstance      = GetModuleHandle(NULL);
        wc.lpfnWndProc    = EventViewProc;
        wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wc.hIcon          = NULL;
        wc.lpszMenuName   = NULL;
        wc.hbrBackground  = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
        wc.style          = 0;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hIconSm        = 0;
    
        return (RegisterClassEx(&wc) != 0);
    }
    

    ... und dann mit CreateWindow das Control in WM_CREATE bzw WM_INITDIALOG erstellen. Das in Klassen zu packen ist auch leicht allerdings machst du da was falsch 😃



  • Ich fände es ganz dufte, wenn du noch die Güte hättest, mir zu sagen, was ich falsch mache.

    Also: Ob ich das Ding jetzt direkt in DllMain ausführe, oder dazu eine Funktion anlege, ist doch egal, oder? Außerdem kann ich nicht einfach die Klassenangabe der Window Procedure weglassen, weil die nunmal Teil einer Klasse ist. Ich habe nämlich alles den Anweisungen oben genannten Tutorials zufolge in eine Klasse getan. Ob das jetzt "Müll" ist oder nicht, darüber habe ich erstmal kein Urteil gefällt, sondern das erstmal umgesetzt.

    Und das ganze Zeigerrumgemache in der Window Procedure, wegen der auch über wc.cbWndExtra extra Platz reserviert wurde, ist laut des Tutorials dazu da, dass bei jedem Ausführen der Window Procedure auch genau feststeht, welches Fenster gemeint ist. Das macht auf den ersten Blick auch erstmal Sinn so. War das vielleicht derjenige Teil, den du "Müll" nanntest?

    Aber ansonsten kann ich da jetzt im Vergleich zu deinem Code keine großen Unterschiede feststellen, bis auf oben angesprochenes. Aber das hat halt irgendwie auch seine Begründung, wenn man dem Tutorial glaubt. Und das sah durchaus seriös aus.

    Bitte um Aufklärung.



  • Achja, es kann sein, dass es hier ein Missverständnis gibt, weil ich vergessen habe zu erwähnen, dass das Custom Control als Resource vorhanden ist und also automatisch erzeugt werden müsste, wenn der Dialog geöffnet wird. Daher brauche ich auch ein CreateWindow mehr auszuführen.



  • Na gut, neuer Anlauf. Ich habe mal die Custom Control aus den Resourcen ausgebaut und lasse ihn jetzt stattdessen mit CreateWindowEx über WM_INITDIALOG erstellen.

    case WM_INITDIALOG:
    	{HWND hwnd_new = CreateWindowEx(WS_EX_CLIENTEDGE, _T("EventViewCtrl"), _T("Event View"), WS_VISIBLE | WS_CHILD, 11, 409, 527, 287, hwnd, NULL, hInstance, NULL);
    	if (hwnd_new == NULL)
    		MessageBox(NULL, "hwnd_new == NULL", "Debug", MB_OK);}
    

    Jetzt wird zwar der Rest des Dialogs wieder erzeugt, aber nach wie vor taucht die neue Control nicht im geringsten auf. Außerdem erscheint die MessageBox, die einen fehlenden Window Handle nach der Erzeugung angibt. Da das Ding ja den extended Style CLIENTEDGE hat, müsste ich zumindest den Rahmen sehen, oder? Aber da ist nichts. Um alle Fehler bei der Window Procedure auszuschließen, habe ich diese darauf beschränkt, eine MessageBox zu erstellen, wenn sie aufgerufen wird, und TRUE zurückzugeben. Sonst wird da nichts getan. Die Registrierung der Klasse funktioniert nach wie vor wie weiter vorne angegeben, allerdings habe ich die Window Procedure mal vorläufig aus der Klasse rausgeholt. Der Aufruf zur Erzeugung des Windows stimmt so: Wenn ich damit ein List-View Control erstellen will, geht das einwandfrei.

    Mir ist aufgefallen, dass die Window Procedure nie aufgerufen wird (die Box erscheint nie), aber das müsste sie doch mindestens einmal bei der Erzeugung der Klasse, oder nicht? Könnte da der Fehler liegen?

    Vielleicht wird es ja jetzt für jemanden hier ersichtlich, wo der Fehler liegen könnte, oder was ich noch hinzufügen müsste.



  • Anstat der MessageBox guck mal was GetLastError sagt!

    MfG schirrmie



  • Das hatte Error 0 ausgegeben und sich dann freundlich aufgehängt.

    Es lag aber dran, dass ich in der Definition der WCLASSEX eine andere Instance angegeben hatte.


Log in to reply