wxTreeCtrl and right click events

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
benedicte
wxWorld Domination!
wxWorld Domination!
Posts: 1409
Joined: Wed Jan 19, 2005 3:44 pm
Location: Paris, France

wxTreeCtrl and right click events

Post by benedicte »

I have a tree control (wxTreeCtrl) in my app. I am trying to catch the right click events.
I have understood how the "context" menu and the "right click" work.

EVT_CONTEXT_MENU(MyFrame::OnContextMenu)
EVT_TREE_ITEM_RIGHT_CLICK(-1, MyFrame::OnItemRightClick)

both functions create and display the popup menu regarding the "selected" item if any. I also handle the context menu when the user clicked in an empty area.

My problem is the following:
1/ I right click on a given element in my tree (the popup is displayed correctly using EVT_TREE_ITEM_RIGHT_CLICK
2/ I LEFT click on another tree item (without cancelling explicitely the popup menu), I receive a "EVT_CONTEXT_MENU" event before the focus is set on the tree item... and I think I should not receive this event at all !

Here is a part of my code:
void MyFrame::OnItemRightClick(wxTreeEvent& event)
{
wxTreeItemId &cur_item = event.GetItem();
if (!IsSelected(cur_item))
{
UnselectAll();
SelectItem (cur_item);
}
// this is my function creating and displaying a dynamic popup menu
ShowMenu(cur_item, event.GetPoint());
event.StopPropagation ();
}
void MyFrame::OnContextMenu(wxContextMenuEvent& event)
{
wxTreeItemId item;
wxPoint pt = event.GetPosition();
// if event was generated by keyboard (MSW-specific?)
if (pt.x==-1 && pt.y==-1) //(this is how MSW indicates it)
{
// get the selection
item = GetSelection();
//attempt to guess where to show the menu
if (item.IsOk())
{
//if an item was clicked, show menu to the right of it
wxRect rect;
GetBoundingRect(item, rect, true); //true = only the label
pt = wxPoint(rect.GetRight(), rect.GetTop());
}
else
pt = wxPoint(0, 0);
}
else
// else, the user clicked in a blank area... so unselect all items
{
//event was generated by mouse, use supplied coords
pt = ScreenToClient(pt);
UnselectAll();
}
ShowMenu(item, pt);
}

void MyFrame::ShowMenu(wxTreeItemId id, const wxPoint& pt)
{
// creates a menu
...
wxMenu * menu = new wxMenu...

if (menu != NULL)
{
PopupMenu(menu, pt);
delete menu;
}
}
The same code works well if I use a wxTreeListCtrl.

Does anyone know what may be wrong ? Is there a "bug fix" in 2.5.3 ?

wxWidgets 2.5.1
on Windows (a port will be done on Linux/Unix & MacOS)
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

Resurrecting this ancient thread: seems this is still an issue in wxWidgets 3.0.x anno 2021 on Linux/GTK.

EVT_TREE_SEL_CHANGED = works only when clicking on items
EVT_TREE_ITEM_MENU = works only when clicking on items
EVT_CONTEXT_MENU = nothing
[s]EVT_RIGHT_DOWN = nothing[/s]*
[s]EVT_RIGHT_UP = nothing[/s]*
EVT_MOUSE_EVENTS = nothing for mouse button events (only for motion and enter/leave events AFAIK)

Presumably, all button events are usurped by the EVT_TREE_ITEM_MENU handler, even when not implemented!
I'm reasonably sure I found a solution for this years ago...but I forgot in which of my many wx projects. :?

There's also this bug ticket: http://trac.wxwidgets.org/ticket/17076

*Edit: actually I was wrong; I do see mouse button up/down events now when explicitly wxTreeCtrl::Bind()-ing the EVT_RIGHT_* events, but EVT_CONTEXT_MENU, still doesn't appear to work in the same manner. Also, an item (root) seems to be always selected, making it impossible to distinguish between non-item clicks and true wxTreeCtrl context clicks...

**Edit2: EVT_CONTEXT_MENU and EVT_TREE_ITEM_MENU seem to behave identically, only one may be implemented in your application however. Again, EVT_CONTEXT_MENU is useless since it automatically selects the nearest tree item when right-clicking.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTreeCtrl and right click events

Post by doublemax »

So is there still an actual problem? From what i've read in the ticket, everything seems to be fixed or work as expected.
Use the source, Luke!
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

I'm still trying to figure that out. But for sure, it's non-intuitive if you just want to implement a simple context menu that's not tied to the currently selected tree item.

I'll post it here if I get it working somehow.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTreeCtrl and right click events

Post by doublemax »

EVT_CONTEXT_MENU is useless since it automatically selects the nearest tree item when right-clicking.
Selecting an item on right-click may be undesirable, but if that's the behavior of the native control, that's how it is. It still doesn't prevent you from showing a popup menu, does it?

BTW: What happens on middle click?
Use the source, Luke!
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

No, the problem is that it is not possible to de-select tree item(s) at all. There's always one tree item selected at all times. So right-clicking always invokes the tree item context event because there's always at least one tree item selected. This makes it impossible to implement a generic context menu in a wxTreeCtrl that's not tied to the selection.

Middle click does nothing on my system.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTreeCtrl and right click events

Post by doublemax »

Usually i don't work under Linux, but i just fired up a VM to test this. If i right click on an empty area, i get a OnContextMenu. Right click on an item, opens the item menu.

Screenshot_2021-07-07_20-29-45.png
Screenshot_2021-07-07_20-29-45.png (50.3 KiB) Viewed 6659 times
Screenshot_2021-07-07_20-29-09.png
Screenshot_2021-07-07_20-29-09.png (47.93 KiB) Viewed 6659 times
Use the source, Luke!
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

Hmm, that's interesting (I'm also using Mint Cinnamon 19 by the way, which has some minor GTK/Gnome/GTK related quirks here and there).

I have something working now, using a workaround. I've set the style to wxTR_MULTIPLE instead of wxTR_SINGLE. This prevents one tree item being selected all the time. Then I bind the right mouse click event, and handle it like this:

Code: Select all

int style = wxNO_BORDER | wxTR_HAS_BUTTONS | wxTR_MULTIPLE;
treeview = new wxTreeCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(300,300), style);
treeview->Bind( wxEVT_RIGHT_DOWN, &CMainWindow::OnTreeMouse, this );

Code: Select all

// lame workaround for testing with wxTR_MULTIPLE instead of wxTR_SINGLE
wxTreeItemId GetOneItem(wxTreeCtrl *treeview)
{
 //return treeview->GetSelection(); // <-- works only for wxTR_SINGLE style
 wxArrayTreeItemIds arr;
 int n = treeview->GetSelections( arr );
 if (n > 0) return arr[0];
 return wxTreeItemId();
}

// shows treeview context menu
void CMainWindow::ShowTreeContextMenu()
{
 if (!treeview) return;
 
 wxMenu menu;
 wxTreeItemId item = GetOneItem( treeview );
 if (item.IsOk()) {
  menu.Append( cmdTreeRemove, "&Remove", "Removes resource"); // <-- selected tree item context menu
 } else {
  menu.Append( cmdTreeAddImage, "&Add Image...", "Adds new image");  // <-- global tree context menu
 }
 PopupMenu( &menu, ScreenToClient( wxGetMousePosition() ) + wxPoint(3,3) );
}

// mouse click event handler
void CMainWindow::OnTreeMouse(wxMouseEvent &evt)
{
 if (evt.RightDown()) {
  ShowTreeContextMenu();
 }
}
Now I only need to manually implement single selection mode to replicate wxTR_SINGLE behavior.

*Edit: also, I've not been able to get wxEVT_CONTEXT_MENU working, it behaves exactly like EVT_TREE_ITEM_MENU, even with wxTR_MULTIPLE. Maybe I need to sprinkle some evt.Skip() here 'n there?
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

I should also try the wx sample program by the way!
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxTreeCtrl and right click events

Post by ONEEYEMAN »

Hi,
Remdul wrote: Wed Jul 07, 2021 6:53 pm I should also try the wx sample program by the way!
That should always be your FIRST course of action. ;-)

Thank you.
Remdul
Earned a small fee
Earned a small fee
Posts: 16
Joined: Tue Oct 27, 2009 10:14 pm
Location: Netherlands

Re: wxTreeCtrl and right click events

Post by Remdul »

Yes, but I'd rather have it working in my application as well. Unfortunately it's easy to get bogged down by undefined behaviour with wxWidgets. I know it's usually related to lower level API (Win32/GTK/X11) and not directly wxWidgets fault, but it's really frustrating and time consuming to make even simple stuff (like this case) work without minimal code snippets. Most wx samples are complex, they're more like unit tests or demos than code samples. I try to post code snippets here or on the wiki when I can, for googlers from the future.
Post Reply