How to Program custom Keyboard Shortcuts - qt

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);

Related

QT Process gets killed automatically when it hits in SLOT

I have written a QT code which starts a new process on a button click, that process have to execute a shell script and append the Std output/error on text Browser dynamically based upon the script result. The code gets failed in the custom Slot. This is what my window.h is
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
QPushButton *goButton;
QTextBrowser *statusWindow;
QProcess *process;
private slots:
void go_Button_Clicked();
void updateOutput();
};
And this is how my window.cpp is
Window::Window(QWidget *parent) : QWidget(parent)
{
// Text Browser
statusWindow = new QTextBrowser(this);
// Create the Go button, make "this" the parent
goButton = new QPushButton(this);
connect(goButton, SIGNAL (clicked()), this, SLOT (go_Button_Clicked()));
}
void Window::go_Button_Clicked()
{
// Step1 - Create a new process
QProcess *process = new QProcess(this);
// Step2 - Connect the Signals and slot
qDebug() << connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(updateOutput()));
// Step3 - Start the Script process
process->start("/home/root/script.sh");
qDebug() << "Process in main";
}
void Window::updateOutput()
{
qDebug() << "Process in update Output";
//statusWindow->append(process->readAllStandardOutput());
}
So whenever i uncommented lines in update Output the GUI crashes as soon as i hit the button. using qdebug i managed to find that the GUI crashes bcoz of the line "statusWindow->append(process->readAllStandardOutput());" .
If the line is commented the debug message keeps on printing on console, but with the un-commented line i get the debug message once and then GUI crashes.Here is the debug output.
true
true
Process in main
Process in update Output
Process killed by signal
Any idea whats going on here, and i am familiar with Debugging in QT
Replace:
QProcess *process = new QProcess(this);
by
process = new QProcess(this);
You are using uninitialized member variable process, because in Window::go_Button_Clicked() you are creating a local variable.
Edit
Actually, the code is very error prone. What happens, when the user presses the button multiple times. Then in the slot you may read the the output from wrong process.
One workaround could be: You don't define QProcess as member at all, but do it like now - as a local variable. Then in the slot, you can cast the sender to QProcess*, and unless it fails use this instance. It will be always the right one. Afterwards, don't forget to delete the sender. Use deleteLater() for this.
Inside your void Window::go_Button_Clicked() slote you hide QProcess *process declared at .h file with new variable
QProcess *process = new QProcess(this);
Replace this line with
process = new QProcess(this);
But when you click second time you'll get memory leak, and can not get more data from first process. So you chould change you design somehow.

How to close QFileDialog programmatically?

I need to process and close QFileDialog in tests of the application.
The dialog invoked by:
QFileDialog::getOpenFileName( ... );
In the test I 'catch' this dialog by:
QApplication::topLevelWidgets();
Then I choose need file by QFileDialog API.
And now I should close the dialog to get valid answer (filename) from QFileDialog::getOpenFileName();
But QDilaog's slots has no effect (accept(), reject(), close()... ). The dialog stays opened.
The solution described here works, but it is no option in my case. I must to use standard dialogs.
Is there a way to close it properly?
QFileDialog::getOpenFileName is a static method, so you're limited by what you can do with it.
If you want more control, I suggest creating an instance of QFileDialog and using that instead. By calling the instance's close() function, you can programmatically close the dialog.
In response to the comment that this doesn't work, here's example code:-
// Must create the FileDialog on the heap, so we can call close and the dialog is deleted
// Set the Qt::WA_DeleteOnClose flag if the instance is still required
QFileDialog* fileDlg = new QFileDialog(this, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// One shot timer to close the dialog programmatically
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]()
{
fileDlg->close();
timer->deleteLater();
} );
timer->start(3000);
fileDlg->exec();
In order for to display a native dialog, you have to run exec() or call one of the static functions.
Unfortunately, in Windows, this calls a blocking function in the Windows API making the displayed dialog modal, running it's own event loop. Without returning to the Qt event loop, you cannot execute the close() function using the signals/slots interface.
I tried to bypass this by calling the close() function directly from another thread, but this results in Qt trying to send an event to the underlying dialog. Since sending (as opposed to posting) events across thread boundaries is not allowed in Qt, a fatal error is generated.
So, it seems for Windows at least, this is not possible.
I have not tested on platforms other than Windows. The code I used was:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog* fileDlg = new QFileDialog(0, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// spawn a new thread
QtConcurrent::run([=](){
QTimer timer;
timer.setSingleShot(true);
QEventLoop *loop = new QEventLoop;
QObject::connect(&timer, &QTimer::timeout, [=](){
fileDlg->close();
fileDlg->deleteLater();
loop->quit();
});
timer.start(3000);
loop->exec();
delete loop;
});
fileDlg->exec();
return a.exec();
}
In Windows you can use WinAPI to close the dialog:
#define WAIT(A) while (!(A)) {}
HWND dialogHandle, button;
WAIT(dialogHandle = FindWindow(NULL, L"Open")); //write here title of the dialog
WAIT(button = FindWindowEx(dialogHandle, NULL, L"Button", L"&Open")); //write here title of the button to click
SendMessage(button, BM_CLICK, 0, 0);

Open Existing QMainWindow from QMainWindow

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());

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.

Displaying a second form in Qt

I know this question has been asked a few time, (http://stackoverflow.com/questions/4436511/display-a-form-in-qt)
I am trying to open an existing form in my Qt C++ project.
it needs to be a subform instead of QDialog box.
both forms have a .ui, .h and .cpp file with them.
in my mwindowtest.cpp I have
//this is used to handle the button click to open the new form
connect(btnConnect, SIGNAL(click()), this, SLOT(openNewWindow()));
for function is:
void mWindowTest::openNewWindow(){
mForm = new dialog (this);
mForm->show();
}
in my mwindowtest.cpp I have:
#include <dialog.h> //second form
class dialog;
I'm now getting the error mForm was not declared in this scope.
but I am not sure what to declare mForm as in my Header file.
any tips would be greatly appreciated.
Thanks
In your mywindowtest.hpp you have to declare the pointer first:
// mytestwindow.hpp
// ...
private:
dialog* mForm;
// ...
// mytestwindow.cpp
void mWindowTest::openNewWindow()
{
mForm = new dialog (this);
form->show();
}
Or you declare it directly in your cpp, but then it is no member and only known in openNewWindow().
void mWindowTest::openNewWindow()
{
dialog* form = new dialog (this);
form->show();
}
When you work with Qt you should know the basics of C++. This example is one of those basics. Use Google and read some stuff about pointer tutorials and dynamic memory allocation.
Hope that helps. :)
In your example you will have memory leak since each time button btnConnect is clicked you will reallocate memory for your form, without deleting the previous first.
Concerning your problem, we need to know how is declare dialog in dialog.h to be able to really help you.
In your mywindowtest.cpp you have included the file and redefined the class. Try to put
class dialog
in your hpp file and
#include <dialog.h>
in your cpp file.
Hope that helps
Edit:
In your slot:
delete mForm;
mForm = new dialog();
dialog->show();
It's the minimum to avoid memory leaks; And don't forget to delete mForm in MyWindowTest destructor too if not null;

Resources