przyciski w MessageBox WinApi

0

Witam, szukałem wiele na ten temat i nie znalazłem odpowiedzi więc pytam tu. Czy jest jakaś możliwość modyfikacji rozmiaru i rozmieszczenia przycisków "ok", "anuluj" itp w MessageBox'ie ? Wiem że można wybrać rodzaj przycisku, ustawiać flagi itp ale chciałbym zmienić rozmiar przycisków. Czy ktoś wie jak coś takiego zrobić? Z góry dziękuję za pomoc.

0

Najlepiej będzie w takim przypadku stworzyć własne okno.

0

No rozumiem, też o tym czytałem lecz to spowoduje iż będę musiał przerobić inne części programu. Czy mógłbyś powiedzieć chodź gdzie szukać, albo czego ? Sam nie znalazłem nic co by zmieniało tylko wymiary przycisków.

0

Może ten artykuł jakoś cię naprowadzi...

Rev napisał(a):

Najlepiej będzie w takim przypadku stworzyć własne okno.

Bieluus napisał(a):

No rozumiem, też o tym czytałem lecz to spowoduje iż będę musiał przerobić inne części programu.

Niekoniecznie. Możesz przecież zdefiniować własną funkcję MessageBox o parametrach identycznych, jak oryginalna. Inne części programu nawet nie zauważą zmiany.

0

Nie można zmieniać rozmiaru przycisków wyświetlanych przez MessageBox().

Ale od Visty w górę jest bardzo fajne okienko zwane "task dialog":

#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#include <Windows.h>
#include <CommCtrl.h>

int main()
{
	TASKDIALOGCONFIG tdc = {0};
	tdc.cbSize = sizeof(tdc);
	tdc.hwndParent = GetConsoleWindow();
	tdc.hInstance = GetModuleHandle(NULL);
	tdc.dwFlags = TDF_SIZE_TO_CONTENT | TDF_USE_COMMAND_LINKS;
	tdc.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON;
	tdc.pszWindowTitle = L"Pytanie";
	tdc.pszMainIcon = TD_INFORMATION_ICON;
	tdc.pszMainInstruction = L"Lorem ipsum";
	tdc.pszContent = L"dolor sit amet";
	tdc.cButtons = 3;
	TASKDIALOG_BUTTON przyciski[] =
	{
		{100,L"Chcę to"},
		{101, L"Chcę tamto"},
		{102, L"Nie wiem czego chcę"}
	};
	tdc.pButtons = przyciski;
	// dużo innych pól do zabawy, patrz dokumentacja

	int result;
	TaskDialogIndirect(&tdc, &result, NULL, NULL);
}
0

Dziękuje bardzo za odpowiedzi, ten task dialog wydaje się najlepszym rozwiązaniem.

0

O ile dobrze zrozumiałem chodzi Tobie o coś takiego jak poniżej. Kod znalazłem kiedyś na google i dostosowałem nieco do swoich potrzeb. Może są inne metody, ale ta jest skuteczna. Fragmenty kodu pochodzą z mojej aplikacji pisanej wyłacznie w WinAPI. Zmienna MainDialogHandle to uchwyt głownego okna aplikacji. Pod VCL powinieneś zastapić to za pewne AktywnaFormatka.Handle lub Appliaction.Handle. Natomiast zmiennej ActiveWindowHandle użyłem w kodzie po to gdyż mam poza oknem głownym jeszcze dodatkowe okienko dialogowe. Jeżeli chodzi o funkcję obsługi komunikatów to możesz ją przypisać do okna formatki, tak jak przypisuje ją ja dla okienka MessageBox, co widać w kodzie poniżej. Oczywiście kod podmienia etykiety przycisków aby zawsze były po angielsku, tak jak GUI całego mojego programu. Ale mając uchwyt okna dialogowego nie problem już zmieniać jego rozmiary czy rozmieszczenie elementów, posiłkując się innym funkcjami WinAPI opisanymi na MSDNie. Co do obsługi klawisza Escape w modyfikowanym dialogu to musiałem go obsłuzyć w taki sposób, bo inaczej okienko w porównaniu do standardowego mi nie reagowało.

//...
const
  WM_CHANGEMSGBOX = WM_USER + 2012;
//...
var
    PNewMsgBoxProc, POldMsgBoxProc : Pointer;
//...
function MsgBoxProc(AHWnd : HWND; Msg : UINT; AWParam : WParam; ALParam : LParam) : LResult; stdcall;
var
  EscapePressed : boolean;
begin
  EscapePressed := GetAsyncKeyState(VK_ESCAPE) shr ((SizeOf(SHORT) * 8) - 1) <> 0;
  if EscapePressed then
  begin
    EndDialog(AHWnd, 0);
  end;
  Result := CallWindowProc(POldMsgBoxProc, AHwnd, Msg, AWParam, ALParam);
end;

function MsgBox(AHWnd : HWND; Text, Title : string; UType : UINT) : integer;
begin
  PostMessage(MainDialogHandle, WM_CHANGEMSGBOX, 0, 0);
  Result := MessageBox(AHWnd, PChar(Text), PChar(Title), UType);
end;

function MainDlgProc(AHWnd : HWND; Msg : UINT; AWParam : WParam; ALParam : LParam) : BOOL; stdcall;
begin
  Result := False;
  if Msg = WM_CHANGEMSGBOX then
  begin
    H := FindWindow(WC_DIALOG, nil);
    if GetParent(H) = ActiveWindowHandle then
    begin
      PNewMsgBoxProc := @MsgBoxProc;
      POldMsgBoxProc := Pointer(SetWindowLong(H, GWL_WNDPROC, Integer(PNewMsgBoxProc)));
      SetDlgItemText(H, IDTRYAGAIN, '&Try again');
      SetDlgItemText(H, IDCONTINUE, 'Contin&ue');
      SetDlgItemText(H, ID_CANCEL, '&Cancel');
      SetDlgItemText(H, ID_RETRY, '&Retry');
      SetDlgItemText(H, IDIGNORE, '&Ignore');
      SetDlgItemText(H, IDABORT, '&Abort');
      SetDlgItemText(H, ID_HELP, '&Help');
      SetDlgItemText(H, ID_YES, '&Yes');
      SetDlgItemText(H, ID_NO, '&No');
    end;
  end;
  case Msg of
    WM_INITDIALOG :
      begin
        ActiveWindowHandle := AHWnd;
      end;
      //...

Przykład użycia - jak standardowego okienka:

begin
  if MsgBox(ActiveWindowHandle, 'Exit from program, are you sure?' + #13#10 +
    'You can disable this confirmation in application settings.', App_Title,
    MB_ICONQUESTION + MB_YESNO + MB_DEFBUTTON1) = IDNO then
  begin
    //...
  end;
0

Mam jeszcze jedno pytanie. MessageBox potrzebuje flagi która odpowiada za to jakie przyciski wybrałem itp ale zwraca ta flaga wartość int. Czy jest jakiś sposób aby rozpoznać w tym int'cie jakich przycisków uzyłem? NP: otrzymam 10 - i skad windows wie że chce przykładowo tak, nie i anuluj ?

0

A czytałeś kiedykolwiek jakąkolwiek dokumentację tej funkcji? Jasno jest w nich napisane o flagach, ich wartościach oraz o wartościach zwracanych przez tą funkcję; Wszelkie stałe są w module Windows;

Ilość i tym przycisków:

MB_OK:               0
MB_OKCANCEL:         1
MB_ABORTRETRYIGNORE: 2
MB_YESNOCANCEL:      3
MB_YESNO:            4
MB_RETRYCANCEL:      5
MB_HELP:             16384

Wartości zwracane przez tą funkcję (czyli wartość stałej, jaka reprezentuje dany przycisk):

IDOK:       1
IDCANCEL:   2
IDABORT:    3
IDRETRY:    4
IDIGNORE:   5
IDYES:      6
IDNO:       7
IDTRYAGAIN: 10
IDCONTINUE: 11

Więcej dowiesz się w tym artykule oraz na MSDN;

0

Tak, czytałem dokumentację :) źle mnie zrozumiałeś, nie chodzi mi o to jaki przycisk został wciśnięty, tylko jakie przyciski mają się pokazać na oknie. Chodzi o to że tą flagę mam w bardzo wielu miejscach w programie, i chciałbym dalej ją interpretować we własnym oknie. Oczywiście mogę szukać te wszystkie miejsca w których "tworzę" tą flagę, aczkolwiek wolałbym tego uniknąć.

Dokładniej: Jeżeli tworzę okno z MB_OK i MB_ABORTRETRYIGNORE to w jaki sposób windows wie że akurat chcę te 4 przyciski a nie jakieś inne? Funkcja zwraca wartość int wiec w tym przypadku 2.

0

Nie bardzo rozumiem, funkcja i Windows "wiedzą to", bo przekazałeś im to jako paramatr, a dalej wszystko ogarnia kod, który jest w systemowych bibliotekach. To tak jakbyś pytał skąd jakaś funkcja Sumuj(3, 2); ma Tobie zwrócić 5. Po prostu za to odpowiada jej kod. Chyba, że nie o to pytasz :/

0
Bieluus napisał(a)

Dokładniej: Jeżeli tworzę okno z MB_OK i MB_ABORTRETRYIGNORE to w jaki sposób windows wie że akurat chcę te 4 przyciski a nie jakieś inne?

A skąd ja mam wiedzieć skąd Windows wie?

Czy Tobie chodzi o to w jaki sposób zostaje rozpoznany typ przycisków i według przekazanej wartości zostały uwidocznione tylko wybrane przyciski? Od tego jest argument uTypes: Cardinal - do niego pakuje się różne flagi, które potem pewnie przez przesunięcie bitowe i koniunkcję zostają wydobyte z liczby i sprawdzone w bloku warunkowym/wyboru; Przynajmniej tak ja to widzę - w ten sposób tworzę własne okna dialogowe oraz wykorzystuję taką metodę w innych rzeczach, dzięki czemu w jednej liczbie można zapisać kilka różnych informacji, które potem można bardzo łątwo wypakować;

Jeśli chcesz wiedzieć dokładnie jak jest to zaimplementowane to przepatrz źródła - być może znajdziesz definicję funkcji MessageBox;

0
Bieluus napisał(a):

Dokładniej: Jeżeli tworzę okno z MB_OK i MB_ABORTRETRYIGNORE to w jaki sposób windows wie że akurat chcę te 4 przyciski a nie jakieś inne? Funkcja zwraca wartość int wiec w tym przypadku 2.

Poczytaj o maskach bitowych, o ile dobrze zrozumiałem o co Tobie chodzi.

Const Flaga1 = 1;
Flaga2 = 2;
Flaga3 = 4;
Flaga4 = 8;
Flaga5 = 16;
Flaga6 = 32;
// i tak dalej
{...}
Var Flagi: LongWord;
Begin
 Flagi := Flaga4 or Flaga6 {...};
 {...}
 if (Flagi and Flaga5) = Flaga5 Then
 Begin
  Flaga5 włączona;
 End;
End;
0

Tak, właśnie o to mi chodzi skąd np: sumuj(3,2) wie że ma być 5. No nic myślałem że coś takiego da się zrobić, dziękuję za pomoc :)

0

Poczytam o tych przesunięciach bitowych o których mówił Furious Programming i może dam radę. Jest to dla mnie nowa rzecz ("ingerowanie w funkcje" WinApi) więc pewnie będzie to robione metodą prób i błędów aczkolwiek mam nadzieję ze za którymś razem się uda.

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