I have a child class of QWidget, and I'm trying to fix a bug where the the window that it is in cannot be programmatically hidden/closed using the QWidget::hide() or close() methods.
Here are some of the things that I tried:
if(widget->isFullScreen())
{
widget->showNormal(); //Makes the window normal-sized before closing it
widget->hide();
}
Here's another way I have tried:
if(widget->isFullScreen())
{
widget->setWindowState(Qt::WindowMinimized);
widget->hide();
}
I also tried setting up a slot/signal system:
if(netcam->isFullScreen())
{
connect(this, SIGNAL(fullScreenExited()),
this, SLOT(onFullScreenExited()));
widget->showNormal();
this->fullScreenExited(); //just hides the widget (or closes it)
}
else
{
widget->hide();
}
The result every time is that the window freezes and must be closed by hand. My suspicion is that the first showNormal() is happening asynchronously, and the second close()/hide() never successfully executes.
I also tried this, in hopes that it would complete showNormal() before going on to hide()/close():
if(widget->isFullScreen())
{
widget->showNormal();
QApplication::processEvents();
widget->hide();
}
THE MAIN QUESTION:
Does anybody have any suggestions for how to deal with closing a full screen QWidget from Qt code?
Question that could also help:
Is there a way to ensure that things run synchronously?
Thanks!
EDIT:
The only way that I got this to work was to call showNormal() further up in the process, which prevents overlap in the execution of showNormal() and hide(). I'll try to remember to come back later and give a good, basic example with a regular QWidget.
I should also add that the window is put into the fullscreen state with the + (full screen) button, which is located at the top of each window in OS X.
This is a known bug.
The workarounds of showNormal() or showMinimized() are not working because the window state change is not synchronous. And a single processEvent() is not enough. You need to wait for the corresponding QEvent::WindowStateChange event to know when the window has fully moved out of fullscreen and can receive a new window state change.
Related
I'm trying to build an application that can spawn a window on a separate thread. Let me explain a simple version. My main creates an object that has a window, let's call this object a menu. From the menu you can select what to do, for example open up an image to a new window. This whole object, or the object's "game loop" needs to be on a separate thread so that I can still keep interacting with the menu. I also need to interact with the image viewer.
My question is, what is the proper way of doing this?
I haven't really used threads a lot before. But from what I understand I need to detach the thread to create a daemon thread.
I tried to play around with the thread to create this but I kept getting these errors:
Failed to activate the window's context
Failed to activate OpenGL context: The requested resource is in use.
I'm not certain what causes this, all objects, like my windows are different instances. The application will still run fine even with these errors.
My application is quite big so here's an extremely simplified version of the code I've tried.
int main()
{
Menu menu; // this spawns a window
menu.run(); // let's say for simplicity this doesn't do anything else other than
// create a new window (the image viewer)
}
...
void caller(Image_view *img_view)
{
img_view->run();
}
void Menu::run()
{
Image_view *img_view = new Image_view(); // This creates the window
this->thread = new std::thread(caller, img_view);
this->thread->detach();
while (1); // This is here to keep the application running,
// in a real application this method would look different.
// This whole thread call would be in an event handler instead,
// but for this example I tried to make it as simple as possible
}
...
void Image_view::run()
{
while (running)
{
update(); // Event handler and whatever
render(); // Renders the image and whatever
}
this->window->close();
}
I mostly want to know if I'm using the thread correctly or not in an application like this. Also if you have any insight as to what the error message means, explaining it would be greatly appreciated. I should also mention that I'm using SFML for rendering and creating the window instance.
The tutorials I found about the threads are always something extremely simple which doesn't involve any window or anything that could for example cause that error message. So I figured someone smarter here might know the proper use of the thread in my case.
Thanks in advance!
Generally I have some button that opens child window and the second press on this button should close it. I use a touch screen.
The problem is when I try to press the button for closing the child window, it is not pressed the first time, so I need another click.
In order to fix this I am trying to return the focus to the parent window after the child window is opened.
I register the OnShowWindow message and call SetFocus on the parent window:
void CFlashGuidanceSteps::OnShowWindow(BOOL bShow, UINT nStatus)
{
CDialog::OnShowWindow(bShow, nStatus);
GetParent()->SetFocus();
}
While the function is called (I can see it in debugger), the focus is not returned to the parent window.
However, it works with the OnSetFocus event:
void CFlashGuidanceSteps::OnSetFocus(CWnd* pOldWnd)
{
CDialog::OnSetFocus(pOldWnd);
GetParent()->SetFocus();
}
Why is the focus is not retained with the OnShowWindow event?
The explanation
The usual rule in MFC is that OnXxx functions are called in response to similarly named window messages, e.g. WM_Xxx. So OnShowWindow would be called in response to WM_SHOWWINDOW.
And according to the documentation, WM_SHOWWINDOW is
Sent to a window when the window is about to be hidden or shown.
That means it is sent before the window is actually shown. So when you set the focus to the parent window inside of the OnShowWindow function, nothing actually happens because the parent window already has the focus. Then, after OnShowWindow finishes running, the child window is displayed and demands the focus. It is as if you never made any attempt to change the focus.
By contrast, OnSetFocus, which corresponds to WM_SETFOCUS, is not called until after the window has gained the focus. So when you reassign the focus here, it works because the child window doesn't steal the focus back.
The better idea
That explains the behavior you are seeing, and as you know, things work fine when you adjust the focus in OnSetFocus. But this really isn't the best way of solving the problem.
Manually changing the focus when a window gets and/or loses the focus is approaching the problem the wrong way around, and generally error-prone. You'll get all kinds of focus-related bugs that are difficult to debug. You are better off looking for ways to prevent the focus from changing when you don't want it to.
It sounds to me like you want to prevent the child window from getting the focus when it is created. And there is a way to do precisely that.
When you display the child window, presumably by calling the ShowWindow function or its moral equivalent in MFC, you should pass the SW_SHOWNA flag. That causes the window to be shown without activating it (i.e., granting it the focus).
In my project, I have a function running while a QProgressDialog shows the progress.
QProgressDialog progress("Saving savegame.dat...", "Abort Save", 0, 3016, this);
progress.setWindowModality(Qt::WindowModal);
//... some loops and other calculations run while I update the progress bar with:
progress.setValue(1000);
All is well until I start another process. (Open a cli program)
QProcess decomBR;
QStringList filePathListBR;
filePathListBR.append("-o");
filePathListBR.append("stuff\\compress.bms");
filePathListBR.append("stuff\\regions\\xbox_chunks\\br");
filePathListBR.append("stuff\\regions\\xbox_chunks\\br");
decomBR.start("stuff\\quickbms.exe", filePathListBR);
decomBR.waitForFinished();
As soon as a process like this is started, the progress bar dialog hides or something and the progress is no longer shown, but the processes still run fine.
Any way to prevent these processes from "closing" the QProgressDialog?
EDIT: So apparently, the dialog isn't closing, it's just the main window is taking priority and "covers" the dialog... if that makes sense. Is there any way to make the dialog maintain display priority?
Thanks for your time :)
I have not tried this, but setWindowFlags(Qt::WindowStaysOnTopHint); may help. Notice that it's a flag, so you'd want to write something like:
progress.setWindowsFlags( progress.getWindowsFlags() | Qt::WindowStaysOnTopHint );
Consider using an assertion to see if it's already set, if so then you can dismiss my answer definitively and add to human knowledge by negation!
I am developing Qt application (Qt version 4.7.3) on SBC6000x board.
I have a MessageBox class derived from QDialog. I have made this class singleton.
Whenever a messagebox is to be show I am using .exec method to show it.
There are few places where I need to show messageboxes one after another.
So, to show new messagebox, I have to close previous one and show new one.
e.g. When Messagebox is open and at same time I receive an error from background I have to close the messagebox which is currently shown and show the one with error.
To closes previous dialog I have exposed CloseDlg method from messagebox class and trying to close it.
Inside this CloseDlg I am emitting finished signal.
void CMsgBox::CloseDlg()
{
if (NULL != CMsgBox::m_msgBox)
{
if(CMsgBox::m_msgBox->isVisible())
{
emit CMsgBox::m_msgBox->finished(0);
//QApplication::processEvents();
}
}
}
and calling it as
CMsgBox::CloseDlg();
My show method is :-
int CMsgBox::showMsgBox(Icon icon, const QString &textMsg, const QString &okBtnText)
{
if (CMsgBox::m_msgBox == NULL)
{
CMsgBox::m_msgBox = new CMsgBox();
}
CMsgBox::m_msgBox->setText(textMsg);
CMsgBox::m_msgBox->setIcon(icon);
CMsgBox::m_msgBox->setOkBtnText(okBtnText);
CMsgBox::m_msgBox->exec();
return CMsgBox::m_msgBox->m_btnPressed; //return, unblock the call
}
Again when I call showMsgBox,it is showing me following warning.
QDialog::exec: Recursive call detected
Problem is, it doesn’t return from previous exec call (unless we return, as commented above //).
I tried same with close(), accept(), reject() methods instead of finished() event but nothing worked.
What is the way to return from previous exe call and achieve above scenario? Any help is welcome.
What you have here looks like a race condition. A modal QDialog runs its own event loop, so your application behaves like a multithreaded application and you need to take care of concurrency and race conditions.
When you receive a second in your main event loop, you call CMsgBox::CloseDlg() and CMsgBox::showMsgBox() in quick succession. However, CloseDlg() tells the dialog's event loop to return, but CloseDlg() actually returns before the dialog's event loop is done cleaning up, and showMsgBox() attempts to call exec() on a dialog which hasn't finished exiting yet.
What you need to do is, when you call CMsgBox::CloseDlg(), connect to the finished(int) signal, and only when you receive the finished(int) can you safely exec() the dialog again.
NOTE: When connecting to the finished(int) signal, make sure to use a Qt::QueuedConnection instead of a Qt::DirectConnection which is the default.
So, you need modeless dialog box. As explained in their documentation :
Modeless dialogs are displayed using show(), which returns control to the caller immediately.
Therefore, instead of showing the box with exec(), show it with show().
Alternative to show() method suggested in another answer is, use QDialog::open(). It will return, but will still give you modal dialog, so the rest of the GUI will be disabled until you close it.
How do i hide a toplevel window without closing it?
NdmWindow is a class inherited from Gtk::Window.
I have added the instance of NdmWindow to Gtk::Application.
Now, how do i hide it instead of closing it?
Thanks in advance..
According to this, the behavior is that when a window is hidden, it is removed from Gtk::Application, and so if it is the last window, the app quits.
If you want your application to keep running when no windows are showing, the solution is to call hold() on your Gtk::Application object to increase the reference count of the application. Presumably you do this before setting up any windows, and call the corresponding release() as part of your quitting logic.
window->hide();
Don't forget to look at classes that Gtk::Window inherits from.
EDIT
I don't know, but my suggestion is to try hold(), and then release() after you show the next window.
Here's a solution that works and doesn't segfault.
Save a reference to Gtk::Application, say send it as a param to your main Window class and call this var app, you'll need it later, it's needed because in some cases get_application() will return null.
In the delete event handler of your window call
app->hold();
hide();
return true;
Don't call app->release() when you want to make your window show up again since it will make your application exit completely. Just call set_visible() on your window object and it will show up.