On Fri, 5 Aug 2022 09:41:07 +0100
jon bird <
ne...@onasticksoftware.co.uk> wrote:
> Hi,
>
> I seem to have encountered a slight issue where wxListCtrl columns are
> not quite sized correctly when scrollbars come into play. Initially I
> thought this was down to using wxLIST_AUTOSIZE instead of
> wxLIST_AUTOSIZE_USEHEADER (as per the discussion around TRAC ticket
> #10326), that seemed to initially improve things but was still seeing
> occasions when I was getting a horizontal scrollbar appear
> unexpectedly.
>
> After a bit of further digging, it seems that everything is fitting
> correctly until there are more items in the list that then require a
> vertical scrollbar to be enabled. At which point a horizontal
> scrollbar is also enabled - just enough to scroll a character or two
> into view.
>
> My guess would be that the sizing logic isn't compensating for this
> condition - taking into account the width of the vertical scrollbar.
>
> This is on MSW, using wxWidgets 3.1.5, using a non-virtual listtrl
> where all the items are populated at the point the window is
> constructed.
>
I posted the above a few months back, didn't take it any further at the
time because it wasn't a big issue and I had more important stuff to
do. However I have bumped into (or related to) the issue a couple of
times since and have delved a bit further.
In my latest encounter, it's a slightly different scenario, here I have
a small (headerless) list control with two columns. I want each column
to occupy 50% of the total available width. I set this up when the
dialog is constructed as follows:
wxSize SelectorSize(m_MultiDetails->GetClientSize());
m_MultiDetails->SetColumnWidth(MultiLViewColTitle,
(float)SelectorSize.GetX() / 2 );
m_MultiDetails->SetColumnWidth(MultiLViewColArtist,
(float)SelectorSize.GetX() / 2 );
At this point the list control is empty, as items are added everything
works as expected until there is not enough visible area to display all
items - at which point a vertical scroll bar is added AND a horizontal
scrollbar (in effect the same behaviour as described in my original
post).
Having thought about it, this behaviour makes sense: at the point the
vertical scrollbar is added, the horizontal client area has been
reduced, hence the inclusion of the x-axis scrollbar (I'm not totally
convinced it is the desired behaviour when the column width is set via
wxLIST_AUTOSIZE but in this case, where I've manually set them, it
does).
Since this isn't the behaviour I want, I planned to deal with it
by checking for when the vertical scrollbar gets enabled as part of the
logic that gets invoked when a new item is added - essentially by
calling wxWindow::HasScrollbar (on the wxListCtrl). I can then resize
the column widths accordingly. But this _always_ returns false even if
a vertical scrollbar is present. Here's the code which implements this:
bool wxWindowBase::CanScroll(int orient) const
{
return (m_windowStyle &
(orient == wxHORIZONTAL ? wxHSCROLL : wxVSCROLL)) != 0;
}
bool wxWindowBase::HasScrollbar(int orient) const
{
// if scrolling in the given direction is disabled, we can't have
the
// corresponding scrollbar no matter what
if ( !CanScroll(orient) )
return false;
const wxSize sizeVirt = GetVirtualSize();
const wxSize sizeClient = GetClientSize();
return orient == wxHORIZONTAL ? sizeVirt.x > sizeClient.x
: sizeVirt.y > sizeClient.y;
}
As can be seen, this totally relies on the window style being set with
the appropriate scrollbar, always returning false if not. Hence it's
never going to yield correct information on a control which
dynamically enables/disables scrollbars.
My initial workaround attempt was to bypass that initial check and see
what the computation that would then be performed would yield but
GetClientSize and GetVirtualSize always come back with the same numbers
so the result likewise comes back false. This same logic appears to be
in play with the latest 3.2.1 release.
My current workaround has been to use native Win32 code which does then
yield the expected result:
SCROLLBARINFO ScrollBarInfo;
ScrollBarInfo.cbSize = sizeof(SCROLLBARINFO);
if (::GetScrollBarInfo(AudioQueueListBox->GetHWND(), OBJID_VSCROLL,
&ScrollBarInfo))
{
if (!(ScrollBarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE))
ScrollState = true ;
}
I think something like this needs to be included as part of the scroll
detection logic however I've got zero experience on GTK and the like so
don't know what that would look like for those.