Open Existing QMainWindow from QMainWindow - qt

I have a little question - I have QMainWindow with button. On click on that button I would like an existing QMainWindow to open (detail: I want open a window with QWT Plot. I mean the refreshtest project example of QWt.)
So I would like to existing Window open on button. As far I was able to open new QMainWindow, but what can I do to see MainWindow from project refreshtest?
void MyWindow::on_pushButton_1_clicked ()
{
QMainWindow *mw = new QMainWindow();
mw->show();
}

With this code, you will get a leaking pointer after leaving the scope of the method.
The reason is that the show() method is not blocking. It will post an event into the event loop queue. It will get processed in an async manner whenever the Qt event loop "gets the capacity for that".
You have several options to address this issue.
1) Qt parent/child relation
QMainWindow *mw = new QMainWindow(this);
^^^^
2) Make "mw" a class member of MyWindow
m_mw.show();
and construct it in the MyWindow constructor.
3) Use a smart pointer
QSharedPointer<QMainWindow> mw = QSharedPointer<QMainWindow>(new QMainWindow());

Related

Understanding signals, slot order, and parent widgets

So I have a situation where I can't get a couple slots to fire in the order that I would like them to.
The basic set-up is that I have a Mainwindow with a statusbar that needs to get updated based on a signal from a child widget (SearchWidget). When the "Go" button is clicked on the child widget, I would like it to update the status bar to say "Searching..." and then perform the actual database search. However, I can only get the updateStatusBar slot to trigger AFTER the search is complete and displayed in a tablewidget. I have tried re-arranging the connections to the appropriate order, I have tried a separate function that emits the signal for the statusbar and then the signal for the search, but nothing seems to work. The search always executes first and the statusbar doesn't change until after that is complete.
I'm a newbie a this, but I'm guessing maybe the issue has something to do with the parent-child relationship between the mainwindow and the widget? Perhaps slots within the same widget are prioritized in some way? See basic code below.
Mainwindow class:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
initMembers();
initUI();
connect(searchWidget, SIGNAL(searchingStatus(QString)), this, SLOT(updateStatusBar(QString)));
}
void MainWindow::initMembers()
{
tabWidget = new QTabWidget(this);
searchWidget = new SearchWidget(this);
saleWidget = new SaleWidget(this);
statusBar = new QStatusBar();
setCentralWidget(tabWidget);
setStatusBar(statusBar);
}
void MainWindow::initUI()
{
tabWidget->addTab(searchWidget, "Search");
tabWidget->addTab(saleWidget, "Sale Data");
}
void MainWindow::updateStatusBar(QString status)
{
statusBar->showMessage(status);
}
SearchWidget class:
SearchWidget::SearchWidget(QWidget *parent) : QWidget(parent)
{
connect(goButton, SIGNAL(clicked), this, SLOT(buildQuery()));
}
void SearchWidget::buildQuery()
{
emit searchingStatus("Searching...");
//builds sql query
}
Any enlightening info would be much appreciated!
I suspect that it's not an ordering issue, but the fact that the SQL query is blocking the main GUI event loop: try inserting a call to QApplication::processEvents() after your emit searchStatus(...) call. If I'm correct, you should see the status bar update before the database search completes.
However, because you're still blocking the event loop, your GUI will still freeze while the DB call executes, which isn't great. You can eliminate this by running the query on a different thread (one of the simplest ways is via http://doc.qt.io/qt-5/qtconcurrent.html#run), but beware you then have to worry about concurrency issues (e.g., now you can click the go button lots of times in a row...).

How to Program custom Keyboard Shortcuts

I have a Qt application on Linux.
I'd like to program custom keyboard shortcuts such as CTRL-Q which will then call a subroutine which quits the program.
How can I do this?
Try this:
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
You can create it in the contructor of your form. This allows to avoid polluting your class with a pointer to access the shortcut. You may still want to add a pointer to the shortcut if you want to access it later on. The shortcut will be deleted when the application exits, since it is parented to it. It automatically does the connection, you don't have to do it manually.
Also note that there is no default Ctrl+Q sequence on Windows, but there is one on Linux and MacOS.
Since CTRL-Q may have a menu item or toolbar entry, too, I think you're looking for QAction.
See this:
http://doc.qt.digia.com/4.6/qaction.html#shortcut-prop
LE:
Example of QAction at work:
QAction *foo = new QAction(this);
foo->setShortcut(Qt::Key_Q | Qt::CTRL);
connect(foo, SIGNAL(triggered()), this, SLOT(close()));
this->addAction(foo);
Just create a new Qt GUI project (I used QtCreator) and add that code to the main window's constructor and it should work as expected.
Please note that there is no need of freeing the memory since the Qt framework will take care of that when the app closes.
For the modern Qt (5.9 as of now):
void MainWindow::bootStrap()
{
// create shortcut
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
// connect its 'activated' signal to your function 'foo'
QObject::connect(shortcut, &QShortcut::activated,
this, &MainWindow::foo);
}
// somewhere in the code, define the function 'foo'
void MainWindow::foo()
{
qDebug() << "Ctrl+Q pressed.";
}
Don't forget to #include <QShortcut>.
Further info: http://doc.qt.io/qt-5/qshortcut.html
this is a sample to create file menu and exit action and connection between signal and slot.
QMenu *fileMenu = new QMenu(trUtf8("&File"));
QAction *actionExit = new QAction(tr("E&xit"));
//set "ctrl+q shortcut for exit action
actionExit->setShortcut(tr("CTRL+Q"));
//connect triggered signal of actionExit to close slot
connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
//add actionExit into file menu
fileMenu->addAction(actionExit);

Using Qt GUI with objects external to application

I'm creating a Qt GUI that will generate some forms for the user, let them fill them in, and then save the forms in a binary search tree that will then be serialized. This is done using Qt (obviously), c++, and boost. The GUI is the only interface with the application at this point. I would like to instantiate my binary search tree object outside of the GUI as creating it inside the main GUI class seems to be a bad design pattern. Is this thought correct?
Here's my main() right now:
int main (int argc, char *argv[])
{
QApplication app(argc, argv);
ChocAnGui *gui = new ChocAnGui;
gui->show();
return app.exec();
}
Is there a way to create a BST object that the ChocAnGui class can use, but that lives outside of the actual GUI? I'd like to do something like:
int main (int argc, char *argv[])
{
MyBST bst = new MyBST;
MyRecord record = new MyRecord;
QApplication app(argc, argv);
ChocAnGui *gui = new ChocAnGui;
gui->show();
return app.exec();
}
I would then like the GUI to be able to call methods on the MyBST and MyRecord classes from within. Because at the start and finish of the application I am serializing and de-serializing data, this seems to be the most abstract approach (vs. serializing and de-serializing from within the GUI code itself). I hope this question is clear... I'm learning all this stuff as we speak. Is there a way to pass those vars through QApplication(argc, argv)? Eventually the record and BST classes will be built into a database and, again, creating the instances outside of the GUI seems most straightforward. Thanks for any input you can provide.
I think it is necessary for you to put your binary search tree outside the GUI thread only when your Binary search takes a long time and is possible to block the GUI's thread.
If this is the case, the what you wanna do is to put the MyBST object under another thread,
In your main application, create a new thread that will handle all BST operations:
QThread * BSTThread = new QThread();
BSTThread->start();
BSTThread is a new thread that has its own event queue.
Then you create you MyBST Object, Make sure MyBST inherits QObject, and you can call the moveToThread method on the object.
MyBST * bst = new MyBST();
bst->moveToThread(BSTThread);
When the main application wants to communicate with the MyBST, you emit a signal from you main application. Connect the signal to a slot in the MyBST class using Qt::QueuedConnection, or just use Qt::AutoConnection, it will automatically be queuedconnection because your bst object lives in a different thread as the main app, and the function in the slot will be executed by the BSTThread.
And when the bst object wants to communicate back to the main app, also emit a signal, this signal is connected to the slot in the main app, which will handle this properly in your mainThread. In this way, your communication is asynchronous, you can not get the result immediately when you send request to the bst object, because you send it as a signal and it is posted in the event queue of the BSTThread waiting to be processed. After the BSTThread processed the request from the main app, it posts back the result to the main thread's event queue, the main thread handles the results and updates the GUI.
I think you need to read this http://doc.qt.digia.com/qt/thread-basics.html on QT if you want to know more details.
Just create your window to declare a MyBST member:
class MyBST;
class ChocAnGui
: public QMainWindow
{
Q_OBJECT
public:
ChocAnGui(MyBST* aBst = 0, QWidget *parent = 0);
MyBST *bst
And then initialize it with your object:
ChocAnGui *gui = new ChocAnGui(bst);
Or you can not make it a member, and make your gui just always take a MyBST pointer:
class MyBST;
class ChocAnGui
: public QMainWindow
{
Q_OBJECT
public:
ChocAnGui(QWidget *parent = 0);
void doSomething(MyBST*);

Passing signals through hierarchies

I am having some difficulty fully grasping how signals and slots are used in Qt. I am sure it is really basic but I'm just no getting it today.
I have a set of widgets a bit like this:
MainWindow
-->StackedWidget
-->ChildForms
Now the idea is that there are some actions on the Child widgets that will cause the stacked widget to display a different page.
So if I understand it properly I thought the way to connect signals and slots is to use the connect() at the scope that knows about the objects but what I have managed to get working doesn't do it this way. At the moment in my child form I use parentWidget() to access the slot of the StackedWidget but I am not very happy with really because it is giving the child information about the parent which it shouldn't have:
void TaskSelectionForm::setButtonMappings()
{
// Set up a mapping between the buttons and the pages
QSignalMapper *mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));
mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}
But I am not really sure how I should do this and connect it up. Do I need to have signals at each level and emit through the tree?
A Bit of Signal-Slot Theory
The signal-slot connections are oblivious to parent-child relationships between QObjects, and any such relationship doesn't matter. You're free to connect objects to their children, to their siblings, to their parents, or even to QObjects that are in a separate hierarchy, or to lone QObjects that have neither parents nor children. It doesn't matter.
A signal-slot connection connects a signal on a particular instance of QObject to slot on another instance of QObject. To use the connect method, you need the pointers to the instance of sender QObject and the instance of receiver QObject. You then use the static QObject::connect(sender, SIGNAL(...), receiver, SLOT(...)). Those connections have nothing to do with any hierarchy there is between the sender and receiver.
You can also connect a signal to a signal, to forward it -- for example from a private UI element to a signal that's part of the API of the class. You cannot connect a slot to a slot, because it'd incur a bit of runtime overhead for a rarely-used case. The overhead would be an extra bool member in QObjectPrivate, plus a failed if (bool) test. If you want to forward slots to slots, there are at least two ways to do it:
Emit a signal in the source slot and connect that signal to the destination slot.
Obtain a list of all signals connected to the source slot, iterate on it and connect them to to the target slot. There's no easy way to maintain such connections when further signals are connected or disconnected from the source slot. Unfortunately, QObject only has a connectNotify(const char*) protected function, but not a signal -- so you can't hook up to it unless you would modify src/corelib/kernel/qobject[.cpp,_p.h,.h] to emit such a signal. If you truly need it, just modify the Qt source, you have access it for a reason, after all. Hacking the vtable without modifying Qt is possible, but discouraged for obvious reasons.
The Answer
Below is a self contained example that shows how to do what you want. Turns out I have answers to quite a few questions from my various experiments I've done in Qt in the past. I'm a packrat when it comes to test code. It's all SSCCE to boot :)
// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Window : public QWidget
{
QSignalMapper m_mapper;
QStackedLayout m_stack{this};
QWidget m_page1, m_page2;
QHBoxLayout m_layout1{&m_page1}, m_layout2{&m_page2};
QLabel m_label1{"Page 1"}, m_label2{"Page 2"};
QPushButton m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
Window(QWidget * parent = {}) : QWidget(parent) {
// the mapper tells the stack which page to switch to
connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));
// Page 1
m_layout1.addWidget(&m_label1);
m_layout1.addWidget(&m_button1);
// tell the mapper to map signals coming from this button to integer 1 (index of page 2)
m_mapper.setMapping(&m_button1, 1);
// when the button is clicked, the mapper will do its mapping and emit the mapped() signal
connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page1);
// Page 2
m_layout2.addWidget(&m_label2);
m_layout2.addWidget(&m_button2);
// tell the mapper to map signals coming from this button to integer 0 (index of page 1)
m_mapper.setMapping(&m_button2, 0);
connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));
PrivateSlot() is a slot declared privately. So in this function, you can add your code to change the page of stackedwidget corresponding to the action produced by currentactivewidget.
Again if you really want to pass the signal up the heirarchy, emit a publicsignal() at the end of private slot function.
Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));

Qt Modeless Dialog Destruction

From what I understand to make dialog Modeless you have to allocate it on the heap. By Doing something like this:
MyDialog* dlg = new MyDialog(this);
dlg->show();
dlg->raise();
Since exec() ignores Modal Property. However now there is a memory leak since nothing deallocates memory pointed to by dlg pointer until the application is closed. I found one solution here http://tinf2.vub.ac.be/~dvermeir/manuals/KDE20Development-html/ch08lev1sec3.html#ch08list09 at the end of the page and was wondering whether there was a less cumbersome way having Modeless dialog.
You can use the attribute Qt::WA_DeleteOnClose to destroy the window when it is closed/hidden, and QWeakPointer (or QPointer) with a static variable to track the existence of the window inside the slot/function which opens it:
void MyWindow::openDialog() {
static QWeakPointer<MyDialog> dlg_;
if (!dlg_)
dlg_ = new MyDialog(this);
MyDialog *dlg = dlg_.data();
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->show();
dlg->raise();
dlg->activateWindow();
}
I'd schedule it for deletion at the time it's work is finished by using deleteLater:
void MyDialog::MyDialog(QWidget *parent) {
// ...
connect(this, SIGNAL(finished(int)), SLOT(deleteLater)));
}
This approach will preclude you from examining it after the finished signal has been emitted (unless you can guarantee that any accesses happen before everything gets back to the event loop when the deletion is actually performed).
Personally, I would choose between either using
dlg->setAttribute(Qt::WA_DeleteOnClose);
or making the dialog a -dynamically allocated- member i.e. creating it only once:
// constructor
: dialog_(0)
// member function
{
if (! dialog_)
dialog_ = new MyDialog(this);
dialog_->show();
dialog_->raise();
}
This way the dialog is deleted when the parent dies, and only needs to be constructed once.

Resources