Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

BUG: TLMDDockPanel.OnCloseQuery sender has incorrect sender

Steps:
Create a new application, add the docking site, add 2 or more panels to the docking site, let's say Panel1, Panel2 and Panel3
Create the OnCloseQuery event for Panel1. Assign the same method (Panel1CloseQuery) to the OnCloseQuery event of all panels.

so you have
Panel1.OnCloseQuery = Panel1CloseQuery.
Panel2.OnCloseQuery = Panel1CloseQuery.
Panel3.OnCloseQuery = Panel1CloseQuery.

Make this the code of the method:

procedure TForm1.Panel1CloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 if sender is TLMDDockPanel then
  begin
     outputdebugstring(pchar('Sender: '+TLMDDockPanel(sender).Name));
     CanClose := false; // << this is just so you can repeat the test as much as you want
  end;
end;


Run the application.
Undock panel1 and leave it floating on the desktop. Undock panel2 and panel3  and dock both into Panel1.
Hit the 'x' close button on any panel.
The Sender will always be Panel1, for any of the 'x' buttons you press.
I expected that hitting the 'x' of Panel2 would call the event with the sender = Panel2, and the same for Panel3.
Is that something that can be fixed?

UPDATE:
This is way worse than I first thought.
When you attempt to close a docked panel, the OnCloseQuery event happens to ALL panels in that site, even for the not visible ones!
And unless all the handlers set CanClose to true, it won't close. And when it closes, it closes ALL the panels!
This makes absolutely no sense to me, can you please review how this works?


Comments

  • 3 Comments sorted by Votes Date Added
  • Ok, I found the issue and fixed it.
    The problem is that there is a bug in the logic behind  TLMDDockPanel.UpdateTracking and how it executes from that point onwards.

    Basically, it ends up calling TFloatingSite.PanelButtonClick, and that internally has what I think is the bug.

    procedure TFloatingSite.PanelButtonClick(APanel: TLMDDockPanel;  B: TLMDPanelBtnKind);
    var
      sgl: TLMDDockPanel;
    begin
      if (GetFormKind(sgl) <> ffPanel) or (APanel = sgl) then
      begin
        if not HeaderBtnClick(B) then
          inherited;
      end
      else
        inherited;
    end;



    The
    if (GetFormKind(sgl) <> ffPanel) or (APanel = sgl) then
    code is insufficient in my view, and that is causing t
    he
    HeaderBtnClick(B)to run and that not only closes the whole floating form (FForm.close), but also returns false and doesn't let the ffPanel.Close execute inside the inherited part.

    This code must correctly differentiate if it's being triggered by the close button of a Panel or of the FloatingForm, and it's failing that.

    I fixed it by adding a parameter to PanelButtonClick to indicate that sender:

    procedure TFloatingSite.PanelButtonClick(APanel: TLMDDockPanel; B: TLMDPanelBtnKind; pPanelBtn : Boolean);

    and then internally the IF code becomes this:


    procedure TFloatingSite.PanelButtonClick(APanel: TLMDDockPanel;  B: TLMDPanelBtnKind; pPanelBtn : Boolean);
    var
      sgl: TLMDDockPanel;
    begin
      if (GetFormKind(sgl) <> ffPanel) or (APanel = sgl) then
      begin
        if (pPanelBtn) or (not HeaderBtnClick(B)) then
          inherited;
      end
      else
        inherited;
    end;

    Now the only thing missing is to call that method with the right parameter at the right time:

    procedure TLMDDockPanel.UpdateTracking(AMouseDown, AMouseUp: Boolean);
    begin
    (...)
    FSite.PanelButtonClick(Self, btn, True);
    (...)
    end;

    And for the DockingSite one:

    procedure TLMDDockSite.MouseUp(Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
    (...)
    PanelButtonClick(pnl, pbClose, False);
    (...)
    end;

    And everything works as I think it should.

  • Posts: 0 Accepted Answer Vote Up0Vote Down
    Hi,

    The buf has been fixed. The fix a quite simpler than your code. You need just invert IF expression, like this:

    procedure TFloatingSite.PanelButtonClick(APanel: TLMDDockPanel;  B: TLMDPanelBtnKind; pPanelBtn : Boolean);
    var
      sgl: TLMDDockPanel;
    begin
      if (GetFormKind(sgl) = ffPanel) and (APanel = sgl) then
      begin
        if not HeaderBtnClick(B) then
          inherited;
      end
      else
        inherited;
    end;
Sign In or Register to comment.