-
-
Notifications
You must be signed in to change notification settings - Fork 56.5k
Blank buttons appear on toolbar with multiple trackbars after window is resized in WinAPI HighGUI backend #22837
Description
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;
}
resize the window so it's wide enough to hold 2 trackbars side-by-side -- all good ..

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

The problem is in the WM_NCCALCSIZE message handler in HGToolbarProc, specifically in line 2072:
opencv/modules/highgui/src/window_w32.cpp
Lines 2067 to 2093 in 64aad34
| 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.
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.

