Skip to content

Blank buttons appear on toolbar with multiple trackbars after window is resized in WinAPI HighGUI backend #22837

@dan-masek

Description

@dan-masek

Windows 10 (and likely other Windows versions)
OpenCV 4.x and 3.x

C++ code to reproduce:

#include "opencv2/highgui.hpp"

int main()
{
    std::string const window_name{ "TrackBars" };
    cv::namedWindow(window_name, cv::WINDOW_NORMAL);
    cv::resizeWindow(window_name, {500, 200 });
    cv::createTrackbar("Slider 1", window_name, nullptr, 255);
    cv::createTrackbar("Slider 2", window_name, nullptr, 255);
    cv::createTrackbar("Slider 3", window_name, nullptr, 255);
    cv::createTrackbar("Slider 4", window_name, nullptr, 255);
    cv::waitKey();
    return 0;
}

Run that...
image

resize the window so it's wide enough to hold 2 trackbars side-by-side -- all good ..
image

and then resize the window so it's wide enough to hold 3 trackbars side-by-side.
image


The problem is in the WM_NCCALCSIZE message handler in HGToolbarProc, specifically in line 2072:

case WM_NCCALCSIZE:
{
LRESULT ret = CallWindowProc(window.toolbar.toolBarProc, hwnd, uMsg, wParam, lParam);
int rows = (int)SendMessage(hwnd, TB_GETROWS, 0, 0);
if (window.toolbar.rows != rows)
{
SendMessage(window.toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
auto& trakbars = window.toolbar.trackbars;
for (auto it = trakbars.begin(); it != trakbars.end(); ++it)
{
auto trackbar = *it;
CV_Assert(trackbar);
RECT rect = { 0 };
SendMessage(window.toolbar.toolbar, TB_GETITEMRECT,
(WPARAM)trackbar->id, (LPARAM)&rect);
MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top,
rect.right - rect.left - HG_BUDDY_WIDTH,
rect.bottom - rect.top, FALSE);
MoveWindow(trackbar->buddy, rect.left, rect.top,
HG_BUDDY_WIDTH, rect.bottom - rect.top, FALSE);
}
window.toolbar.rows = rows;
}
return ret;
}

With 4 toolbars as an example scenario, when going from 2 to 3 columns, the number of rows stays the same, which means that the trackbar and buddy control windows don't get re-positioned. Since the idea is for those two windows to completely cover the placeholder buttons, and they didn't get re-positioned, we get to see the placeholder.

I think the easiest way to deal with this is just get rid of the if and have it re-position the controls one each call. It seems to behave fine like that, and the overhead doesn't seem noticeable even in debug mode.

image


One more thing I've noticed -- that SendMessage on line 2074:
SendMessage(window.toolbar.toolbar, TB_BUTTONCOUNT, 0, 0);
seems rather pointless, given that the result is ignored. Unless this is meant to have some unexplained side-effect, I'd propose to get rid of it.

It appears to be 13+ year old piece of code. Removing it doesn't appear to have any negative effects on my system.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions