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.
Related
I have a complex widget on the screen which is visible. By pushing a button a dialog appears but parts of the original widget is still visible. When closing the dialog I would like to refresh some data of my particular widget ... but this widget does not know anything about that dialog. Is there any event I can check for this purpose ? Or any other way to get to know when the dialogs closed ?
First I used
virtual void QWidget::showEvent( QShowEvent* event );
but it is not called when the parts of the widget is already visible.
EDIT
I'm sorry but I wasn't precise enough. When I wrote complex, I meant that I have a main window, which has a child widget which also has child widget and so on (for about file level). That lowest level child widget initiates the opening of the dialog. The other widget which needs the closing event of this dialog is also an embedded widget but somewhere else in the application. When I wrote sending the signal through many classes I meant this. In this case if want to notify my final widget I have to connect the closing signal from my source widget to several intermediate widgets which does not even interested in that signal. I also didn't want to (and can't) connect these signal/slot in the main window because of the mentioned structure. In this is there any advice ?
send the signal through many objects just for this purpose
There's no such thing as sending a signal "through" objects unless you insist on manually threading it through a bunch of them. So this doesn't make much sense unless you explain why you want to "thread" the signal through many objects ("threading" as in a string through a needle, not as in a processing thread).
A signal-slot connection has two endpoints. All you need is:
A signal at the dialog.
A slot at the supercomplex widget.
A connection set up outside of both of them. To make life simple, both the widget and the dialog could be instantiated in main(), and a connection set up before anything even appears on the screen.
The dialog signal you're looking for is simply QDialog::finished, if you have a properly designed dialog. Otherwise, use an EventSignaler of some sort to convert a QEvent::close to a signal.
The slot in the supercomplex widget should be e.g.:
Q_SLOT void refreshSomething();
Its signature/name shouldn't refer to the fact that some dialog was closed: that's coupling the API too much to the external detail of some dialog being there. The slot should get the dialog to update/refresh what you need. The reasons for invoking it are irrelevant to the widget.
Inside the widget, the slot's implementation should most likely simply call update() on one or more subwidgets, perhaps with a relevant region - if you wish to, you can have the region as an optional slot parameter.
See this question about how to forward signals or slots inside of a complex composite class that contains many objects. It's supposed to be very simple; if it's not you'll have to edit the question to indicate why it's complex for you.
At the simplest, with the most decoupled code - where the dialog knows nothing about the widget, and vice versa - as it should be, you can have:
class Dialog : public QDialog { ... };
class Widget : public QMainWindow {
Q_OBJECT
Q_SIGNAL void showDialog();
Q_SLOT void refreshSomething();
...
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
...
Widget widget;
Dialog dialog;
QObject::connect(&widget, &Widget::showDialog, &dialog, &QWidget::show);
QObject::connect(&dialog, &QDialog::finished, &widget, &Widget::refreshSomething);
widget.show();
return app.exec();
}
I want to be able to enable and disable filtering mouse clicks on my entire QMainWindow by pressing a button or a key which will cause filtering to start. I want to enable the event filter from inside a class, QMainWindow.
I want to be able to have a eventfilter inside my class we can call MyWindow, from what i've found i'm supposed to make a new class MouseFilter, redefine eventFilter(QObject* object,QEvent* event) and install it on myWindow
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MyWindow w;
w.installEventFilter(new MouseFilter());
w.show();
return a.exec();
}
Is there a way I can implement the event filter from inside my object?
Solution
I think I may have been over-complicating things. It as simple as subclassing mousePressEvent.
void MouseFilter::mousePressEvent(QMouseEvent * event){
if(event->button() == Qt::RightButton){
qDebug() << "Right-o";
}
}
I think what you're looking for is the mousePressEvent which you can override from within MyWindow
Cheers,
Rostislav.
An event filter is used to filter events on their way to another object. An event handler allows you implement event handling logic. An event filter is also an event handler, but it works by intercepting events, bound to be received by other objects, and decide whether and how to pass through to the destination.
What you want to do sounds like you are only looking to implement an event handler. So no event filter is necessary.
An event filter is useful when you want to block or translate events, or to alter the behavior of some object whose event handling you can't or don't want to override.
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.
I have created a set of watcher/helper classes that monitor an outside application, and I would like these to print to a log window inside my MainWindow's ui when changes are made. My idea was to create this watcher inside a thread in main, but I am not sure the best way to link it to my MainWindow. I know that simply passing it as below will not work, but am unsure of the proper way to do this, if there even is one, because of Qt's design. Some research indicated to me that it isn't really appropriate to pass MainWindow to an outside class, but I am unsure of a better way to do it.
int main(int argc, char *argv[])
{
try {
std::string host = "localhost";
unsigned short port = 8193;
MainWindow w;
w.show();
// Access class for the program that I am watching
UserInterface ui(host, port);
// StatePrinter class, which is registered in the UI and will print changes to MainWindow, ideally
// would I be able to pass something in the StatePrinter constructor to accomplish my goal?
ui.registerObserver(new StatePrinter(w));
UiRunner runner(ui);
boost::thread runnerThread(boost::ref(runner));
w.show();
QApplication a(argc, argv);
runner.cancel();
runnerThread.join();
return a.exec();
} catch(std::exception &ex) {
// ...
}
}
I suppose it is a possibility to make this thread inside MainWindow itself, but I prefer having it in main. What would be the best way to link my StatePrinter class to MainWindow?
You could make your watcher class a QObject itself, push it into a thread, and make it emit signals when it "notices" changes that you want to log with the log informations as the signal parameters.
Then, you could push this object in a QThread as follow :
QThread* thread = new QThread();
ui->moveToThread(thread);
//Create the needed connections
thread->start();
Depending on what you need, you may connect a signal to the thread's start() slot instead of calling it directly. (Read this to know which connections you'll need with your thread so it is started, stopped and cleaned correctly).
You have several problems:
Creating widgets before instance of QApplication
runnerThread.join call will block main Qt thread before entering Qt event loop - so your GUI will be freezed
You should implement notification system to watch for termination of boost threads. But better solution is to use Qt threads.
You should create first class - "watcher" with neccessary signals.
Then create second class with UI logic and neccessaty slots
Then connect signals to slots
Profit!
Look at Qt documentation about QThread - there are simple samples.
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.