Jak wstawić dowolną ikonę tj na MessageBox na Formę?

0

Witam.
czy jest jakiś sposób aby wstawić taką ikonę UINT uType z

MessageBox

na formę? Załóżmy że mam czystą formę i co dalej?
Jeśli tej nie da rady to może jakaś inna w zastępstwie.
Pozdrawiam

1

Można kombinować z CreateMessageDialog pod VCL i sobie tak jak tutaj podmieniam tę ikonę na aplikacji, pobrać ją przez Assign do jakiegoś innego TImage.

procedure TMainForm.ShowMsgDlgButtonClick(Sender: TObject);
var
  Dlg : TForm;
  CBX : TCheckBox;
begin
  Dlg := CreateMessageDialog('Czy na pewno chcesz zamknąć program?',
  mtConfirmation, [mbYes, mbNo]);
  Dlg.Caption := Application.Title;
  Dlg.BorderIcons := [];
  Dlg.Height := 130;
  Dlg.ActiveControl := TButton(Dlg.FindComponent('Yes'));
  TImage(Dlg.FindComponent('Image')).Picture.Assign(Application.Icon);
  TButton(Dlg.FindComponent('Yes')).Caption := 'Tak';
  TButton(Dlg.FindComponent('No')).Caption := 'Nie';
  TButton(Dlg.FindComponent('Yes')).Top := 70;
  TButton(Dlg.FindComponent('No')).Top := 70;
  CBX := TCheckBox.Create(Dlg);
  CBX.Parent := Dlg;
  CBX.Caption := 'Zawsze pytaj';
  CBX.Left := (Dlg.Width - CBX.Width) div 2;
  CBX.Top := 40;
  CBX.Checked := False;
  CBX.OnClick := CBXOnClick;
  Dlg.ShowModal;
  case Dlg.ModalResult of
    mrYes : begin
      Caption := 'Tak';
    end;
    mrNo : begin
      Caption := 'NIE';
    end;
  end;
  if CBX.Checked then
  begin
    Caption := Caption + #32 + '- Zaznaczony';
  end
  else
  begin
    Caption := Caption + #32 + '- Odznaczony';
  end;
end;

Tylko wiadomo, taki obrazek będzie tym co zaprojektowali twórcy IDE typu Delphi czy Lazarus. A pod tym pierwszym na pewno nie będzie to w pełni idelnie systemowa grafika. Przynajmniej tak się mi zdaje. Natomiast pod WinAPI nie próbowałem tego, ale na logikę można kombinować tak jak poniżej. Najpierw jakaś stała. Przykładowo:

const
    WM_CHANGEMSGBOX = WM_USER + 2012;

I dodać sobie własną funkcję do wywołania MessageBoxa. Poniżej akutat żywcem kopiowiane z mojego kodu w WinAPI. Ale pod VCL możesz sobie tam podstawić uchwyt głownej formatki, tylko ważne żeby Formatka obsługiwała ten komunikat w swoim WndProc, czyli musisz subclassować na przykład.

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;

Ważne jest żeby było PostMessage, a nie Send, bo może nie zadziałać gdyż czeka na efekty. Ok. To teraz trzeba obsłużyć komunikat we WndProc formatki lub naszego okna czy dialogu. Na przykład tak:

//...
  if Msg = WM_CHANGEMSGBOX then
  begin
    H := FindWindow(WC_DIALOG, nil);
    if GetParent(H) = AHWnd then
    begin
      PNewMsgBoxProc := @MsgBoxProc;
      POldMsgBoxProc := Pointer(SetWindowLong(H, GWL_WNDPROC, Integer(PNewMsgBoxProc)));
      if (AWParam and MB_OKCANCEL > 0)
        or (AWParam and MB_YESNOCANCEL > 0) then
      begin
        SetDlgItemText(H, IDCANCEL, '&Cancel');
      end;
      SetDlgItemText(H, IDTRYAGAIN, 'Try again');
      SetDlgItemText(H, IDCONTINUE, 'Continue');
      SetDlgItemText(H, IDIGNORE, 'Ignore');
      SetDlgItemText(H, IDRETRY, 'Retry');
      SetDlgItemText(H, IDABORT, 'Abort');
      SetDlgItemText(H, IDHELP, '&Help');
      SetDlgItemText(H, IDYES, '&Yes');
      SetDlgItemText(H, IDNO, '&No');
    end;
  end;
//...

Jak widzisz sublassuje tutaj obsługę komunikatów okienka MessageBox. Czyli można cudować w razie potrzeby na przykład, tak jak poniżej kiedy okienko się mi nie zamykało Escapem, a chciałem tego:

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;

Jak widzisz tutaj bez problemów dobierając się do funkcji obsługi komunikatów lub wcześniej mając już uchwyt tego tworzonego okienka. Nic nie stoi na przeszkodzie by sobie enumerować kontorlki z niego poprzez EnumChildWindows i poprzez GetClassName sprawdzić czy klasa to Static i spróbować wysłać do kontrolki komunikat za pewne STM_GETICON lub STM_GETIMAGE. Jeżeli zwróci to nam uchwyt rózny od zera. Za pewne typu HICON, to nic już nie stoi nam na przeszkodzie by podstawić go do TImage, czy narysować go sobie na formatce albo na jakimś Canvasie. Lub na przykład zapisać do pliku.

Tak ja bym kombinował. Trzeba tylko sobie zrobić formatkę do testów i poenumerować do na przykład Memo listę kontrolek z uchwytami oraz klasami. Żeby mieć pewność czy nie ma innych Staticów w oknie i takie tam. I może są prostsze sposoby, ale ja tak bym kombinował i dla mnie sposób z wykorzystaniem WinAPI, wydaje się najprostszy do zastosowania i nawet wręcz oczywisty.

EDIT: na szybko zrobiłem takie coś. Pokazałem sobie jakieś okienko MessageBox ze swojego programu WinAPI z "aboutem". Ustaliłem uchwyt Static z ikonką swoim prostym lamerskim programikiem WinInfo, który tutaj kiedyś zapodawałem. I zrobiłem pod VCL na szybko:

  Image1.Picture.Icon.Handle := SendMessage($603C8, STM_GETICON, 0, 0);

Ikona widoczna na MessageBox pokazała się bez problemów na TImage, także tak jak podejrzewałem, można w ten sposób śmiało zrobić i uzyskać bez większych problemów zamierzony efekt :)

2

http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045%28v=vs.85%29.aspx
Dajesz chyba: OBM_EXCLAMATION - dokładnie nie pamiętam, kiedy to szukałem - znalazłem w google.

0

Ano fakt. Zapomniałem, że LoadImage może też nam ładować standardowe grafiki, tak jak SetCursor ustawiać systemowe kursory. No coż, na około pokombinowałem. Lecz może i taki sposób się też przyda szukającym, bo subclassując standardowego MessageBoxa, mamy fajne możłiwości. Jak na przykład łatwe dodanie innych potrzebnych nam kontrolek w takim oknie bez potrzeby tworzenia własnego dialogu od zera :)

0

Ja w tej chwili mam dynamicznie tworzoną formę z tym komponentami> I właśnie pasowało by na niej umieścić ikonkę po prawej stronie z możliwością nawet dla ułatwienia tej samej zmiennej jak przy MessageBox np. IconWarnning, żeby to już było intuicyjne/ na zasadzie analogii.
Na początku procedury przymierzałem się do zmiennej uType: UINT; i w tym miejscu utknąłem. Zapewne dojdzie do tego położenie ikony, jakieś

IconX, IconY: Integer;

Poniższa forma jest testowa i na jej przykładzie chciałem zmajstrować kilka większych do pobierania i przetwarzania danych. Dlatego chciałem dopracować temat. Więc co by teraz należało tam wstawić? Powyższe przykłady też się przydadzą.

Przykładowy kod

// Okno dialogowe o zapisaniu lub wczytaniu pliku zrobione na podstawie InputQuery
procedure TDlgImpExp.FormCreate();
const
  btWidth = 75;
var
  btMarginX,btSpace: Integer;
  uType: UINT;    // http://4programmers.net/WinAPI/MessageBox
begin
  uType:= MB_ICONQUESTION;

  Form := TForm.Create(Application);
  with Form do
    try
      Form.Font := Font;
      Width := 300;
      Height:= 160;
      BorderStyle := bsDialog;
      Position := poScreenCenter;
      Caption := 'Wybór opcji.';
      Name  := 'Form';


      lbPrompt := TLabel.Create(Form);
      with lbPrompt do
      begin
        Parent := Form;
        Caption := 'Informacja o .....';
        Left := 16;
        Top := 16;
        Width:= fmDlgImpExp.Width - 32;
        WordWrap := True;
        Name  := 'lbPrompt';
      end;

      btMarginX:= 30;
      btSpace:= (Form.Width - (2*btMarginX) - (3*btWidth)) div 2;

      btExport := TButton.Create(Form);
      with btExport do
      begin
        Parent := Form;
        Caption := 'Eksport';
        Left := btMarginX;
        Top := lbPrompt.Top +20 +lbPrompt.Height;
        Width := btWidth;
        Height:= 25;
        Name  := 'btExport';
        OnClick:= btExportClick;
      end;

      { kilka butonów ...............
      }

      Form.ShowModal;

    finally
      lbPrompt.Free;
      btExport.Free;

      ....

      Form.Free;
    end;
    
end;

0

Skoro potrzebujesz okno dialogowe, wyglądające podobnie jak systemowe, ale z własnymi elementami, to dlaczego nie zrobisz sobie swojego? Dla okna funkcjonalnego jak MessageBox to bardzo mało roboty - więcej klikania niż programowania;

Jeśli byłbyś zainteresowany zrobieniem własnego okna dialogowego według własnych wytycznych, to polecam swój artykuł pt. "Własne okna dialogowe", w którym to opisałem sposób na stworzenie prostego okna dialogowego (własny odpowiednik MessageBox), jak i okna zwracającego dowolne dane (np. struktury).

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