1. Tomáš Podzimek
  2. PowerBuilder
  3. Wednesday, 10 April 2024 08:47 AM UTC

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áš

Accepted Answer
John Fauss Accepted Answer Pending Moderation
  1. Wednesday, 10 April 2024 15:01 PM UTC
  2. PowerBuilder
  3. # Permalink

* * * 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

Comment
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Thursday, 11 April 2024 23:27 PM UTC
  2. PowerBuilder
  3. # 1

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!

 

Comment
  1. Tomáš Podzimek
  2. Friday, 12 April 2024 16:17 PM UTC
Exquisite, 10 out of 10. You seem to like challenges, good for me :).

Thanks a lot.

Regards,

Tomáš
  1. Helpful
  1. John Fauss
  2. Friday, 12 April 2024 16:32 PM UTC
You're welcome. Yes, I do enjoy a challenge ;)
  1. Helpful
There are no comments made yet.
Tomáš Podzimek Accepted Answer Pending Moderation
  1. Thursday, 11 April 2024 07:16 AM UTC
  2. PowerBuilder
  3. # 2

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áš

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.