4

When checking or unchecking the checkbox in the vst, I want to ask for confirmation in some cases. (Un)checking works fine until I open a MessageBox from the OnChecking event handler.

When I have shown the MessageBox (and set Allowed to true) the checkbox state does not change and I have to click a second time in order to toggle the checkbox.

For any reason I haven't figured out yet, the second time the OnChecking event handler isn't called.

It seems to be related with the focus: if I click on another node before the second click to the checkbox it doesn't work a all. I'm using Delphi XE2 and Vitual Treeview 5.3.

Can somebody confirm this behavior and think of a fix/workaround?

This MCVE shows the behavior. Just add a button and a vst to a form and assign the event handlers:

type
  TMyData = class
  public
    value: String;
    constructor Create(str: String);
  end;

constructor TMyData.Create(str: String);
begin
  value := str;
end;

procedure TForm3.btnInitTreeClick(Sender: TObject);
begin
  VirtualStringTree1.NodeDataSize := Sizeof(TObject);
  VirtualStringTree1.TreeOptions.MiscOptions := VirtualStringTree1.TreeOptions.MiscOptions + [toCheckSupport];
  VirtualStringTree1.CheckImageKind := ckSystemDefault;

  with VirtualStringTree1.Header.Columns.Add do
  begin
    Text := 'Colum header';
    Width := 150;
  end;

  VirtualStringTree1.AddChild(nil, TMyData.Create('1')).CheckType := ctCheckBox;
  VirtualStringTree1.AddChild(nil, TMyData.Create('2')).CheckType := ctCheckBox;
  VirtualStringTree1.AddChild(nil, TMyData.Create('A')).CheckType := ctCheckBox;
  VirtualStringTree1.AddChild(nil, TMyData.Create('B')).CheckType := ctCheckBox;
end;

procedure TForm3.VirtualStringTree1Checking(Sender: TBaseVirtualTree;
  Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean);
var
  data: TObject;
begin
  data := TObject(Sender.GetNodeData(Node)^);
  if assigned(data) and (data is TMyData) and (TMyData(data).value = 'A') then
    Allowed := Application.MessageBox('Are you sure?', 'Confirmation', MB_YESNO or MB_ICONQUESTION) = ID_YES
  else
    Allowed := true;
end;

procedure TForm3.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var
  data: TObject;
begin
  data := TObject(Sender.GetNodeData(Node)^);
  if assigned(data) and (data is TMyData) then
    CellText := TMyData(data).value
end;

Edit: The problem also can be reproduced with version 5.5.2

Chris
  • 1,508
  • 1
  • 11
  • 30
  • Have you tried using the latest XE2 compatible version [5.5.2](https://github.com/Virtual-TreeView/Virtual-TreeView/releases/tag/V5.5.2) or the [XE2 fork](https://github.com/Virtual-TreeView/Virtual-TreeView-XE2)? – Joachim Marder Nov 13 '15 at 08:06
  • @JoachimMarder no I haven't as I did not find an entry in changelog or issues. – Chris Nov 13 '15 at 09:08
  • I can't tell from my mind if this is a known issue. Is there anything that prevents you from using the latest available version? – Joachim Marder Nov 13 '15 at 12:00
  • I should not change component version on my development machine just for testing purposes. I will try it on a testing / "play" machine (probably on Monday or Tuesday) and let you know the result. – Chris Nov 13 '15 at 13:49

2 Answers2

4

I can confirm this behavior. VST v4.5.5

The problem with the OnChecking implementation (TBaseVirtualTree.HandleMouseDown) is that the WM_LBUTTONUP message is not being processed and TBaseVirtualTree.HandleMouseUp goes out of sync when showing the modal dialog, and the new state is not being updated. I have not dug deep enough into this to suggest a general fix.

The workaround:

type
  TBaseVirtualTreeAccess = class(TBaseVirtualTree);

procedure TForm1.VirtualStringTree1Checking(Sender: TBaseVirtualTree;
  Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean);
var
  data: TObject;
begin
  data := TObject(Sender.GetNodeData(Node)^);
  if assigned(data) and (data is TMyData) and (TMyData(data).value = 'A') then
  begin    
    Allowed := False; // We will handle this ourself
    if Application.MessageBox('Are you sure?', 'Confirmation', MB_YESNO or MB_ICONQUESTION) = ID_YES then
    begin
      // Update the state and trigger OnCheck if needed
      TBaseVirtualTreeAccess(Sender).DoCheckClick(Node, NewState);
    end;
  end
  else
    Allowed := True;
end;
kobik
  • 21,001
  • 4
  • 61
  • 121
0

Same behaviour on 5.2.1.

The following does the job modifying the state after it's changed.

procedure TForm3.VirtualStringTree1Checked(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  data: TObject;
begin
  data := TObject(Sender.GetNodeData(Node)^);
  if assigned(data) and (data is TMyData) and (TMyData(data).value = 'A') then begin
    if Application.MessageBox('Are you sure?', 'Confirmation', MB_YESNO or MB_ICONQUESTION) = IDYES then
      Exit;
    if  Node.CheckState = csUncheckedNormal then
      Node.CheckState := csCheckedNormal
    else
      Node.CheckState := csUncheckedNormal;
  end;
end;
fantaghirocco
  • 4,761
  • 6
  • 38
  • 48