1. Ronnie Po
  2. PowerBuilder
  3. Wednesday, 19 May 2021 21:35 PM UTC

Does anyone know a way to get the coordinates and size of the tab part of a tabpage (i.e. the part that the user clicks to select that particular tabpage in a tab control)?

 

Miguel Leeuwe Accepted Answer Pending Moderation
  1. Thursday, 20 May 2021 09:09 AM UTC
  2. PowerBuilder
  3. # 1

Clicks where? Positions relative to what? (screen, parent object, window, etc.)

If on the tab label, you could use the selectionchanged event.

x, y, width and height should do it, but I have the feeling that it might be that I'm not understanding the question right.

regards

Comment
There are no comments made yet.
Ronnie Po Accepted Answer Pending Moderation
  1. Thursday, 20 May 2021 22:44 PM UTC
  2. PowerBuilder
  3. # 2

Hi Miguel,

I probably didn't state that very well. For example, I'm trying to figure out the position and size of the red squares in this window, relative to the window:

Long story short: we have an established app in which we sometimes alert the user by flashing different background colors on individual tabs. This worked well before the introduction of UI Themes. We are in the process of "theming" the app, but, unfortunately, that takes away our ability to dynamically change the background color of an individual tab.

We're just brainstorming possible workarounds, and were experimenting with the idea of placing a control (e.g. text and/or rectangle) over the tab areas to simulate changing the tab background color.

Comment
  1. Miguel Leeuwe
  2. Tuesday, 25 May 2021 09:28 AM UTC
Okay, so the questions remains the same: can't you create the exclusion for whichever object you want to apply it to?
  1. Helpful
  1. Ronnie Po
  2. Tuesday, 25 May 2021 17:17 PM UTC
Yes, of course, but as far as I know, a custom theme doesn't allow me to dynamically flash a color on and off at runtime.
  1. Helpful
  1. Ronnie Po
  2. Wednesday, 26 May 2021 02:29 AM UTC
Thanks for the suggestions, Miguel.
  1. Helpful
There are no comments made yet.
Benjamin Gaesslein Accepted Answer Pending Moderation
  1. Tuesday, 25 May 2021 07:58 AM UTC
  2. PowerBuilder
  3. # 3

Hi Ronnie,

Windows has a macro called TabCtrl_GetItemRect that will fill a RECT structure with the coordinates of the specified tab. But I guess you'd have to write a DLL implementing this first in order to actually use it in PB.

https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-tabctrl_getitemrect


The only appearance-related thing you can natively control in themed tabs is the icon so you might be able to flash that by replacing it with a different colored one. I haven't tried doing this at runtime but it's something that might be worth a shot.

Comment
  1. Ronnie Po
  2. Tuesday, 25 May 2021 17:14 PM UTC
Hi Benjamin,



Thanks for the pointer! I had a feeling that was the direction I would need to go.
  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Tuesday, 25 May 2021 19:20 PM UTC
  2. PowerBuilder
  3. # 4

Hi, Ronnie -

Benjamin's excellent suggestion does indeed work, and you don't need to create a custom DLL in order to accomplish this from PB.

Here's the external function declaration I used:

FUNCTION Longptr SendMessageTabItemRect ( &
   Longptr           hWnd, &
   UnsignedLong      Msg, &
   LongPtr           wParam, &
   REF s_winapi_rect lParam &
) LIBRARY "user32.dll" ALIAS FOR "SendMessageW"

The "trick" is to pass the WinAPI rectangle structure by reference as the LPARAM argument to the SendMessageW API function, so that the address of the structure gets passed and Windows can fill in the structure member values.

Here's code I used to call this external function:

ULong   lul_tabctrl_getitemrect = 4864 + 10 // = TCM_FIRST + 10
Longptr llptr_rc, llptr_htab
s_winapi_rect lstr_recttab1, lstr_recttab2

llptr_htab = Handle(tab_1)

llptr_rc = SendMessageTabItemRect(llptr_htab,lul_tabctrl_getitemrect,0,lstr_recttab1)

MessageBox('Tab Control GetItemRect for Tabpage 1', &
   'Left = ~t'+String(lstr_recttab1.l_left) + &
   '~r~nTop = ~t'+String(lstr_recttab1.l_top) + &
   '~r~nRight = ~t'+String(lstr_recttab1.l_right) + &
   '~r~nBottom = ~t'+String(lstr_recttab1.l_bottom) + &
   '~r~n~r~nRC = ' + String(llptr_rc))

llptr_rc = SendMessageTabItemRect(llptr_htab,lul_tabctrl_getitemrect,1,lstr_recttab2)

MessageBox('Tab Control GetItemRect for Tabpage 2', &
   'Left = ~t'+String(lstr_recttab2.l_left) + &
   '~r~nTop = ~t'+String(lstr_recttab2.l_top) + &
   '~r~nRight = ~t'+String(lstr_recttab2.l_right) + &
   '~r~nBottom = ~t'+String(lstr_recttab2.l_bottom) + &
   '~r~n~r~nRC = ' + String(llptr_rc))

Note the tab # argument is zero-based (the first tab is tab #0). The SendMessageW message # for the TabCtrl_GetItemRect is defined as TCM_FIRST (TCM = Tab Control Message)+ 10, or 4864 + 10 = 4874.

The rectangle structure member values are in pixels, of course. relative to the upper-left corner of the tab control.

The APi appears to work with non-standard tab positioning, not just when tabs are on the top. Be aware that if the tab area is "scrollable", you may need to recognize how this affects the values returned in the rectangle.

By obtaining the position of every tab and checking the tab position and multi-line properties, you can now dynamically determine the number of tab rows at execution time... an added benefit.

HTH, John

Comment
  1. Ronnie Po
  2. Wednesday, 26 May 2021 02:28 AM UTC
Hi John,

Thanks for posting your solution, which works perfectly!

I rarely (i.e. never) do much Win API coding, so I was looking at functions such as SystemParametersInfo() and would never have thought to look at SendMessage(). Very nice!
  1. Helpful
  1. Benjamin Gaesslein
  2. Wednesday, 26 May 2021 08:07 AM UTC
Ah, but of course! Nice work, John. I didn't think of using Sendmessage to send TCM_GETITEMRECT directly.

To get the number of tab rows directly, you could probably utilize the TCM_GETROWCOUNT message the same way.

  1. Helpful
  1. John Fauss
  2. Wednesday, 26 May 2021 13:59 PM UTC
The key clue was to look at the TabCtrl_GetItemRect macro, which I found in CommCtrl.h. The macro becomes:

(BOOL)SNDMSG((hwnd), TCM_GETITEMRECT, (WPARAM)(int)(i), (LPARAM)(RECT *)(prc))

- where "SNDMSG" translates to "SendMessage", then recognizing that the LPARAM argument to SendMessage was a pointer to a RECT structure. This was an interesting challenge, made possible only by your terrific tip to look at the TabCtrl_GetitemRect macro, Benjamin, so thank you for that!
  1. Helpful
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.