-
-
Notifications
You must be signed in to change notification settings - Fork 56.5k
Incorrectly sized and rendered trackbars (in some cases) in WinAPI HighGUI backend #22767
Description
Windows 10 (and likely other versions)
OpenCV 4.6.0, going back at least until 3.3 (haven't tried further TBH)
Reference: https://stackoverflow.com/q/74358897/3962537
C++ code to reproduce:
#include "opencv2/highgui.hpp"
int main()
{
std::string const window_name{ "TrackBars" };
cv::namedWindow(window_name, cv::WINDOW_AUTOSIZE);
// cv::namedWindow(window_name, cv::WINDOW_NORMAL);
cv::resizeWindow(window_name, {500, 100 });
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::createTrackbar("Slider 5", window_name, nullptr, 255);
cv::createTrackbar("Slider 6", window_name, nullptr, 255);
cv::resizeWindow(window_name, { 500, 300 });
cv::waitKey();
return 0;
}
Examples with various initial window heights (100, 200, and 10 respectively:



If you switch the window mode to WINDOW_NORMAL, and resize the window with the mouse, you can even achieve this level of weirdness:

As trackbars are added to the toolbar (initially set up so that each trackbar fills one row), the toolbar control expands vertically, consuming the available client area of the parent window. Placeholder buttons are added to the toolbar to determine where the trackbar and buddy control will be located. Upon creating, the placeholder buttons are sized to current window width by the following code:
opencv/modules/highgui/src/window_w32.cpp
Lines 2477 to 2482 in 2aad039
| RECT rect = { 0 }; | |
| GetClientRect(window.hwnd, &rect); | |
| tbis.cx = (unsigned short)(rect.right - rect.left); | |
| SendMessage(window.toolbar.toolbar, TB_SETBUTTONINFO, | |
| (WPARAM)tbs.idCommand, (LPARAM)&tbis); |
Problem lies in line 2478 -- we use window.hwnd to determine the width to which the button should be sized. However, that HWND is the client area of the parent, which is getting squished out of the toolbar in non-client area. Once the toolbar grows bigger than what the window can hold, the client area becomes 0 (as in rect contains all zeros after the call to GetClientRect).
It appears that when cx is set to 0, the toolbar control sets the width to some default, perhaps one determined by the length of this string:
opencv/modules/highgui/src/window_w32.cpp
Lines 78 to 79 in 2aad039
| static const char* trackbar_text = | |
| " "; |
Since the button sizes are never changed after creation, the incorrect sizes remain even after the window is resized by the two available methods.
The solution turns out to be quite simple.
GetClientRect(window.toolbar.toolbar, &rect);
i.e. use the width of the client area of the toolbar control itself. With this change applied, I can no longer reproduce any of the odd situations shown above.