Corrected wxTreeCtrl::DoGetBestSize(), added DoGetBestClientWidth (PR #26097)

44 views
Skip to first unread message

RobertRoeb

unread,
Jan 13, 2026, 5:13:56 AMJan 13
to wx-...@googlegroups.com, Subscribed

For the generic wxTreeCtrl:

  • Corrected ::DoGetBestSize(), added DoGetBestClientWidth
  • Adapted both to the same calculation of the required virtual size that is used in AdjustScrollbars() removing the need for adding magic 4
  • Now, importantly, wxTreeBook actually calls a real DoGetBestClientWidth() based on a known height and can correctly figure out if a vertical scrollbar is needed
  • This removes the ugly horizontal scrollbar in wxTreeBook when a the horizontal scrollbar appears.
  • Tested on macOS 26

You can view, comment on, or merge this pull request online at:

  https://github.com/wxWidgets/wxWidgets/pull/26097

Commit Summary

  • 178a27f Corrected wxGenericTreeCtrl::DoGetBestSize(), added DoGetBestClientWidth()

File Changes

(2 files)

Patch Links:


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097@github.com>

RobertRoeb

unread,
Jan 24, 2026, 8:58:40 AMJan 24
to wx-...@googlegroups.com, Subscribed
RobertRoeb left a comment (wxWidgets/wxWidgets#26097)

This image illustrates the problem: when all branches are expanded, a horizontal scrollbar appears because the current code miscalculated the width. This looks broken and you cannot even add some manual extra space.

Treebook.Tahoe.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/c3794688782@github.com>

RobertRoeb

unread,
Jan 24, 2026, 9:03:12 AMJan 24
to wx-...@googlegroups.com, Push

@RobertRoeb pushed 1 commit.


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/before/178a27f71f72ab31a8bc4cd206b02145d7cb8e28/after/542f13a50ca2463c2c35d2990458cb68f4f56466@github.com>

VZ

unread,
Jan 24, 2026, 7:38:42 PMJan 24
to wx-...@googlegroups.com, Subscribed

@vadz requested changes on this pull request.

Thanks but, again, it looks like there is an "obvious" (unless I'm missing something, which is perfectly possible, but please explain what to me then) better way of doing this by defining DoGetBestClientSize() and reusing it from the new function.


In src/generic/treectlg.cpp:

> +    // add the border
+    const wxSize& borderSize = GetWindowBorderSize();
+    size.x += borderSize.x;
+    size.y += borderSize.y;

Could we avoid this by overriding DoGetBestClientSize() instead of DoGetBestSize()?

And if not, this should be written simply as

size += GetWindowBorderSize();

In src/generic/treectlg.cpp:

> +    // make sure all positions are calculated as normally this only done during
+    // idle time but we need them for base class DoGetBestSize() to return the
+    // correct result
+    wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions();
+
+    wxSize size = wxTreeCtrlBase::DoGetBestSize();
+
+    // DoGetBestClientWidth calculates if a vertical scrollbar is
+    // needed based on the given height
+
+    // Use the calculation from AdjustMyScrollbars()
+    size.y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+    size.x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+    size.x = (size.x / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;
+    size.y = (size.y / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;

This is just an exact copy of DoGetBestClientSize(), right? Why not simply call it from here?


In src/generic/treectlg.cpp:

>  
-    // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or
-    // scrollbars still appear
-    const wxSize& borderSize = GetWindowBorderSize();
+    // Use the calculation from AdjustMyScrollbars()

Could we, perhaps, add a function like wxSize GetTotalAreaFromClientArea(wxSize) and use it both here and in AdjustMyScrollbars()?


In src/generic/treectlg.cpp:

> +    size.x = (size.x / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;
+    size.y = (size.y / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;

This rounds up, unlike AdjustMyScrollbars() which rounds down. A comment explaining why this is the right thing to do here but not there would be quite helpful because this doesn't seem obvious to me.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3703043981@github.com>

RobertRoeb

unread,
Jan 31, 2026, 9:06:13 AMJan 31
to wx-...@googlegroups.com, Subscribed

@RobertRoeb commented on this pull request.


In src/generic/treectlg.cpp:

> +    size.x = (size.x / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;
+    size.y = (size.y / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;

I think I am using the same calculations, so I must be overlooking something. Please point me to it.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3732680536@github.com>

RobertRoeb

unread,
Jan 31, 2026, 9:17:46 AMJan 31
to wx-...@googlegroups.com, Subscribed

@RobertRoeb commented on this pull request.


In src/generic/treectlg.cpp:

> +    // add the border
+    const wxSize& borderSize = GetWindowBorderSize();
+    size.x += borderSize.x;
+    size.y += borderSize.y;

So maybe for background, this is the sequence of calls that I am trying to fix:
a) wxBookCtrlBase::DoSize() wants to lay out the controller (tree control on the left) and the page (right)
b) it calls wxBookCtrlBase::GetControllerSize() to determine the size of the controller
c) that calls m_bookctrl->GetBestWidth(sizeClient.y); to allow the controller to figure out how much it has to stretch out horizontally
d) wxWindowBase::GetBestWidth(int height) calls DoGetBestClientWidth(height);

Therefore, I had to override wxGenericTreeCtrl::DoGetBestClientWidth(height) to make it properly report the width of the tree depending on whether or not it has a vertical scrollbar. This function needs to know what is essentially the primary direction of expansion, in our case the tree should expand horizontally to not have a horizontal scrollbar and should use scrolling vertically (if it does not fit, obviously).

DoGetBestSize() calculates the size so that (or as if) no scrollbar are present in either direction, that is a different task.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3732719039@github.com>

VZ

unread,
Jan 31, 2026, 5:55:35 PMJan 31
to wx-...@googlegroups.com, Subscribed

@vadz commented on this pull request.


In src/generic/treectlg.cpp:

> +    size.x = (size.x / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;
+    size.y = (size.y / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;

Sorry, it looks like I misread the code, either here or there, because rereading it now I don't see the difference. But this just (completely inadvertently) proves my point about having GetTotalAreaFromClientArea(): if we called it from both places, it would be perfectly obvious that the calculation is the same.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3733813032@github.com>

VZ

unread,
Jan 31, 2026, 5:59:41 PMJan 31
to wx-...@googlegroups.com, Subscribed

@vadz commented on this pull request.


In src/generic/treectlg.cpp:

> +    // add the border
+    const wxSize& borderSize = GetWindowBorderSize();
+    size.x += borderSize.x;
+    size.y += borderSize.y;

I understand that it's not enough to override only DoGetBestSize(). The comment above only said that we could override DoGetBestClientSize() instead of it to avoid having to add borders manually.

Overridden version of DoGetBestClientWidth() would still remain (but hopefully reuse this one instead of duplicating it).


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3733820466@github.com>

VZ

unread,
Feb 11, 2026, 1:22:47 PM (11 days ago) Feb 11
to wx-...@googlegroups.com, Subscribed
vadz left a comment (wxWidgets/wxWidgets#26097)

Should I make the changes discussed above myself or is it not desirable to make them for some reason I'm missing?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/c3886152961@github.com>

RobertRoeb

unread,
4:16 AM (3 hours ago) 4:16 AM
to wx-...@googlegroups.com, Push

@RobertRoeb pushed 1 commit.

  • 33dd0a9 Factor code for better re-use


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/before/542f13a50ca2463c2c35d2990458cb68f4f56466/after/33dd0a98423ac1e15bcef136b16a1d5fd22221c7@github.com>

RobertRoeb

unread,
4:19 AM (3 hours ago) 4:19 AM
to wx-...@googlegroups.com, Subscribed

@RobertRoeb commented on this pull request.


In src/generic/treectlg.cpp:

> +    // make sure all positions are calculated as normally this only done during
+    // idle time but we need them for base class DoGetBestSize() to return the
+    // correct result
+    wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions();
+
+    wxSize size = wxTreeCtrlBase::DoGetBestSize();
+
+    // DoGetBestClientWidth calculates if a vertical scrollbar is
+    // needed based on the given height
+
+    // Use the calculation from AdjustMyScrollbars()
+    size.y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+    size.x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+    size.x = (size.x / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;
+    size.y = (size.y / PIXELS_PER_UNIT) * PIXELS_PER_UNIT;

There was no DoGetBestClientSize() so this question puzzled me for a while. I just added it and made DoGetBestSize() and DoGetClientBestWidth() use it.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3837094986@github.com>

RobertRoeb

unread,
4:19 AM (3 hours ago) 4:19 AM
to wx-...@googlegroups.com, Subscribed

@RobertRoeb commented on this pull request.


In src/generic/treectlg.cpp:

>  
-    // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or
-    // scrollbars still appear
-    const wxSize& borderSize = GetWindowBorderSize();
+    // Use the calculation from AdjustMyScrollbars()

I added this as a local function since it has no general use


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/26097/review/3837095537@github.com>

Reply all
Reply to author
Forward
0 new messages