Window Close button Issue
If you try to use the Native Window Close button, the window is not responding. This behaviour can be reproduced in every cvui example. I workaround and was able to make borderless window using classic tricky windows api calls. Basically I modified the watch function (and lose linux compatibility with the inclusion of windows.h ). So if @Dovyski or other users find this code useful feel free to use or modified to make it a general solution. Let me know your thoughts,
inline void watch(const cv::String& theWindowName, bool theCreateNamedWindow, bool createBorder) {
cvui_context_t aContex;
if (theCreateNamedWindow) {
cv::namedWindow(theWindowName,0);
if (!createBorder)
{
HWND win_handle = FindWindow(0, theWindowName.c_str());
if (!win_handle)
{
printf("Failed FindWindow\n");
}
// Borderless
SetWindowLong(win_handle, GWL_STYLE, GetWindowLong(win_handle, GWL_EXSTYLE) | WS_EX_TOPMOST);
ShowWindow(win_handle, SW_SHOW);
}
}
aContex.windowName = theWindowName;
aContex.mouse.position.x = 0;
aContex.mouse.position.y = 0;
internal::resetMouseButton(aContex.mouse.anyButton);
internal::resetMouseButton(aContex.mouse.buttons[RIGHT_BUTTON]);
internal::resetMouseButton(aContex.mouse.buttons[MIDDLE_BUTTON]);
internal::resetMouseButton(aContex.mouse.buttons[LEFT_BUTTON]);
internal::gContexts[theWindowName] = aContex;
cv::setMouseCallback(theWindowName, handleMouse, &internal::gContexts[theWindowName]);
}

That borderless window looks gorgeous! :smile: Thank you for sharing the code snippet.
Unfortunately, I can't afford to lose platform compatibility with any addition to cvui. However, I think your suggestion could be easily incorporated in a platform-specific guide/tutorial that I'm planning to add to the docs.
I understand @Dovyski your point. No matter how would you solve the windows close buttons? In the meantime I have improved and fixed the code or borderless window. Use this :-)
inline void watch(const cv::String& theWindowName, bool theCreateNamedWindow, bool createBorder) {
cvui_context_t aContex;
if (theCreateNamedWindow)
{
if (createBorder)
{
cv::namedWindow(theWindowName);
}
else
{
cv::namedWindow(theWindowName, 0);
HWND win_handle = FindWindowA(0, theWindowName.c_str());
if (win_handle)
{
// Borderless
SetWindowLong(win_handle, GWL_STYLE, GetWindowLong(win_handle, GWL_EXSTYLE) | WS_EX_TOPMOST);
ShowWindow(win_handle, SW_SHOW);
}
}
}
aContex.windowName = theWindowName;
aContex.mouse.position.x = 0;
aContex.mouse.position.y = 0;
internal::resetMouseButton(aContex.mouse.anyButton);
internal::resetMouseButton(aContex.mouse.buttons[RIGHT_BUTTON]);
internal::resetMouseButton(aContex.mouse.buttons[MIDDLE_BUTTON]);
internal::resetMouseButton(aContex.mouse.buttons[LEFT_BUTTON]);
internal::gContexts[theWindowName] = aContex;
cv::setMouseCallback(theWindowName, handleMouse, &internal::gContexts[theWindowName]);
}
Thanks, @lukadt !
Apparently, the native close button not being able to properly close the window is a limitation in OpenCV itself. I think it would be useful to add a function to cvui to help developers monitor if a window has been closed, so they can end the application accordingly.
As I said, I can only proceed with that if a solution is available on all platforms.
Dear @Dovyski , I dig a little bit deeper into this issue and solved it using a suggestion found online. Basically my loop guard is like this on all the samples you provide:
// Init cvui and tell it to create a OpenCV window, i.e. cv::namedWindow(WINDOW_NAME).
cvui::init(WINDOW_NAME);
//while cv2.getWindowProperty('window-name', 0) >= 0:
while (cv::getWindowProperty(WINDOW_NAME, 0) >= 0)
{
// Fill the frame with a nice color
frame = cv::Scalar(49, 52, 49);
// Show some pieces of text.
cvui::text(frame, 50, 30, "Hey there!");
// This function must be called *AFTER* all UI components. It does
// all the behind the scenes magic to handle mouse clicks, etc.
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC key was pressed
if (cv::waitKey(20) == 27) {
break;
}
}
Try it yourself and let me know, Luca
That's a great solution! I've tested it in C++ and Python and everything seems to be working properly (at least on Windows).
I think putting the call to getWindowProperty() at the end, within the if that checks for the ESC key, makes things a bit more clear, since such if is already checking if the app should end. What do you think?
E.g.:
while (cv::getWindowProperty(WINDOW_NAME, 0) >= 0)
{
// Fill the frame with a nice color
frame = cv::Scalar(49, 52, 49);
// Show some pieces of text.
cvui::text(frame, 50, 30, "Hey there!");
// This function must be called *AFTER* all UI components. It does
// all the behind the scenes magic to handle mouse clicks, etc.
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC key was pressed or if the window was closed
if (cv::waitKey(20) == 27 || cv::getWindowProperty(WINDOW_NAME, cv::WND_PROP_ASPECT_RATIO) < 0) {
break;
}
}
Additionally, I don't think using cv::getWindowProperty(WINDOW_NAME, 0) instead of cv::getWindowProperty(WINDOW_NAME, cv::WND_PROP_*) is ideal, because the code could break in the future if OpenCV developers make any of the cv::WND_PROP_* stop using the value zero.
Dear @Dovyski, your refactoring is a good one, it's better than my proof of concept. That being said I just found a small issue and it's related to cvui init with waitkey enable. If you try this code you can see the potential issue in action, i.e. the window is not closed. Let me know your findings,
// Init cvui and tell it to create a OpenCV window, i.e. cv::namedWindow(WINDOW_NAME).
cvui::init(WINDOW_NAME, 2000);
while (cv::getWindowProperty(WINDOW_NAME, 0) >= 0)
{
}
HTH, Luca
You are absolutely right, my suggestion will not work when cvui is handling the calls to waitKey. It seems the use of while (cv::getWindowProperty(WINDOW_NAME, 0) >= 0) is the best way to go.