Right Click on a control

BlitzMax Modules Forums/Brucey's Modules/Right Click on a control

I have some code that works fine till i limit the popupmenu to particular controls.
In the TestPopupsMain.bmx i have:
Type MyFrame2 Extends MyFrame2Base

	Method OnInit()
		Super.OnInit()

		
'		ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)
		m_listBoxPopup1.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)', Null, Self)
		' intercept all menu events And Log them in this custom event handler
		PushEventHandler(New MyEvtHandler.Create(Self))
	End Method


If i comment out m_listBoxPopup1.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)', Null, Self) and uncomment ' ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)
then it works as expected.
BUT it produces the menu on items/spaces where i don't want it.

any ideas?

Cheers
Glenn

TestPopups.bmx
'
' BlitzMax code generated with wxCodeGen v0.96 : 25 Feb 2008 23:22:05
' 
' 
' PLEASE DO "NOT" EDIT THIS FILE!
' 
SuperStrict

Import wx.wxFrame
Import wx.wxListBox
Import wx.wxListCtrl
Import wx.wxPanel
Import wx.wxWindow
Import wx.wxMouseEvent

Type MyFrame2Base Extends wxFrame

	Field m_panel5:wxPanel
	Field m_listBoxPopup1:wxListBox
	Field m_listBoxPopup2:wxListBox
	Field m_listBoxNoPopup:wxListBox
	Field m_listCtrlMainTask:wxListCtrl
	

	Const ID_lb1:Int = 1000
	Const ID_lb2:Int = 1001
	Const ID_MainTask:Int = 2000
	
	Method Create:MyFrame2Base(parent:wxWindow = Null,id:Int = wxID_ANY, title:String = "", x:Int = -1, y:Int = -1, w:Int = 800, h:Int = 500, style:Int = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL)
		Return MyFrame2Base(Super.Create(parent, id, title, x, y, w, h, style))
	End Method

	Method OnInit()

		Local bSizer11:wxBoxSizer
		bSizer11 = New wxBoxSizer.Create(wxVERTICAL)
		m_panel5 = New wxPanel.Create(Self, wxID_ANY,,,,, wxTAB_TRAVERSAL)

		Local bSizer12:wxBoxSizer
		bSizer12 = New wxBoxSizer.Create(wxVERTICAL)
		m_listBoxPopup1 = New wxListBox.Create(m_panel5, ID_lb1, Null)

		bSizer12.Add(m_listBoxPopup1, 0, wxALL, 5)

		m_listBoxPopup2 = New wxListBox.Create(m_panel5, ID_lb2, Null)

		bSizer12.Add(m_listBoxPopup2, 0, wxALL, 5)

		m_listBoxNoPopup = New wxListBox.Create(m_panel5, wxID_ANY, Null)

		bSizer12.Add(m_listBoxNoPopup, 0, wxALL, 5)

		m_listCtrlMainTask = New wxListCtrl.Create(m_panel5, ID_MainTask,,,,, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES)
		bSizer12.Add(m_listCtrlMainTask, 0, wxALL, 5)

		m_panel5.SetSizer(bSizer12)
		m_panel5.Layout()
		bSizer11.Add(m_panel5, 1, wxEXPAND | wxALL, 5)

		SetSizer(bSizer11)
		Layout()

'		Connect(ID_lb1, wxEVT_RIGHT_UP, _RightClickForPopup)
'		Connect(ID_lb2, wxEVT_RIGHT_UP, _RightClickForPopup)
		
		m_listBoxPopup1.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
		m_listBoxPopup2.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
		m_listCtrlMainTask.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
	
	End Method

	Function _RightClickForPopup(event:wxEvent)
		MyFrame2Base(event.sink).RightClickForPopup(wxMouseEvent(event))

	End Function

	Method RightClickForPopup(event:wxMouseEvent)
		DebugLog "Please override MyFrame2.RightClickForPopup()"

		event.Skip()
	End Method

End Type


TestPopupsMain.bmx
'
' Example application stub generated by wxCodeGen v0.96 : 25 Feb 2008 20:01:20
'
SuperStrict

Framework wx.wxApp

Import "TestPopups.bmx"
Import brl.filesystem
Import brl.system

Const Menu_Add_SelectorType:Int = 100
Const Menu_Edit_SelectorType:Int = 101
Const Menu_Delete_SelectorType:Int = 102

New MyApp.run()

Type MyApp Extends wxApp

	Field frame:MyFrame2
	
	Method OnInit:Int()

?macos
		' make the default Mac font for controls not so big
		wxSystemOptions.SetOption(wxWINDOW_DEFAULT_VARIANT, wxWINDOW_VARIANT_SMALL)
?
		wxInitAllImageHandlers()

		wxImage.AddHandler( New wxXPMHandler ) ' for Mac/Win32 (it is default on Linux)

		Local frame:MyFrame2 = MyFrame2(New MyFrame2.Create(, , "Test Popup Menu Selection"))

		frame.show()
		
		SetTopWindow(frame)

		Return True
	End Method

End Type



Type MyFrame2 Extends MyFrame2Base

	Method OnInit()
		Super.OnInit()

		
'		ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)
		m_listBoxPopup1.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu)', Null, Self)
		' intercept all menu events And Log them in this custom event handler
		PushEventHandler(New MyEvtHandler.Create(Self))
	End Method

	Method RightClickForPopup(event:wxMouseEvent)
	DebugLog "this has evert.GetID() = " + event.GetID()
		Select event.GetId()

		    Case ID_lb1
        	DebugLog "You clicked on ListBox1"

    		Case ID_lb2
        	DebugLog "You clicked on ListBox2"

    		Case ID_MainTask
        	DebugLog "You clicked on ListCtrl"

		End Select		
		
	End Method

	Function OnContextMenu(event:wxEvent)
		Local frame:MyFrame2 = MyFrame2(event.parent)
		Local x:Int, y:Int
		
		wxContextMenuEvent(event).GetPosition(x, y)
		' This line makes sure the popup menu is positioned where the mouse is.
		frame.ScreenToClient(x, y)
		' This line displays the popup menu
		frame.ShowContextMenu(x, y)
	End Function
	
	Method ShowContextMenu(x:Int, y:Int)
		Local menu:wxMenu = New wxMenu.Create()
		
		menu.Append(Menu_Add_SelectorType, "Add a NEW Selector Type")
		menu.Append(Menu_Edit_SelectorType, "Edit the highlighted Selector Type")
		menu.AppendSeparator()
		menu.Append(Menu_Delete_SelectorType, "Delete the highlighted Selector Type")
		
		PopupMenu(menu, x, y)
		
		menu.Free()
	End Method
	
End Type

' A small helper type which intercepts all menu events And logs them
Type MyEvtHandler Extends wxEvtHandler

	Field frame:MyFrame2
	
	Method Create:MyEvtHandler(_frame:MyFrame2)
		frame = _frame
		Return MyEvtHandler(CreateHandler())
	End Method
	
	Method OnInit()
	    Connect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, OnMenuEvent)
	End Method
		
	Function OnMenuEvent(event:wxEvent)
		DebugLog "Popup Menu item Chosen"
		Select event.GetId()

'		    Case Menu_Add_SelectorType
 '       	DebugLog "You clicked on ADD"

'    		Case ID_lb2
 '       	DebugLog "You clicked on Fred!"

		End Select	
'		MyEvtHandler(event.parent).frame.LogMenuEvent(event)
		
		event.Skip()
	End Function

End Type



You have two sets of Connect/Any() plugged into a right-down/context menu event.
Is that what you want?

The first thing to happen will be the Right-down, which, if you want it to get to the context menu event, you will have to Skip() - otherwise it is consumed and will not advance to be further processed.


If you remove the Connects() for Right-Down, and change your context menu connect to :
Connect(ID_lb1, wxEVT_CONTEXT_MENU, OnContextMenu)

The menu opens as expected on the first list box.

Or, you might use this instead :
m_listBoxPopup2.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)

which connects listbox2 to a context menu event. Notice here though, that you require to pass the Frame as the "sink" parameter, since you want that reference back during the callback (which you access via event.sink).
In this case, you will need to change your callback function to use the sink instead :
	Function OnContextMenu(event:wxEvent)
		Local frame:MyFrame2 = MyFrame2(event.sink)

since "parent" will be the listbox.

In normal use, sink and parent are the same object.
Parent tends to be the object that the connect belongs to. However, the sink param of Connect enables you to add another object reference to the event, which can be very useful, as is the case in the above example.

Thanks Bruce,
Got it sorted now.
So ListBox 1 responds to the Right_Click_Down event and the menu event, ListBox 2 just responds to the Right_Click_Down event, ListBox 3 doesn't respond to anything, and finally the ListCtrl responds to both events.

The menu only displays for these specific controls.

Each control has a specific menu. I have added a case statement for lb2 even though it is not called because it isn't connected. This was just to prove it to myself.

Finished Sample.

Cheers
Glenn

TestPopups.bmx
'
' BlitzMax code generated with wxCodeGen v0.96 : 25 Feb 2008 23:22:05
' 
SuperStrict

Import wx.wxFrame
Import wx.wxListBox
Import wx.wxListCtrl
Import wx.wxPanel
Import wx.wxWindow
Import wx.wxMouseEvent

Type MyFrame2Base Extends wxFrame

	Field m_panel5:wxPanel
	Field m_listBoxPopup1:wxListBox
	Field m_listBoxPopup2:wxListBox
	Field m_listBoxNoPopup:wxListBox
	Field m_listCtrlMainTask:wxListCtrl
	

	Const ID_lb1:Int = 1000
	Const ID_lb2:Int = 1001
	Const ID_MainTask:Int = 2000
	
	Method Create:MyFrame2Base(parent:wxWindow = Null,id:Int = wxID_ANY, title:String = "", x:Int = -1, y:Int = -1, w:Int = 800, h:Int = 500, style:Int = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL)
		Return MyFrame2Base(Super.Create(parent, id, title, x, y, w, h, style))
	End Method

	Method OnInit()

		Local bSizer11:wxBoxSizer
		bSizer11 = New wxBoxSizer.Create(wxVERTICAL)
		m_panel5 = New wxPanel.Create(Self, wxID_ANY,,,,, wxTAB_TRAVERSAL)

		Local bSizer12:wxBoxSizer
		bSizer12 = New wxBoxSizer.Create(wxVERTICAL)
		m_listBoxPopup1 = New wxListBox.Create(m_panel5, ID_lb1, Null)

		bSizer12.Add(m_listBoxPopup1, 0, wxALL, 5)

		m_listBoxPopup2 = New wxListBox.Create(m_panel5, ID_lb2, Null)

		bSizer12.Add(m_listBoxPopup2, 0, wxALL, 5)

		m_listBoxNoPopup = New wxListBox.Create(m_panel5, wxID_ANY, Null)

		bSizer12.Add(m_listBoxNoPopup, 0, wxALL, 5)

		m_listCtrlMainTask = New wxListCtrl.Create(m_panel5, ID_MainTask,,,,, wxLC_HRULES|wxLC_REPORT|wxLC_SINGLE_SEL|wxLC_VRULES)
		bSizer12.Add(m_listCtrlMainTask, 0, wxALL, 5)

		m_panel5.SetSizer(bSizer12)
		m_panel5.Layout()
		bSizer11.Add(m_panel5, 1, wxEXPAND | wxALL, 5)

		SetSizer(bSizer11)
		Layout()

		m_listBoxPopup1.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
		m_listBoxPopup2.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
		m_listCtrlMainTask.ConnectAny(wxEVT_RIGHT_DOWN, _RightClickForPopup, Null, Self)
	
	End Method

	Function _RightClickForPopup(event:wxEvent)
		MyFrame2Base(event.sink).RightClickForPopup(wxMouseEvent(event))

	End Function

	Method RightClickForPopup(event:wxMouseEvent)
		DebugLog "Please override MyFrame2.RightClickForPopup()"

		event.Skip()
	End Method

End Type


TestPopupsMain.bmx
'
' Example application stub generated by wxCodeGen v0.96 : 25 Feb 2008 20:01:20
'
SuperStrict

Framework wx.wxApp

Import "TestPopups.bmx"
Import brl.filesystem
Import brl.system

Const Menu_Add_SelectorType:Int = 100
Const Menu_Edit_SelectorType:Int = 101
Const Menu_Delete_SelectorType:Int = 102

Global ObjectMenuClicked:Int

New MyApp.run()

Type MyApp Extends wxApp

	Field frame:MyFrame2
	
	Method OnInit:Int()

?macos
		' make the default Mac font for controls not so big
		wxSystemOptions.SetOption(wxWINDOW_DEFAULT_VARIANT, wxWINDOW_VARIANT_SMALL)
?
		wxInitAllImageHandlers()

		wxImage.AddHandler( New wxXPMHandler ) ' for Mac/Win32 (it is default on Linux)

		Local frame:MyFrame2 = MyFrame2(New MyFrame2.Create(, , "Test Popup Menu Selection"))

		frame.show()
		
		SetTopWindow(frame)

		Return True
	End Method

End Type



Type MyFrame2 Extends MyFrame2Base

	Method OnInit()
		Super.OnInit()

		m_listBoxPopup1.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)
		m_listCtrlMainTask.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)
		' intercept all menu events And Log them in this custom event handler
		PushEventHandler(New MyEvtHandler.Create(Self))

	End Method

	Method RightClickForPopup(event:wxMouseEvent)

		DebugLog "this has evert.GetID() = " + event.GetID()
		Select event.GetId()

		    Case ID_lb1
        		DebugLog "You clicked on ListBox1"
				ObjectMenuClicked = ID_lb1
				
    		Case ID_lb2
        		DebugLog "You clicked on ListBox2"
				ObjectMenuClicked = ID_lb2

    		Case ID_MainTask
        		DebugLog "You clicked on ListCtrl"
				ObjectMenuClicked = ID_MainTask

		End Select		
		
	End Method

	Function OnContextMenu(event:wxEvent)
		Local frame:MyFrame2 = MyFrame2(event.sink)
		Local x:Int, y:Int
		
		wxContextMenuEvent(event).GetPosition(x, y)
		' This line makes sure the popup menu is positioned where the mouse is.
		frame.ScreenToClient(x, y)
		' This line displays the popup menu
		frame.ShowContextMenu(x, y)
	End Function
	
	Method ShowContextMenu(x:Int, y:Int)
		Local menu:wxMenu = New wxMenu.Create()
		
		Select ObjectMenuClicked 
			Case ID_lb1
				menu.Append(Menu_Add_SelectorType, "Add a NEW lb1")
				menu.Append(Menu_Edit_SelectorType, "Edit the highlighted lb1")
				menu.AppendSeparator()
				menu.Append(Menu_Delete_SelectorType, "Delete the highlighted lb1")
			Case ID_lb2
				menu.Append(Menu_Add_SelectorType, "Add a NEW lb2")
				menu.Append(Menu_Edit_SelectorType, "Edit the highlighted lb2")
				menu.AppendSeparator()
				menu.Append(Menu_Delete_SelectorType, "Delete the highlighted lb2")
			Case ID_MainTask
				menu.Append(Menu_Add_SelectorType, "Add a NEW MainTask")
				menu.Append(Menu_Edit_SelectorType, "Edit the highlighted MainTask")
				menu.AppendSeparator()
				menu.Append(Menu_Delete_SelectorType, "Delete the highlighted MainTask")
		End Select
		
		PopupMenu(menu, x, y)
		
		menu.Free()
	End Method
	
End Type

' A small helper type which intercepts all menu events And logs them
Type MyEvtHandler Extends wxEvtHandler

	Field frame:MyFrame2
	
	Method Create:MyEvtHandler(_frame:MyFrame2)
		frame = _frame
		Return MyEvtHandler(CreateHandler())
	End Method
	
	Method OnInit()
	    Connect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, OnMenuEvent)
	End Method
		
	Function OnMenuEvent(event:wxEvent)
		DebugLog "Popup Menu item Chosen"
		Select event.GetId()

		    Case Menu_Add_SelectorType
        	DebugLog "You clicked on ADD"

		End Select	
		
		event.Skip()
	End Function

End Type



Hi Glenn.

Here on my WinXP SP2 only the first and the last listbox shows the menu. the 2nd and 3rd does nothing? Any idea whats wrong?

greez
tom

run in debug mode.
First and Last show a debuglog statement for the right_mouse_down event and then the menu for each control pops up.
Second only shows a debuglog statement for the right_mouse_down event BUT doesn't show the menu (even though i added the appropriate menu creation lines) because i didn't add a ConnectAny line for it.
Type MyFrame2 Extends MyFrame2Base

	Method OnInit()
		Super.OnInit()

		m_listBoxPopup1.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)
		m_listCtrlMainTask.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)
		' intercept all menu events And Log them in this custom event handler
		PushEventHandler(New MyEvtHandler.Create(Self))


If you want it to respond then add
m_listBoxPopup2.ConnectAny(wxEVT_CONTEXT_MENU, OnContextMenu, Null, Self)

to the OnInit method above.

I left it out just to prove to myself that i was understanding the process properly.

Cheers
Glenn

Hi Glenn,

now it works with the second one also...

the thing is, i can't compile my programm with debug mode on. i've no idea where the error message comes from. maybe it seems like a graphic thing or so...

Linking:TestPopupsMain.debug.exe
C:/Programme/BlitzMax/mod/brl.mod/dxgraphics.mod/dxgraphics.debug.win32.x86.a(d3d7graphics.bmx.debug.win32.x86.o): undefined reference to `pub_win32_WNDCLASS'
Build Error: Failed to link D:/TestPopupsMain.debug.exe
Process complete

help requested

greez
tom

That's strange eh? What happens if you also Import Pub.Win32 ?

HEy Brucey,

still the same error, with Import Pub.Win32:

Linking:TestPopupsMain.debug.exe
C:/Programme/BlitzMax/mod/brl.mod/dxgraphics.mod/dxgraphics.debug.win32.x86.a(d3d7graphics.bmx.debug.win32.x86.o): undefined reference to `pub_win32_WNDCLASS'


..- strange -.......*lol*


greez
tom