Zugriff auf eine Listbox vom Child-Dialogfenster aus
-
Hallo,
in einem mit Hilfe der CreateDialog()-Funktion erzeugten Dialogfenster (nenn ich mal "parent") habe ich eine Listbox erstellt. Wenn ich ein Element in die Listbox vom diesem parent-Dialogfenster aus einfügen möchte, dann kann ich das mit folgender Zeile problemlos machen:HWND hProfileList = GetDlgItem(hWndDlg, IDC_PROFILELIST); //hWndDlg ist in dem Fall das "parent"-Dialogfenster ... SendMessage(hProfileList, LB_INSERTSTRING, NULL, (LPARAM)TEXT("text"));Da ich mit Ressourcen arbeite, greife ich auf die Listbox über die ID "IDC_PROFILELIST". Nun so weit, so gut. Nach einem Button-Klick innerhalb des "parent"-Fensters wird ein modales Dialogfenster ("child") über DialogBox() erzeugt. Meine Frage ist: Wie kann ich denn Informationen aus dem zuletzt erzeugten Child-Dialogfenster in die Listbox innerhalb des "parent"-Dialogs einfügen?
Was ich bisher probiert habe://Prozess-Funktion des "child"-Dialogfensters LRESULT CALLBACK AddNewProfileProc (HWND hWndDlgNew, UINT Msg, WPARAM wParam, LPARAM lParam) { ... case WM_COMMAND: { ... case IDOK: { //1. Variante: Zugriff auf die Listbox über das Handle zum [i]parent window [/i] HWND hProfileList = GetDlgItem(GetParent(hChildWndDlg), IDC_PROFILELIST); ... SendMessage(hProfileList, LB_INSERTSTRING, NULL, (LPARAM)TEXT("text")); //2. Variante: Zugriff direkt über das Handle der Listbox SendMessage((HWND)IDC_PROFILELIST, LB_INSERTSTRING, NULL, (LPARAM)TEXT("text")); //3. Variante wäre FindWindowEx, aber das würde ich nicht so gerne benutzen, da // es bestimmt einen einfacheren Weg gibt. } break; } break; ...Alles leider erfolglos. Ich geh stark davon aus, dass dieser Schritt eine häufige WinAPI-Methode ist und jemand bestimmt, weiß wie das geht.
Danke.
-
ich würde es so machen (von der logik her):
wenn in deinem child-window der ok button geklickt wird
dann die daten des childs (deine "child-membervariablen") ans parent übergeben.da deine edit/list ja ebenfalls im parent sitzt kannst dort
die daten bequem einfügen (so wie du es bisher ja auch machst).lg
-
a4 schrieb:
dann die daten des childs (deine "child-membervariablen") ans parent übergeben.
Hört sich sehr gut an, aber das ist genau das, was ich nicht hinbekomme. Könntest du mir einen Hinweis/Stichpunkt geben?
-
Meiner Meinung nach müßte Variante 1 funktionieren
Statt: "GetDlgItem()" u "SendMessage()" kannst Du gleich "SendDlgItemMessage()" verwenden ;). Variante 2 kann nicht funktionieren, da Du die ID nicht als HWND casten kannst. Sonst bräuchte ja man nie "GetDlgIem()". Wenn Variante 1 nicht funktioniert, kannst Du noch einen globalen String anlegen, der entweder statisch oder dynamisch allokiert wird. Wenn die Child-Dialog-Funktion endet, setzt Du einfach den globalen String in die List-Box ein; beim nächsten Aufruf überschreibst Du ihn einfach wieder.
-
Danke, Exhumed, aber aus irgendeinem Grund funktioniert die erste Methode nicht. Das Problem mit dem Anlegen eines Strings ist, dass ich neben dem Einfügen in die Listbox noch andere Operationen (wie z.B. Deaktivieren von Buttons) an der Stelle ausführen möchte. Und das mit Strings zu machen, wäre meiner Meinung nach nicht so geschickt. Muss ich vielleicht alle Fenster registriert haben? Vielleicht sollte ich den ganzen Code (ca. 300 zeilen) posten...
Ich habe gerade eben einen Weg gefunden, wie ich das Problem lösen könnte - und zwar indem ich die Handles der Controls (buttons, listbox) im Parent-Fenster, auf die das Child-Fenster zugreifen soll, als globale Variable deklariere. Aber verliert mein Programm bzw. Code dadurch nicht an Sicherheit? Globale Variable sind ja für alle Funktionen (eben global) zugänglich... Oder sollte ich dabei was anderes beachten?
VG,
Rew.
-
Statt der globalen Variable könntest du auch DialogBoxParam verwenden.
Es funktioniert genau wie DialogBox, über einen zusätzlichen Parameter kann der Box bspw. das Handle des parents oder ein Zeiger auf eine komplexe Struktur übergeben werden.
Die DialogProc des Childs kann im WM_INITDIALOG-Zweig darauf zugreifen (LPARAM) und sich das Handle oder den Zeiger lokal speichern.
Aber ich bin auch der Meinung, dass Variante 1 funktionieren müßte. Poste doch mal den Code des Aufrufs von DialogBox. Als parent übergibst du doch das Handle des Dialoges, oder?
-
Ok, hier ist der Code. Ich habe unten die Stelle fett markiert, an der das Ganze scheitert. Bei mir gibt es weder Kompilierungs-, noch Runtime-Fehler.
#define STRICT //Für eine erweiterte Überwachung des Programms auf Fehler #define WIN32_LEAN_AND_MEAN //Weist den Compiler an, unnötige Header auszulassen #include "main.h" #include "resource.h" HINSTANCE hInst; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK DlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK AddNewProfProc (HWND hWndDlgNew, UINT Msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hI, HINSTANCE hPrI, PSTR szCmdLine, int iCmdShow) { char szName[] = "MainClass"; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; // CS = "class style" wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hI; wc.hIcon = LoadIcon (NULL, IDI_WINLOGO); wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)CreateSolidBrush (RGB(240, 240, 240));// (HBRUSH) GetStockObject (LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szName; RegisterClass (&wc); HWND hWnd = CreateWindow ( szName, "OptSync v0.01", WS_SYSMENU | WS_MINIMIZEBOX | WS_CAPTION, 400, 300, 500, 280, NULL, NULL, hI, NULL); if (!hWnd) { MessageBox(NULL, "Call to CreateWindow failed!", "Internal error.", NULL); return 1; } hInst = hI; //assign a value to the global variable hInst so that other functions have access to the instance ShowWindow (hWnd, iCmdShow); UpdateWindow (hWnd); // Message loop MSG msg; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam; } LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; HWND hMainWindow = NULL; switch (message) { case WM_PAINT: { hdc = BeginPaint (hWnd, &ps); //Change background color SelectObject(hdc, GetStockObject(DC_BRUSH)); SetDCBrushColor(hdc, RGB(255,0,0)); //Background color for the parent (main) window SetBkColor (hdc, RGB(232, 232, 232)); //Background color for child windows EndPaint (hWnd, &ps); } break; case WM_CREATE : { hMainWindow = CreateDialog(hInst, MAKEINTRESOURCE(IDR_MAINWINDOW), hWnd, (DLGPROC)DlgProc); //..., reinterpret_cast<DLGPROC>(DlgProc)); if(hMainWindow == NULL) //Check for creating error { MessageBox(hWnd, "CreateDialog returned NULL", "Warning!", MB_OK | MB_ICONINFORMATION); } } break; case WM_DESTROY: PostQuitMessage (0); break; } return DefWindowProc (hWnd, message, wParam, lParam); } LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND hProfileList = GetDlgItem(hWndDlg, IDC_PROFILELIST); HWND hNewProfileButton = GetDlgItem(hWndDlg, IDC_ADDPROFBUTTON); HWND hEditProfileButton = GetDlgItem(hWndDlg, IDC_EDITPROFBUTTON); HWND hDeleteProfileButton = GetDlgItem(hWndDlg, IDC_DELETEPROFBUTTON); HWND hSourcePathEdit = GetDlgItem(hWndDlg, IDC_MAINWSOURCE); switch(Msg) { case WM_INITDIALOG: { //Call function to READ FROM REGISTRY } break; case WM_COMMAND : { switch (LOWORD(wParam)) { //Click (or keyboard input) within the list box area case IDC_PROFILELIST: { //An element in the list box was clicked if (HIWORD(wParam) == LBN_SELCHANGE) //LBN_SELCHANGE ) { EnableWindow (hEditProfileButton, TRUE); EnableWindow (hDeleteProfileButton, TRUE); } } break; //IDC_PROFILELIST case IDC_ADDPROFBUTTON: { SendMessage(hProfileList, LB_INSERTSTRING, NULL, (LPARAM)TEXT("bbbbb")); DialogBox(hInst, MAKEINTRESOURCE(IDR_NEWPROFWINDOW), hWndDlg, (DLGPROC)AddNewProfProc); } break; case IDC_EDITPROFBUTTON: { DialogBox(hInst, MAKEINTRESOURCE(IDR_NEWPROFWINDOW), hWndDlg, (DLGPROC)AddNewProfProc); } break; case IDC_DELETEPROFBUTTON: { //SetWindowText(hSourcePathEdit, LPCSTR); //ProfSelection = SendMessage(hProfileList, LB_GETCURSEL, NULL, NULL); SendMessage(hProfileList, LB_DELETESTRING, SendMessage(hProfileList, LB_GETCURSEL, NULL, NULL), NULL); //Disable the profile editing buttons EnableWindow (hEditProfileButton, FALSE); EnableWindow (hDeleteProfileButton, FALSE); } break; case IDCANCEL: { PostQuitMessage (0); } break; }//END OF switch(LOWORD(wParam)) } break; //WM_COMMAND } //END OF switch(msg) return FALSE; } /////////////////////////////// // LRESULT CALLBACK AddNewProfProc (HWND hWndDlgNew, UINT Msg, WPARAM wParam, LPARAM lParam) { HWND hBrowseSourceP = GetDlgItem(hWndDlgNew, IDC_BROWSESOURCE); HWND hSourcePath = GetDlgItem(hWndDlgNew, IDC_NEWPROFWSOURCE); HWND hTargetPath = GetDlgItem(hWndDlgNew, IDC_NEWPROFWTARGET); //Handles for the controls in the parent window HWND hParentProfileList = GetDlgItem(hWndDlgNew, IDC_PROFILELIST); HWND hParentAddProfileButton = GetDlgItem(GetParent(hWndDlgNew), IDC_ADDPROFBUTTON); //Initialise the parameters for folder browsing LPITEMIDLIST pidl; TCHAR szPath[MAX_PATH * 2]; BROWSEINFO BI; ZeroMemory(&BI,sizeof(BROWSEINFO)); BI.hwndOwner = hWndDlgNew; BI.pidlRoot = NULL; BI.pszDisplayName = szPath; BI.lpszTitle = "Choose folder"; BI.ulFlags = NULL; BI.lpfn = NULL; switch(Msg) { case WM_INITDIALOG: { //TODO: Call function to READ THE PROFILES FROM AN ARRAY } break; case WM_COMMAND : { switch (LOWORD(wParam)) { case IDC_BROWSESOURCE: { //Source path selection /* ... */ } break; //IDC_NEWPROFWSOURCE case IDC_BROWSETARGET: { //Target path selection /* ... */ } break; //IDC_BROWSETARGET case IDOK: { //TODO: !! FIRST CHECK THE VALUES FOR VALIDATE !! S[b]endMessage(hParentProfileList, LB_INSERTSTRING, NULL, (LPARAM)TEXT("aaa")); //CHECK IF THE LIST IS FULL (9 profiles); if yes, then DEACTIVATE THE "New" button if (SendMessage(hParentProfileList, LB_GETCOUNT, NULL, NULL) >= 3) EnableWindow (hParentAddProfileButton, FALSE); [/b] EndDialog(hWndDlgNew, IDOK); } break; case IDCANCEL: { EndDialog(hWndDlgNew, IDCANCEL); } break; }//END OF switch(LOWORD(wParam)) } break; //WM_COMMAND } //END OF switch(msg) return FALSE; }
-
Wenn du die DialogProcs jeweils
INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam );so deklarieren würdest, wären die Casts unnötig.
Wenn du im WM_PAINT-Zweig schon einen neuen Scope definierst, können der erforderliche HDC und PAINTSTRCUCT auch erst dort deklariert werden.Einige Casts sind außerdem überflüssig (wie z.b. bei CreateSolidBrush).
Aber der Fehler liegt in AddNewProfProc:
// statt hParentProfileList = GetDlgItem(hWndDlgNew, IDC_PROFILELIST); // so hParentProfileList = GetDlgItem(GetParent(hWndDlgNew), IDC_PROFILELIST)Die BrowseInfo-Struktur benötigst du nur bei IDC_BROWSESOURCE/TARGET im WM_COMMAND-Zweig, warum führst du den Code bei jeder Nachricht aus?
Um Codeduplikate zu vermeiden, kannst du auch Folgendes machen:switch(LOWORD(wParam) { case IDC_BROWSESOURCE: case IDC_BROWSETARGET: { LPITEMIDLIST pidl; // restlicher Code // Fallunterscheidung bspw. BI.lpszTitle =LOWORD(wParam)==IDC_BROWSESOURCE?TEXT("choose source"):TEXT("choose target"); break; } }Generell gilt, Code nur auszuführen, wenn es nötig ist und in C++ Variablen erst so spät wie möglich zu definieren.
-
Danke für die Hinweise, Falke! Das mit dem fehlenden
GetParentwar ein Tippfehler. Es funktioniert auch dann nicht, wenn ichs korrigiere..
-
Setz' einmal Debug-Haltepunkte und schau dir die Werte der Handles an.
Was mich verwirren würde, ist die Namensgebung der Handles in deinen Funktionen. Ich schreibe bspw. immerINT_PTR DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);Das heißt, hwnd ist immer das Handle des Fensters in der Funktion. In deinem ersten Post das erste Beispiel:
HWND hProfileList = GetDlgItem(GetParent(hChildWndDlg), IDC_PROFILELIST);Was ist hChildWndDlg? Es müsste hWndDlgNew sein.
Bei immer gleicher Benennung wäre es einfachHWND hProfileList = GetDlgItem(GetParent(hwnd), IDC_PROFILELIST);Ich denke, so könnte man schon einige Fehler vermeiden.