-1

I have a problem with showing a modal form from a custom component. During the application start the CustomComponent creates a custom form (CreateMenu) which is not visible for the user. When the user clicks on the component (during runtime) the custom form is shown (MouseClick) which is a form with buttons - commands.

When I use ShowModal method to show the menu-form for the component The Parent form is blocked and also the shown menu-form is blocked. Below is the code for creating the custom form (in a custom component) and showing it.

procedure TCustomComponent.MouseClick(Sender: TObject; Button: TMouseButton;         Shift: TShiftState; X: integer; Y: integer);
begin
self.Repaint;
  self.PMenuForm.Left := self.Left; // p.x;
  self.PMenuForm.Top := self.Top + self.Height + 5; // p.Y+self.Height+5;
  PMenuForm.ShowModal;
end;


procedure TCustomComponent.CreateMenu(title: string);
begin

  if PMenuForm = nil then
  begin
    PMenuForm := TForm.Create(self.Parent);
    PMenuForm.Parent := self.Parent;
    PMenuForm.ParentWindow := self.Parent.Handle;
    PMenuForm.FormStyle := fsStayOnTop;
    PMenuForm.Enabled := true;
    PMenuForm.Visible := false;
    PMenuForm.BorderWidth := 2;
    PMenuForm.BorderStyle := bsNone;
    PMenuForm.BorderIcons := [];
    PMenuForm.caption := title;
    PMenuFormTitle := TLabel.Create(PMenuForm);
    PMenuFormTitle.Left := 0;
    PMenuFormTitle.Top := 0;
    PMenuFormTitle.Margins.Left := 5;
    PMenuFormTitle.AutoSize := true;
    PMenuFormTitle.Visible := true;
    PMenuFormTitle.Parent := PMenuForm;
    PMenuFormTitle.Font.Color := MakeColor($FFFFFF);
    PMenuFormTitle.Font.Size := 10;
    PMenuFormTitle.Font.Style := [fsBold];
    PMenuFormTitle.Color := MakeColor($0000CC);
    PMenuFormTitle.Transparent := false;
    PMenuFormTitle.caption := title;
    PMenuFormTitle.Layout := tlCenter;
    PMenuFormTitle.Alignment := taLeftJustify;
    PMenuFormTitle.AutoSize := false;
    if PMenuFormTitle.Width < 55 then
      PMenuFormTitle.Width := 65;
    if PMenuFormTitle.Height < 10 then
      PMenuFormTitle.Width := 10;

    PMenuFormItems[0] := TBitBtn.Create(PMenuForm);
    PMenuFormItems[0].Parent := PMenuForm;
    PMenuFormItems[0].ParentWindow := PMenuForm.ClientHandle;
    PMenuFormItems[0].tag := 0;
    PMenuFormItems[0].Enabled := true;
    PMenuFormItems[0].Visible := true;
    PMenuFormItems[0].Top := 0;
    PMenuFormItems[0].Left := PMenuFormTitle.Width - 22;
    PMenuFormItems[0].caption := 'X';
    PMenuFormItems[0].Font.Style := [fsBold];
    PMenuFormItems[0].Width := 20;
    PMenuFormItems[0].Height := PMenuFormTitle.Height;
    PMenuFormItems[0].OnClick := self.MenuItemClick;
    PMenuForm.AutoSize := true;
    self.PMenuFormItemsCount := 0;

    self.OnMouseDown := self.MouseClick;
    self.Cursor := crHandPoint;
  end;
end;

Thank you for any suggestions.

Clarifications: 1. Blocked means that the parent form AND the shown menu-form are both unresponsive, not enabled. Also every button on the menu-form is unresponsive ie. does not respond to mouse hoover, and cannot be clicked (it is not grayed though just does not react to clicks and anything else)

  1. It is intended that the parent form is "blocked" / unresponsive but this also affects the shown menu-form - it is also unresponsive (buttons it).
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
Quba
  • 1
  • 1
  • What do you mean when you say "blocked:? – Freddie Bell Aug 31 '18 at 15:47
  • 2
    If you mean the parent form does not respond to user input, then that is what ShowModal means. It is by design. If you need the parent to be responsive, use Show instead, but it is a bit harder to manage. – Dsm Aug 31 '18 at 15:51
  • Clarifications in the main question. – Quba Aug 31 '18 at 15:58
  • 1
    On a side note, I have never seen someone create an instance of an empty form and then populate the controls within the form. Why not just design another form and create it in one single line? – Jerry Dodge Aug 31 '18 at 17:45

3 Answers3

0

This is by intent, from the first version of Delphi on. The oldest on-line html documentation is from Delphi 2007, where ShowModal documents:

Use ShowModal to show a form as a modal form. A modal form is one where the application can't continue to run until the form is closed. Thus, ShowModal does not return until the form closes. When the form closes, it returns the value of the ModalResult property.

If your question is actually about how to work around the menu also being blocked:

  • do not use ShowModal, but Show, and be prepared that the form is now not modal any more, so the user can switch back and forth between the form and the rest of the applications
  • show the menu in the modal form
Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154
  • I am using the second option that You have mentioned. I am creating a New form called PMenuForm and after creating bitbtns for the commands. The probkem is that when I show the newly created PMenuForm the buttons are unresponsive. – Quba Aug 31 '18 at 16:12
  • Please ask this in a new question, and be sure to trim it down to a small reproducible problem. That way others can reproduce it and help you approaching a solution. – Jeroen Wiert Pluimers Sep 04 '18 at 16:46
0

This line: PMenuFormItems[0].OnClick := self.MenuItemClick; says that self (CustomComponent) has a method MenuItemClick. Is it implemented? What does it do?

That is where a click on the bitbutton PMenuFormItems[0] would end up. If that doesn't lead to either setting PMenuForm.ModalResult or specifically closing the PMenuForm, the unresponsiveness continues.

There are two setting in your code

//    PMenuForm.ParentWindow := self.Parent.Handle;
//    PMenuFormItems[0].ParentWindow := PMenuForm.ClientHandle;

that I had to outcomment. They caused AV:s

They are useless in your code, as is documented:

Setting ParentWindow has no effect if Parent is not nil (Delphi) or NULL (C++).

For both, you are setting the Parent property-

Tom Brunberg
  • 20,312
  • 8
  • 37
  • 54
  • MenuItemClick is implemented but is never fired because the shown modal form is unresponsive. Although in the MenuItemClick I call PMenuForm.Close. It works when I change the call PMenuForm.showmodal to PMenuForm. Show. – Quba Aug 31 '18 at 16:32
  • Is the `TCustomComponent` crucial to show the problem? As you did not show it, I tried your code without, and simply used my main form as a substitute, for the `OnClick` to show the menu and to host the event for the menu item (TBitBtn) click. It works as it should! Main form is nonresponsive during showing the menu and a click on the `bitbtn` closes the menu and the main form becomes responsive again. (I tried both with `PMenuForm.Close` and `PMenuForm.ModalResult := mrOK;` – Tom Brunberg Aug 31 '18 at 16:49
  • Please provide a [mcve], with emphasis on *minimal* and *complete*. Reduce all code to the real minimum. – Tom Brunberg Aug 31 '18 at 16:50
  • I checked it also without the component and it works as it should. I think that maybe something is wrongly assigned in the menucreate. I feel that the problem May be xonnected with PMenuForm. Parent and ParentWindow properties. – Quba Aug 31 '18 at 17:03
0

The reason why your PMenuForm gets blocked is because as its parent you have set a control on another form which means that the window of your form is actually a child window of another form.

So when that form gets blocked by ShowModal call there is no way for your PMenuForm to receive the OnClick message because in order to do so such message must be forwarded from parent form or component which in this case is disabled at the time.

Therefore I'm afraid you will have to use a different approach to achieve what you wish. Here is what I would do.

Show your PMenuForm normally but disable other controls on your form. You can do this easily by placing your controls on panels and then simply disabling the panels which in turn disables all child controls that are placed on panels. If your application has multiple forms you can also disable those other forms and thus similar effect as using modal forms.

SilverWarior
  • 7,372
  • 2
  • 16
  • 22