Toflidium.com Articles

Creating a Treeview that really does RightClickSelect

By Toby Allen
Monday, March 04, 2002

When you've been working with Delphi for a while you notice that some VCL components just don't do things they're supposed to.  One example of this is the TTreeview which despite having a property called RightClickSelect, doesn't actually often select the item when you right click - especially if you are using a popup menu.

I am sure there are many ways of doing this, but I have come up with one.  I have also provided code to allow the OnClick event handler to be called when the right click is active.

What I've done in order to ensure that all the TTreeviews that I use have this added, is to created a base class descended from TTreeview (you could descend from TCustomtreeview - which would give you greater control over published properties).  I've called this TRCSelectTV, and then any new custom components I create can be descended from this.

The definition is like this.


type
    TRCSelectTV = class(TCustomTreeView)
    protected
      procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
    end;

The only extra code we need to add is a Message handler that catches the WM_RBUTTONDOWN message.  Windows message procedures work slightly differently from normal overridden methods.  You dont use the override directive in the method declaration, but you do use the inherited keyword in the implementation to call the inherited version of the message method.  This ensures as with normal overridden methods that the inherited code is called.  In this case I dont actually believe its necessary, but its a good habit to get into.

procedure TRCSelectTV.WMRButtonDown(var Message: TWMRButtonDown);
begin

    if RightClickSelect then
        Selected :=  GetNodeAt(Message.XPos, Message.YPos);
    inherited;

end;

Now all we need to do is build our compoent into a package and we have a new basic Treeview that correctly selects when the user right clicks.

Providing an OnClick event.

We have one more problem, our OnClick handler won't run when we right click and so some code we might have to update other things when we click on a node might not run when we right click.  There are a number of ways of doing this.

  1. We could just call the standard OnClick event handler (if assigned).
  2. We could have a boolean property such as RightClickOnClick which if true would mean we would call the standard OnClick event handler (if assigned).
  3. We could have a seperate OnRightClick event handler which we will try to call if assigned.

I'm going to go for the third option, as personally I believe it is the neatest, although option 2 is equally as good.  Option 1 I think is a bit presumptuous.

We extend our Class definition to include our new event property.

 


type
    TRCSelectTV = class(TCustomTreeView)
    private
         FOnRightClick : TNotifyEvent;
    protected      
      procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
    published
      property OnRightClick : TNotifyEvent read FOnRightClick write FOnRightClick;

    end;

Now we change our method definition



procedure TRCSelectTV.WMRButtonDown(var Message: TWMRButtonDown);
begin

    if RightClickSelect then
        Selected :=  GetNodeAt(Message.XPos, Message.YPos); 

    if assigned(FOnRightClick) then    FOnRightClick(Self);
    inherited;

end;

About Us | Site Map | Contact Us | ©2003 Toby Allen - Toflidium Software