What is the best way to communicate between two windows in Qt?
I need to have a separate login window and main application window which appears one after another (the second one, I mean main application window, will show only if the login was successful). Should I create these two objects (login window and main application objects) in the main function or make login window data member of the main application class and create it in the constructor of the main application class?
You can create login window as a data member of the main application class and create it in its constructor. Next you can invoke login by connecting a signal named login_
asked() of the main class to a slot named perform_login() and emitting the signal after that:
QObject::connect(this,SIGNAL(login_asked()),this,SLOT(perform_login())
,Qt::QueuedConnection);
emit login_asked();
You should hide your main window in the perform_login() slot and show your login form like:
this->setVisible(false);
loginfm->show();
You can notify your main application of the failure or success in login by signals and slots like:
QObject::connect(loginfm,SIGNAL(login_accepted()),this,SLOT(entered()));
QObject::connect(loginfm,SIGNAL(login_canceled()),this,SLOT(canceled()));
In the the slot entered() of your main window you should show the main window:
this->setVisible(true);
This way you can invoke login as many as you like during the application life cycle by just emiting the login_asked() signal.
The login window should be a QDialog-derived window. This has accepted and rejected signals, which you can trivially handle in your main window. (This answers the question in the title)
It doesn't matter very much where you create them, that's really a style issue. I'd probably put it in main myself, but if I took over an existing codebase I wouldn't bother changing such details.
Related
I am developing an application to feed a database. My main window is basically a menu that opens forms for different utilities.
Not sure if it's the best practice but let me explain what I'm trying to do:
my class mainwindow has a private QString that will store the current project name. In the menu, "Load" opens the form (another class) that lists all the existing projects in a combobox. The user chooses the project he wants and clicks OK.
I would like to return the combobox.currentText() into the dedicated private variable. After some research I still cannot figure out how to make it, wether I should use SIGNAL from the form to trigger a SLOT of the mainform or if there is a simple way to just return a value after pressing OK (such as an input dialog). If i am not clear enough, maybe the following sketch could help.
I definitively have a lack of knowledge on the subject but would be grateful for some help.
Indeed if your form for loading a project would emit a signal currentProjectChanged as soon as the user accepts the form (presses the OK button), this signal could be connected to a slot of the main window. For simple things this may be fine and elegant.
On the other hand reacting on actions sometimes needs more logic. If your action triggers a slot that cares for action execution, this slot probably should implement the logic. It should open the form and check whether the user has accepted the project change (pressed OK). In this case the action execution slot could get the new project name from the form and call a main window method to pass the new project name.
Currently I am writing a C++ Qt GUI standard (i.e. via Qt Creator) application.
Basically, what I am trying to do is an application, which operates the following singleton classes:
a MainWindow class, which is responsible for the core logic;
a ServerWindow class, which is responsible for the server connection;
a User class, which is returned (in form of a pointer) by the ServerWindow class after successfull authentication;
a Data class, which is initialized with the data, recieved via ServerWindow upon user authentication.
The algorithm is:
Construct a MainWindow and create a Data class; it also holds a pointer (nullptr at this step) at the current user.
When the constructor has finished, the ServerWindow (derived from QDialog) is executed (via Qt delayed connection). At this step the MainWindow is frozen and set invisible, untill the ServerWindow emits one of the signals (logged, fail). The ServerWindow has a modal mode flag set.
When the ServerWindow is done, a pointer to the current user is passed to the MainWindow. The ServerWindow also knows about the Data class and initializes it.
The main problem is that at step 2 the application icon in the taskbar (I use Windows OS) is not shown. When the MainWindow is "offline" (i.e., not shown, invisible via setVisibility(false)), there is no icon. It is highly annoying, especially if there is a bunch of other applications open. So that, my question is: what can I do to make ServerWindow create an application icon in the taskbar without MainWindow being shown?
The additional, by-the-way question is about possible application architecture remastering. I cannot find any books in my small library about similar applications designing. Frankly, I cannot even figure out, which words I should pass to the Google search line. Any advice?
Preliminary, thanks for any answers!
I have the following situations where I would like to display some widgets.
My main windows is mostly a text editor.
I have an action called 'Run', which interprets the text and does something.
One of the possible results is that a window needs to be opened.
It works, but the window is only displayed after the run function (which I have as a slot)returns.
Another situation I have to open a window is that I want to be abe to same interpreter to run from console input.
But opening the window in this case results in errors like:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Oxygen::WidgetStateEngine(0xee2d90), parent's thread is QThread(0xda53b0), current thread is QThread(0x7f2178004000)
QObject::installEventFilter(): Cannot filter events for objects in a different thread.
What can I do to somehow 'centralize' window operations so that this does not happen ?
All GUI objects are to be created within your main thread. You can get access to QMainWindow instance from any place in your code using static method QApplication::topLevelWidgets()
I have console MFC form application that consists from one form. In MFC application contructor thread with task is started :
CfbSrvApp::CfbSrvApp()
{
AfxBeginThread(MTServerThread,0);
}
MTServerThread procedure sometimes needs to show simple text input or yes/no form.
How to create MFC form in separate MTServerThread.
Main form sometimes can be minimised to tray, but input forms should appear to desktop anyway.
Derive a class from CWinThread.
Overwrite InitInstance
Create the Dialog there as known with DoModal
Create the new Thread with AfxBeginThread and RUNTIME_CLASS(CYourNewCWiNThreadClass)
Main form sometimes can be minimised to tray, but input forms should
appear to desktop anyway.
For what you want to achieve, it is better to create Modeless dialog in the main thread itself. Let the background server thread update the UI of the modeless dialog by sending messages to the main thread. This way you can minimize the main form in tray but still show modeless dialog.
In Single Document Interface (SDI) or Multiple Document Interface (MDI) MFC application, I created an application wide timer in the View. The timer will tick as long as the application is running and trigger some periodic actions.
How can I do the same with Dialog Based MFC application?
Should I create Thread's Timer (SetTimer with NULL HWND) and pass a callback function to it?
Should I create worker threads? My experience with other projects was when I tried to display some feedback GUI from non-GUI/worker threads, I need to roll out my own "delegate"/command pattern and a "delegate invoker"/command invoker. The worker thread will send message (I think using message is safer than direct function call when dealing across thread-boundary, CMIIW) to the UI-thread. and the UI-thread will be the "delegate"/command invoker. Failing to do this and to make sure that the windows/dialogs have the correct parent will result in bizzare behaviors such as the Application suddenly disappears to the background; Window/Dialog that is shown behind the current window/dialog and causing the current window to be unresponsive/unclickable. Probably I was doing something wrong but there were so much problems when dealing with threads.
Are there best practices for this?
A timer works as well in a dialog-based application as an SDI or MDI app. OTOH, timers are (mostly) a leftover from 16-bit Windows. If you want to do things periodically, a worker thread is usually a better way to do it (and yes, Windows Mobile supports multiple threads).
Edit: in a dialog-based application, the main dialog exists for (essentially) the entire life of the application. Unless you really need the timer during the milliseconds between application startup and dialog creation or dialog destruction and application exit, just attach it to the dialog. Otherwise, you can attach it to the main window -- which MFC creates and destroys, even though it's never displayed.
If you use the MFC Wizard to create the Dialog based app, you probably have a hidden view window as well as a dialog window. The view window creates the dialog with DoModal(), which runs the dialog in the same thread, effectively suspending the view window.
While the dialog is open, the view window will not process any events. So, if the view window owns the timer, it will not process the timer events.
The simplest solution is to create the timer in the dialog and let the dialog handle the timer messages.
IMO, use the Timer if it solves the problem. As you've mentioned a Worker Thread interacting with the UI, in MFC, can be more trouble than its worth sometimes.
If the problem is simple enough for a timer to suffice, thats what i'd use (Remember KISS)
SetTimer does not have to be handed a window to work, it can call a callback method.
You can use that in your application - declare in your CWinApp (or anywhere really)
static void CALLBACK OnTimer(HWND, UINT, UINT, DWORD);
Then in the InitInstance call SetTimer(0, [eventid], [time period], OnTimer);
In OnTimer you can get back to the CWinApp instance via AfxGetApp() or theApp since there is only one.
Second attempt: my previous answer was dne in a hurry and was not correct.
Your basic vanilla MFC Dialog app only uses one thread. The main thread starts with a class derived from CWinApp. In the InitInstance() method it launches the dialog using CDialog::DoModal(). This function doesn't return until the dialog is closed.
While the dialog is running, the CWinApp class does not process any messages, so won't see a WM_TIMER.
There are many ways around this.
Let the first dialog own the timer and make all other dialogs children of it. This might be OK, depending on your dialog requirements, but it might be too restrictive.
Launch the first Dialog as modeless, i.e. use Create() instead of DoModal(). Create() returns straight away (putting the Dialog into a different thread). You can then create a message loop in the CWinApp class and process timers there. You'll have to use thread timers instead of window timers as the CWinApp class doesn't have a window. (or you could create a hidden window if that is more convenient).
You can hack the dialog's mesage loop and make it pass messages to the CWinApp class' message handler. That is quite complex and not for the faint hearted.
You can create a dedicated timer thread. You'd probably do that from the CWinApp class before it creates the dialog, but other strategies are possible.
Do any of those schemes sound like they fit your needs? If not, maybe you can explain your needs more fully and we might be able to come up with something appropriate.