Event Handling in Qt - c++

I am new to Qt GUI programming and come from a .NET/Winforms background as far as GUI development goes. I am using the Qt Creator IDE.
How can I handle a button press event in Qt to do something like the following:
if (button.clicked = true)
{
startProgram();
}
Also, how would I browse for a configuration file which would populate values into all of my line edit textboxes when opened? I am programming this in C++.
EDIT: I am taking a console app that someone else wrote and building a GUI around it. I want to access one of the functions in there from a button click event. However, I can't figure out how to get the functions of the original app to be in scope of the GUI which I have created when I try to use SIGNALS and SLOTS.

A simple example could be something like this. Say you have a class like ProgramStarter:
#include <QObject>
class ProgramStarter : public QObject {
Q_OBJECT
public slots:
void startProgram() {
//Do stuff
}
};
and something like this where ProgramStarter is used:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QObject>
#include "programstarter.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPushButton *testButton = new QPushButton("Push me");
testButton->resize(100, 40);
testButton->show();
ProgramStarter *program = new ProgramStarter;
QObject::connect(testButton, SIGNAL(clicked()), program, SLOT(startProgram()));
return app.exec();
}
Qt uses signals and slots to communicate between objects. The core idea is that signals are emitted when events occur and these signals can be connected to slots. In this case the button emits a clicked() signal when the button is pressed and the clicked() signal is connected to the startProgram() slot. So when the button is pressed, startProgram() is called.
Qt has a meta-object system for enabling the use of signals and slots, among other things. This is the reason why ProgramStarter inherits QObject and why the Q_OBJECT macro is in the header. I highly suggest reading this if you want to understand how signals and slots and the meta-object system work in Qt: http://doc.qt.io/qt-5/signalsandslots.html

It's a little long to explain but you connect the signal from the button to the slot with the function.
connect(button, SIGNAL(triggered()), this, SLOT(doSomething()));
You really need to read and understand signals and slots before trying to write code
edit: You are trying to call functions in a compiled separate running program?
Are you confusing Qt Signals with C/Unix signals? You could start the separate app from within your Qt app, get its PID and then send it a 'c' signal.
Or if you have the source of the app you could include it's code into your Qt app and then call any of the functions by simply wrapping them with a Qt slot handler.

In order to access the functions defined in the console application, you need to include the headers (.h/.hpp) that declare these functions, and link their implementation. I you have the source code of the implementations (.cpp), you need to add them to the sources to be compiled (they will be compiled in object files (.o) that will be linked in the final executable). If the console application is a front-end to a set of functions defined in a library (.lib, .a), you need to link this library.
After that, you can use Qt's signal/slot mechanism to connect the "button clicked" signal to a slot calling the function you want to execute, as described in other answers.

It seems like your problem is not really to do with Qt or GUI programming at all, but rather a general design issue. Others have told you how to be notified when the button is pressed - it's up to you to hook that notification up to whatever code you want to call. Some possibilities:
If you just need to call a function then include the appropriate header file and call it.
If you have an object you want to call a method on, then you will need to provide a reference to that object to the class which receives the notification.
If your console app is a separate program, you can use QProcess to launch and communicate with it.

I guess your problem is that you cannot call the console app's function, because it hasn't been defined to be a slot. So here is how you might do it.
Let's assume you have a console app class which might look like this:
class ConsoleApp
{
public:
void run()
{
// Code which you want to trigger by a button in your UI.
}
}
Then we implement a Qt based wrapper class which inherits from QObject class and, hence, is able to send and receive signals. This class simply provides a custom slot which delegates execution to the ConsoleApp class.
class ConsoleAppWrapper : public QObject
{
Q_OBJECT
public slots:
void startProgram()
{
m_consoleApp.run();
}
private:
ConsoleApp m_consoleApp;
}
Ok, and now we want a button which, when pressed, will trigger a call of the 'run()' method.
int main(int argc, const char** argv)
{
QApplication app(argc, argv);
// Define wrapper for console app.
ConsoleAppWrapper wrapper;
// Define button and connect its 'clicked()' signal
// to the wrapper's 'startProgram()' slot.
QPushButton startProgramButton("Start Program");
connect(&startProgramButton, SIGNAL(clicked()), &wrapper, SLOT(startProgram()));
// Show the button.
startProgramButton.setVisible(true);
// Start Qt's event loop.
app.exec();
}
This should give you a 'Start Program' button which, when pressed, will call ConsoleApp::run() method.
While this example is not Qt Designer based I hope this example helps you hunderstand how signals and slots work in Qt.
Cheers,
Jonny

If you have a button created with the Designer you can use on_myButton_clicked() slot in the parent widget class, just like in WinForms.

Related

How to connect Qt signals and slots using QT Designer and Visual Studio

I am using Qt Designer for the design of my application which contains a "Load File" QPushButton (which has been promoted to a custom loadfile.h) as well as an QOpenGLWidget (which has been promoted to a custom OGLWidget.h).
I wanted to have it so that when I click my "Load File" button it sends a signal to a slot in my OGLWidget class which brings up a dialogue and loads the file.
I started by going into signal/slot edit mode in Qt Designer and connected the button to the openglwidget with clicked() as the signal and a newly added (from within Qt Designer) populate_mesh_from_obj().
I then made a function:
void OGLWidget::populate_mesh_from_obj()
{
exit(0);
}
as a test and in the header put:
public slots:
void populate_mesh_from_obj();
Now in my head I thought:
The signal clicked() is already implemented by Qt magic
The slot has been implemented by me
Qt Designer has connected them somewhere
So to me this should have worked. Any ideas why it hasn't?
you have to connect them manually..
connect(ui->button, &QPushButton::clicked, yourGlPointer, &OGLWidget::populate_mesh_from_obj);
Fortunately, the accepted answer is incorrect (It's not that it doesn't work manually, but you don't have to do it that way).
In fact, QT will automatically connect the signal to all slots that follow a standard naming convention.
This naming convention for slots goes like this:
void on_<object name>_<signal name>(<signal parameters>);
In your case, this means if you created the QPushButton in QT Designer like this:
the object name is loadfile and the signal name is clicked.
Now, declare your function like this in the header:
public slots:
void on_loadfile_clicked();
and define it like this in the cpp:
void OGLWidget::on_loadfile_clicked()
{
exit(0);
}
and the connection will be automatically taken care of.
This auto-connection feature is actually implemented through the QT Meta-Object compiler. You can retrace what happens by opening the ui_<classname>.h file generated by QT Designer. It will contain a function void setupUi(<QClassName> *<YourClassName>) containing a line QMetaObject::connectSlotsByName(<YourClassName>);. This is what instructs QTs Meta-Object Compiler to implement the connections for you.

Call events from the main function

I was used, in java, to create events almost anywhere, but in c++ (Qt), I notice that you have to create a class to be able to use the object's events. My question is the following : would it be possible to use MouseEvent (or any other event) belonging to a QPushButton from the main function ?
#include <QApplication>
#include <QWidget>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QWidget window;
QPushButton* btn = new QPushButton("Add",&window);
//Here, an event related to 'btn' to update the window...
window.show();
return app.exec();
}
PS : I know it's better to use the Qt Designer form, but I'm just asking about the possibility of doing this task.
Some events, e.g. mouse movement or focus changes, are not accessible through slots/signals.
You can use a small proxy QObject to filter events for other objects. See installEventFilter() for a code sample. You don't need to actually filter the events; you may just listen in and let them pass through.
Likewise, you can trigger/fake an event manually through QCoreApplication via notify().
As Joel Bodenmann notes, Qt uses signals and slots. You can have a slot on a QObject, but Qt can also connect to a lambda. Your lambda would have to capture window by reference, so it can update the window.
You'd probably want to connect the clicked event.
Qt offers the signal & slots mechanism. You can simply connect the QPushButton::clicked() signal to a slot that then performs the update you're referring to.
Using C++11's lambda:
// Create pushbutton
QPushButton* btn = nw QPushButton("Add",&window);
// Connect slot to 'clicked' signal
QObject::connect(btn, &QPushButton::clicked, []{
qDebug("Button clicked!");
// ... whatever else you want to happen on a button click
});
Keep in mind that you have other problems in your code as pointed out in the comments.

How to write QT system tray app without a window class, and integrate it with another process?

Here is my setup:
A background process that keeps running and does it's job.
A launcher which launches the aforementioned process and monitors it, relaunches it if crashed or killed.
I wish to add a system tray access to the launcher process (and the launcher process ideally will contain code for system tray display) and enable basic options (start, stop etc) to be triggered from the system tray context menu. The system tray does not need a window of it's own. Just a windowless system tray with a Context menu that contains 2-3 options.
Since the all code written so far is in C/C++ and I need it to run on Windows and Linux, QT comes across as obvious choice. I have found it quite frustrating to get past basic QT launcher tray display. Nearly every example I have seen of QSystemTrayIcon includes a 'mainwindow' inheritance.
Below is the code I am using to create system tray.
#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#include <QtGui/QIcon>
#include <QtWidgets/QSystemTrayIcon>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenu>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QPixmap oPixmap(32,32);
//QMenu* menu1 = new QMenu(); // want to get a context menu from system tray
oPixmap.load ("systemTrayIcon.png");
QIcon oIcon( oPixmap );
QSystemTrayIcon *trayIcon = new QSystemTrayIcon(oIcon);
qDebug() << trayIcon->isSystemTrayAvailable();
trayIcon->setContextMenu( menu1);
trayIcon->setVisible(true);
trayIcon->showMessage("Test Message", "Text", QSystemTrayIcon::Information, 1000);
return app.exec();
}
The code displays system tray alright, but I haven't been able to get around on how to add menus to it. What I want is:
1) Add the context menu to the system tray above without adding any window class (unless that is not possible)
2) Connect those context menu items to functions in my existing code
3) The app.exec() seems to be an infinite loop that processes QT events. However, since my launcher has it's own event loop, I want to make it so that the QT event loop is integrated with my launcher loop. In other words, add some non-QT tasks to the event loop.
Given the clarification from the comments, you have a couple of options on how to get code called for context menu or activation actions.
A receiver object: basically what the examples where using, just that you don't derive your receiver class from any window type.
For macro based signal/slot connections, the base type needs to be QObject or something derived from that, for function pointer based connect it can be any class
class MyReceiver : public QObject
{
Q_OBJECT
public slots:
void onActivated(QSystemTrayIcon::ActivationReason reason);
};
// in main()
MyReceiver receiver;
// macro based connect
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
&receiver, SLOT(onActivated(QSystemTrayIcon::ActivationReason)));
// or function pointer based connect
connect(trayIcon, &QSystemTrayIcon::activated,
&receiver, &MyReceiver::onActivated);
Connect to stand-alone functions
void onActivated(QSystemTrayIcon::ActivationReason reason);
connect(trayIcon, &QSystemTrayIcon::activated, &onActivated);
With a C++11 capable environment, connect to a lambda
connect(trayIcon, &QSystemTrayIcon::activated,
[](QSystemTrayIcon::ActivationReason reason) {});
For the context menu the same techniques apply, the "sender" objects are the QAction items you add to the menu and their signal is triggered() or toggled(bool) depending on whether the action can be just clicked or toggled between and "on" and "off" state.

Qt: Access Widget from main function and implement exit button

I want to implement an exit button in my application, which has the following setup:
I have a main function which looks like this:
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
I also have a mainWindow function which has been generated by the QT Creator IDE.
I design the GUI with the Qt Designer and when I want a pushbutton to do something when clicked, I use a function like this:
void on_selection_clicked();
I hope the setup is now sufficiently described.
Now to my problem: I want to implement a button, which, when clicked, terminates the window and the application. I first tried implementing this in a function like this:
void on_exit_clicked();
But I don't know that to to here.
Then I heard of a aproach via QObject::connect, but I have two questions:
1.) Where should I put this? In the main function? 2.) can I access the object simply via the object name given in the QT Designer?
no you should connect it in the constructor of the MainWindow
connect(ui->exit,SIGNAL(clicked()),QCoreApplication::instance(), SLOT(exit()));
QCoreApplication::instance()->exit() will quit the application
yes through the ui field in MainWindow see the code above
I don't know which Qt version you use, so I will suppose Qt 5.0 (signal/slot mechanims was updated).
QWidget has slot QWidget::close().
QPushButton provides signal QPushButton::clicked(bool checked = false)
So you can connect them in constructor of your MainWindow:
QObject::connect(your_button, &QPushButton::clicked, this, &QWidget::close());
Also I suggest to look into the files generated from *.ui files - so you have deeper understanding of what's going on.

QT/C++ yet another issue about accessing UI files

Although I have read the answers to this question
QT/C++ - Accessing MainWindow UI from a different class
and searched the whole www for quite some time - I don't get it working.
I was given the task to recreate an applications UI using QT Designer. Unfortunately there was already some UI spread all over several classes (the team then came across the idea, that using QT but not using the Designer however "handcoding" the UI seems to make little sense)
So now my job is to untangle the open ends, create a GUI (done that) find every possible signal and slot and put it all together to look nice and clean.
So much for the theoretical part.
Addition: I have very little experience in C++ and I seem to be getting nowhere searching for answers and don't have the time to read whole books until tomorrow, otherwise I wouldn't ask.
I am kind of going nuts about two things:
A) My mainwindow.cpp, mainwindow.h and mainwindow.ui need to be linked into other files e.g. the previewwidget.cpp...
the previewwidget.cpp had a lot of code like:
buttonLayout->addWidget(fpsSpinBox, 0, Qt::AlignCenter);
buttonLayout->addWidget(playButton, 0, Qt::AlignCenter);
buttonLayout->addWidget(backwardButton, 0, Qt::AlignCenter);
apparently I replaced it by creating the corresponding buttons in Designer.
now in the same file theres the connect SIGNAL SLOT entries (I added the "ui->")
connect(ui->playButton, SIGNAL(clicked()), this, SIGNAL(playButtonClicked()));
connect(ui->stopButton, SIGNAL(clicked()), this, SIGNAL(stopButtonClicked()));
connect(ui->forwardButton, SIGNAL(clicked()), this, SIGNAL(forwardButtonClicked()));
but the compiler keeps telling me:
\preview\previewwidget.cpp:77: Error:'ui' was not declared in this scope
I put the ui_mainwindow.h into the header but that wasn't the solution either.
B) This Question is probably related very closely to the first one: since the Designer strickly keeps model/view/controll apart I need to rewrite the signals and slots to match the new UI - has anyone got a good tutorial or any hints for me how to do this fast and uncomplicated?
Any help would be greatly appreciated.
Let's assume you have a class called MyWidget and a corresponding ui file MyWidget.ui. In order to use it in your class I would do the following:
In the MyWidget.ui set a value to the objectName. It's the first property in the Property Editor if you open the file with the Designer. I would name it MyWidget
In the MyWidget.h you have to do the following:
Declare a namespace for the ui object and forward declare it.
Add as member variable (private) a pointer to the ui object.
Sample header file follows:
#ifndef MY_WIDGET_H_
#define MY_WIDGET_H_
#include <QWidget>
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget {
Q_OBJECT
public:
MyWidget(QWidget* parent = NULL);
~MyWidget();
// Add other class functions
private:
Ui::MyWidget ui;
}
#endif // MY_WIDGET_H_
In the MyWidget.cpp
Include the automatically generated ui_MyWidget.h
Create a new ui object in the constructor
Call the setupUi function in the constructor
Delete the ui in the destructor
Sample code:
#include "MyWidget.h"
#include "ui_MyWidget.h"
MyWidget::MyWidget(QWidget *parent)
:QWidget(parent), ui(new Ui::MyWidget)
{
ui->setupUi(this);
}
MyWidget::~MyWidget()
{
delete ui;
}
Now you are ready to use the ui throughout your class. For example if you have a spin box called spinBox1 you can take its value using
int val = ui->spinBox1->value();
.ui Signals and Slots
I would advise you to use QtDesigner in order to make the connections between ui widgets and slots. Check this link for more details.
If you want to connect a widget with a custom slot you can again do it using the designer.
Switch to Edit Signals/Slots mode (F4)
Drag and drop from the widget which it to emit the signal, to the widget which is to receive the signal.
A Configure Connection dialog appears, showing the signals for the emitting widget, and the slots for the receiving widget. Click
Edit... below the slots column on the right.
A Signals/Slots of ReceivingWidget dialog appears. In here its is possible to click the plus icon beneath slots to add a new slot of
any name.
You can then go back and connect to your new slot in the Configure Connection dialog, or indeed in the Signal/Slot Editor
dockwidget back in the main window.