Hi all,
is it possible to trigger an event on the tabpage after pressing the middle mouse button (scroll wheel) - e.g. to close it - as in the browser?
I can't find a way...
Regards,
Tomáš
Hi all,
is it possible to trigger an event on the tabpage after pressing the middle mouse button (scroll wheel) - e.g. to close it - as in the browser?
I can't find a way...
Regards,
Tomáš
* * * Edited * * * Revised to close the tab that the middle/wheel button clicks instead of the current tab.
Hi, Tomáš -
I was able to get this to work by adding two events to the tab control. Also needed are two Windows API-compatible structures and three external function declarations for Windows API functions:
A Windows API-compatible POINT structure is needed first. I've called it s_point:
type s_point from structure
long x
long y
end type
Next, another Windows-compatible TCHITTESTINFO (Tab Control Hit Test Info) structure I've named s_tchittestinfo:
type s_tchittestinfo from structure
s_point pt
unsignedlong flags
end type
Also needed are three external function declarations for some Windows API functions:
FUNCTION Boolean GetCursorPos ( &
REF s_point lpPoint &
) LIBRARY "user32.dll"
FUNCTION Boolean ScreenToClient ( &
Longptr hWnd, &
REF s_point lpPoint &
) LIBRARY "user32.dll"
FUNCTION Longptr TabCtrl_HitTest ( &
Longptr hWnd, &
UnsignedLong Msg, &
Longptr wParam, &
REF s_tchittestinfo lParam &
) LIBRARY "user32.dll" ALIAS FOR "SendMessageW"
Now to the code. You need a Boolean instance variable:
Boolean ib_mbuttondown = False
Create a tab control user event named mbuttondown mapped to pbm_mbuttondown:
// Keeps track of user pressing the middle mouse button on/over a tab, in order
// that the MButtonUp event will know it is OK to close the tab that is clicked.
ib_mbuttondown = True
Return 0
Lastly, create a tab control user event named mbuttonup mapped to pbm_mbuttonup:
// There is no mapped "middle mouse button click" event available, only down/up events.
// This script ignores a middle mouse button up event UNLESS the user also caused a
// middle mouse button down event. This prevents the up event from taking any action if
// the user presses the middle mouse button down somewhere else, moves the mouse over a
// tab in the tab control, then releases the middle mouse button.
Constant UnsignedLong TCM_HITTEST = 4877 // Message ID for tab control "hit test" message.
Boolean lb_rc
Integer li_num_tabs, li_tab_2b_closed, li_tab_2b_selected
Longptr lp_rc
s_tchittestinfo lstr_hti // This structure contains a WinAPI "point" structure.
// Do nothing if the user did not press the middle mouse button down over a tab.
If Not ib_mbuttondown Then Return 0
ib_mbuttondown = False
// Don't close the last/only tab page.
li_num_tabs = UpperBound(This.Control[])
If li_num_tabs < 2 Then Return 0
// Determine which tab the cursor is currently over (if any). To accomplish this,
// use Windows API functions to (1) Obtain the cursor's position in screen coordinates,
// (2) convert that point to client (i.e., tab control) coordinates, and (3) perform a
// "hit test" that will tell us the tab index the cursor is over.
lb_rc = GetCursorPos(lstr_hti.pt)
lb_rc = ScreenToClient(Handle(This),lstr_hti.pt)
lp_rc = TabCtrl_HitTest(Handle(This),TCM_HITTEST,0,lstr_hti)
// A return code of -1 means the cursor is not over a tab, so take no action.
If lp_rc = -1 Then Return 0
// In Windows, the tab index begins with zero, but in PB the tab index begins with one.
li_tab_2b_closed = lp_rc + 1
// Assume the current tab will remain the current tab after one is closed.
li_tab_2b_selected = This.SelectedTab
// Determine which tab page should be selected after the requested tab page is closed.
If li_tab_2b_closed = This.SelectedTab Then
// The current tab is to be closed. After it is closed, the tab that is to the
// immediate right will become the current tab (thus, the tab index will not change).
//
// However, it there is not a tab to the immediate right, the tab to the immediate
// left needs to become the selected/current tab.
If li_tab_2b_selected = li_num_tabs Then li_tab_2b_selected --
ElseIf li_tab_2b_closed < li_tab_2b_selected Then
// The tab to be closed is to the left of the current tab. The current tab will remain
// the current tab, but its tab index will decrease by 1.
li_tab_2b_selected --
End If
// Close the requested tab page and select the same or different tab. If you do not perform
// the SelectTab, then an empty tab control might be displayed.
This.CloseTab(This.Control[li_tab_2b_closed])
This.SelectTab(li_tab_2b_selected)
Return 0
At runtime, if you click the middle mouse button (wheel) while the cursor is over any of the tabs, the clicked tab page will be closed.
I hope this does what you are looking for.
Best regards, John
I have figured out how to determine which tab the cursor is over when the middle/wheel button is clicked, so I have updated my earlier response to reflect the necessary code changes. The code is not difficult, but finding the right WinAPI calls to utilize and coding to use them was a challenge.
Enjoy!
Hi John,
An excellent piece of code, thank you very much! It works as you say - it closes the currently selected tab page.
I will try to tweak it to close the tab under the mouse cursor - not necessarily the selected one.
Best regards,
Tomáš