Okienko dialogowe wygląda źle, zachowuje się jeszcze gorzej

0

W Resources utworzyłam nowe okienko dialogowe, IDD_REPAIR_JDN - załącznik epbrsc.jpg.
Jednak pojawia mi się jakaś kupa - załącznik epberr.jpg.

Oto mój kod:

LRESULT CALLBACK PodajJednostkeDialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (uMsg) 
	{
		case WM_INITDIALOG:
			{
				CenterWindow(hWnd);
				return 0;
			}
		case WM_COMMAND:
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			// Parse the menu selections:
			switch (wmId)
			{
				case IDOK:
					EndDialog( hWnd, TRUE );
					DestroyWindow(hWnd);
					return TRUE;
					break;
				case IDCANCEL:
					DestroyWindow(hWnd);
					break;
				default:
					return DefWindowProc(hWnd, uMsg, wParam, lParam);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}
char napis[256];
std::string buff;
MSG msg;
int bRet;

sprintf(napis, "Pobrana struktura aktu prawnego: %s jest najprawdopdobniej błędna.\n\nPodaj jednostkę dla:", idAktu);
HWND okno_repair = CreateDialog(_Module.m_hInst, MAKEINTRESOURCE (IDD_REPAIR_JDN), NULL, (DLGPROC) PodajJednostkeDialogProc);
if (okno_repair != NULL)
{
	SetDlgItemText(okno_repair, IDC_TEKST, napis);
	SetDlgItemText(okno_repair, IDC_POM, pom);
											
	ShowWindow(okno_repair, SW_SHOW);
	SetForegroundWindow(okno_repair);
	UpdateWindow(okno_repair);

	while ( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 ) 
	{ 
		if (bRet == -1)
		{
			break;
		}
		else if (!IsWindow(okno_repair) || !IsDialogMessage(okno_repair, &msg)) 
		{ 
			HWND okno_jdn = GetDlgItem(okno_repair, IDC_JDN);
			buff = GetWindowText(okno_jdn);
													
			TranslateMessage(&msg); 
			DispatchMessage(&msg); 
		}
	}
	DestroyWindow(okno_repair);
}
if (buff != "")
{
	strcpy(cel, buff.c_str());
	blad = false;	
}

Generalnie to w ogóle nie chce dobrze działać, muszę robić coś karygodnie źle, tylko nie wiem co... Wygląda jak wygląda, to pierwsza sprawa, której totalnie nie kumam - po bokach prześwitują programy z pod spodu... Druga sprawa jest taka, że okienka nie da się przesunąć, zmienić rozmiaru. To przesuwanie to szczególnie mnie zastanawia - przecież to bardzo podstawowa, standardowa rzecz.
Oczywiście nie działa też pobieranie danych z pola tekstowego - to co tu widać to już jest szczyt mojej kombinatoryki, bo inne sposoby też nie działały. Co by nie było - w buff zawsze jest "". Jedyne co działa to guzik Cancel.

EDIT:
No i jestem w szoku, bo chyba jednak pobieranie tekstu działa oO Bardzo mnie to cieszy, ale okienko wciąż wygląda i zachowuje się dziwnie.

0

Ok, beznadziejny wygląd powodowało DefWindowProc - usunięcie wywołań tej funkcji poprawiło sytuację znacznie.

Teraz bardzo bym chciała wiedzieć, czy użytkownik kliknął OK czy Anuluj. Już mi koledzy powiedzieli, że w WinApi ładnie tego nie zrobię. Przykłady z msdna sugerują użycie zmiennych globalnych... Oto kod, który napisałam:

else if (!IsWindow(okno_repair) || !IsDialogMessage(okno_repair, &msg)) 
{
	int wmId, wmEvent;
	HWND okno_jdn;
	if (msg.message == WM_COMMAND)
	{
		wmId = LOWORD(msg.wParam); 
		wmEvent = HIWORD(msg.wParam); 
		// Parse the menu selections:
		switch (wmId)
		{
			case IDOK:
				okno_jdn = GetDlgItem(okno_repair, IDC_JDN);
				buff = GetWindowText(okno_jdn);
				break;
			case IDCANCEL:
				buff = "";
				break;
		}
	}
	TranslateMessage(&msg);
	DispatchMessage(&msg); 
}

Funkcja PodajJednostkeDialogProc praktycznie bez zmian (wywalona wyżej wspomniana funkcja).
Tak, dobrze widzicie, chcę obsłużyć część komunikatów w pętli przetwarzania. Jak ktoś ma lepszy pomysł, to ja bardzo poproszę.
Tak czy siak - no to nie działa dobrze. Niezależnie do tego, co kliknę, w msg.message jest 18 (czyli WM_QUIT). W wParam zawsze 0.
W funkcji PodajJednostkeDialogProc wpada w dobre case'y.

Zaczynam nienawidzić WinApi, zaraz wezmę się wkurzę i cały projekt przepiszę na coś bardziej do ludzi. Chyba że coś podpowiecie :]

1

Wszystko robisz nie tak jak trzeba. W pętli komunikatów obsługującej dialog z zasobów powinno być wywołanie funkcji EndDialog:

  • z parameterem IDCANCEL dla WM_DESTROY/WM_CLOSE (będzie to sytuacja gdy użytkownik zamknie okno)
  • z parametrem IDOK gdy użytkownik kliknie OK - w pętli komunikatów będzie to WM_COMMAND i LOWORD(wParam) takie jaki masz ID przycisku OK w twoim oknie
  • analogicznie IDCANCEL gdy użytkownik kliknie ANuluj

Ogólnie, najwygodniej zrobić switcha na LOWORD(wParam) pod case'em WM_COMMAND - mozesz wtedy wygodnie obsługiwać zdarzenia od wszystkich kontrolek: LOWORD(wParam) to będzie wartość int taka, jaki masz ustawiony ID kontrolki w zasobach.

Zakładam, że ten dialog ma byc modalny - musisz więc utworzyć dialog za pomocą funkcji DialogBox. Funkcja ta utworzy modalne okno dialogowe, jako parametr podajesz ID lub nazwę okna znajdującego się w zasobach. Funkcja zakończy się, gdy okno modalne zostanie zamknięte przez wywołanie EndDialog i zwróci ci wartość taką, jaka była podana w EndDialog - w ten sposób odróżnisz, czy uzytkownik kliknął OK, czy ANuluj. Oczywiście trzeba pamiętać, że wywołanie EndDialog zniszczy okno, więc jeśli chcesz jakieś dane z tego okna przekazać do okna głównego, to należy to zrobić przez wywołaniem EndDialog - można uzyć zmiennych globalnych, ale są bardziej eleganckie sposoby (znajdziesz na msdn)

Zajrzyj zresztą tutaj: http://msdn.microsoft.com/en-us/library/ms644996%28v=vs.85%29.aspx#modal_box

0

Zakładam, że ten dialog ma byc modalny

Źle zakładasz. Robię niemodalny na podstawie: http://msdn.microsoft.com/en-us/library/ms644996(VS.85).aspx#modeless_box
Dialog tworzę przez CreateDialog, a nie DialogBox.
Z resztą i w przykładzie który podałeś, nie jest używane EndDialog. No nie mówcie, że z niemodalnego okienka nie da się zwrotu pobrać...

Oczywiście trzeba pamiętać, że wywołanie EndDialog zniszczy okno, więc jeśli chcesz jakieś dane z tego okna przekazać do okna głównego, to należy to zrobić przez wywołaniem EndDialog - można uzyć zmiennych globalnych, ale są bardziej eleganckie sposoby (znajdziesz na msdn)

Właśnie tych elegantszych sposobów to nie znalazłam. W linku, który podałeś i na którym się opierałam tworząc powyższy kod są zmienne globalne. Tak robić NIE BĘDĘ.

Choć wiem, że to co zrobiłam to też jakaś pokraka :P
Kod z pierwszego posta działa - zwraca mi zawartość IDC_JDN do buff. Z tymże teraz ja chcę ten tekst pobrać tylko gdy LOWORD(msg.wParam) == IDOK, a gdy LOWORD(msg.wParam) == IDCANCEL chcę buff wyzerować. Dodanie warunku jak w drugim poście nie pomaga, bo nigdy nie jest prawdą.

1

A dlaczego chcesz niemodalne okno? Skoro jest to komunikat w którym musisz coś potwierdzić (Ok, Anuluj) to powinien być raczej modalny.

Z resztą i w przykładzie który podałeś, nie jest używane EndDialog. No nie mówcie, że z niemodalnego okienka nie da się zwrotu pobrać...

Z okna niemodalnego możesz pobierać co chcesz, przez cały czas gdy okno istnieje. Wystarczy ci jego uchwyt. Problem się zaczyna, gdy chcesz wykryć kiedy takie okno zostało zamknięte. Nie wykryjesz tego z poziomu parenta tego okna. Najlepiej będzie jak wywołasz jakąś funkcję w reakcji na naciśnięcie OK/Anuluj tuz przed zniszczeniem okna i w niej umieścisz odpowiednie operacje do wykonania. EndDialog ma zastosowanie tylko przy oknach modalnych.

Ogólnie, radzę zrobić okno modalne jednak.

[edit]
Tak sobie pomyślałem jeszcze, że można by wysłać jakiś komunikat do okna głównego przed zamknięciem dialogu niemodalnego. W taki sposób można by było wykryć kiedy użytkownik zamknął to okno i czy kliknął OK, czy anuluj. W komunikacie tym mogą być też inne potrzebne informacje - to wyeliminuje konieczność stosowania zmiennych globalnych. To chyba będzie najbardziej elegancki sposób.
Chyba że taki komunikat już i tak jest przesyłany do okna głównego - tego nie pamiętam, poszperaj na msdn.

0

Wielkie dzięki za wskazówki, faktycznie modalne okienko było tu lepszym wyborem :)
Działający kod:

LRESULT CALLBACK PodajJednostkeDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
	case WM_INITDIALOG:
			SetDlgItemText(hwndDlg, IDC_TEKST, jdnNapis);
			SetDlgItemText(hwndDlg, IDC_POM, jdnPom);
			return TRUE;
        case WM_COMMAND: 
            switch (LOWORD(wParam)) 
            { 
                case IDOK: 
                    if (!GetDlgItemText(hwndDlg, IDC_JDN, szJdn, 80)) 
                         *szJdn = 0; 
                    // Fall through. 
 
                case IDCANCEL: 
                    EndDialog(hwndDlg, LOWORD(wParam)); 
                    return TRUE; 
            } 
    } 
    return FALSE; 
} 
INT_PTR okno_repair = DialogBox(_Module.m_hInst, MAKEINTRESOURCE (IDD_REPAIR_JDN),  NULL, (DLGPROC) PodajJednostkeDialogProc);
	
if (okno_repair == IDOK)
{
	buff = szJdn;
}
else
{
	buff = "";
}

if (buff != "")
{
	strcpy(cel, buff.c_str());
	blad = false;	
}

Teraz jeszcze tylko pozbyć się tych paskudnych zmiennych globalnych i bedzię git ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1