How can I connect a signal to QWidget::update slot? - qt

I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.

TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });

Related

Instantiate QWidget derived classes in a QObject derived class

For some reason the Qt compiler doesn't compile if you try to pass a QObject derived class as the rparent to a QWidget derived class.
What is the correct way to provide a parent to QWidget derived classes in a QObject derived class? I'm thinking of the following solutions:
Use a smart pointer with the QWidget classes, instead of giving the object a parent.
Derive from QWidget instead of QObject (Sounds wrong to me, since the class isn't a widget).
Pass a QWidget instance to the QObject derviced class which already has a parent, as I've tried to demonstrate in the example below:
#include <QApplication>
#include <QtWidgets>
class ErrorMsgDialog;
class Controller;
class MainWindow;
// This is the QWidget class used in the QObject derived class (DataReadController)
class ErrorMsgDialog : public QDialog
{
Q_OBJECT
public:
explicit ErrorMsgDialog(QWidget *parent = nullptr)
: QDialog(parent)
{
errorLbl = new QLabel("An unknown read error occured!");
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(errorLbl);
setLayout(layout);
setWindowTitle("Error!");
setGeometry(250, 250, 250, 100);
}
~ErrorMsgDialog() { qDebug() << "~ErrorMsgDialog() destructed"; }
private:
QLabel* errorLbl;
};
// QObject derived class - I want to instatiate Qwidget derived classes here, with this class as parent
class DataReadController
: public QObject
{
Q_OBJECT
public:
DataReadController(QWidget* pw, QObject *parent = nullptr)
: QObject(parent)
{
m_errorMsgDialog = new ErrorMsgDialog(pw);
//m_errorMsgDialog = QSharedPointer<ErrorMsgDialog>(m_errorMsgDialog);
//m_dataReader = new DataReader(this); m_dataReader->moveToThread(m_dataReaderThread); connect(....etc
//simulate that DataReader emits an error msg
QTimer::singleShot(2000, [&]() {
onErrorTriggered();
});
}
public slots:
void onNewDataArrived() {}
// called if reader emits an error message
void onErrorTriggered() { m_errorMsgDialog->show(); }
private:
ErrorMsgDialog* m_errorMsgDialog;
//QSharedPointer<ErrorMsgDialog> m_errorMsgDialog;
//DataReader* m_dataReader;// DataReader is not shown here, it would be moved to a different thread and provide some data
};
// MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr)
: QMainWindow(parent)
{
parentWidget = new QWidget(this);
m_dataReadController = new DataReadController(parentWidget, this);
setGeometry(200, 200, 640, 480);
//Close after 5 seconds.
QTimer::singleShot(5000, [&]() {
close();
});
}
private:
QWidget* parentWidget; // QWidget to pass to OBject derive class for parenting QWidgets
DataReadController* m_dataReadController;
};
// Main
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
This test crashes if I use QSharedPointer with ErrorMsgDialog.
Any suggestions on the way to do this? Maybe none of my suggested solutions is the best practise?
Correct storage and life-time management of dynamically created objects is not quite easy in C++. After a long time of struggling, I started to prefer certain techniques which I still use quite successful:
local variables (storage and life-time managed by scopes)
non-pointer member variables
smart pointers with clear ownership (shared pointer) or non-ownership (weak pointer).
With this, I banned raw pointers from my sources nearly completely resulting in much maintenance friendlier code and less annoying debugging.
Of course, when external libraries (like e.g. widget sets) come into play, then I am bound to their APIs.
Concerning gtkmm 2.4, the above techniques worked quite good as well. gtkmm provides
smart pointers for sharable objects
some kind of ownership for widgets concerning child widgets.
When I switched to Qt, I saw all the news and raw pointers in the tutorial samples which made me afraid a bit. After some experiments, I came to the conclusion that I will be able to write ful-featured Qt applications similar like I did before in gtkmm – without nearly any need of new by (again) defining widgets as local variables (e.g. in main()) or member variables of other classes derived (directly or indirectly) from QWidget.
Beside of this, over the time, I realized the general Qt concept of Object Trees & Ownership but I must admit that I rarely rely on this in daily business.
Concerning the specific problem of OP:
A QWidget is derived of QObject. Hence, the usual ownership principle of QObjects apply. Additionally, a QWidget expects another QWidget as parent. A QWidget may be parent of any QObjects but not vice versa.
Hence, I would suggest the following ownership:
MainWindow is parent of DataReadController
MainWindow is parent of ErrorMsgDialog (which is created in DataReadController).
DataReadController stores a pointer to ErrorMsgDialog as raw pointer. (I believe the ownership provided by a QSharedPointer would collide with the ownership of MainWindow.)
(As already described above, in my own programming, I would try to prevent pointers at all and use (non-pointer) member variables instead. However, IMHO that's a matter of style and personal preference.)
The modified sample of OP testQParentship.cc:
#include <QtWidgets>
class Label: public QLabel {
private:
const QString _name;
public:
Label(const QString &name, const QString &text):
QLabel(text),
_name(name)
{ }
virtual ~Label()
{
qDebug() << _name + ".~Label()";
}
};
class HBoxLayout: public QHBoxLayout {
private:
const QString _name;
public:
HBoxLayout(const QString &name):
QHBoxLayout(),
_name(name)
{ }
virtual ~HBoxLayout()
{
qDebug() << _name + ".~HBoxLayout()";
}
};
class ErrorMsgDlg: public QDialog {
private:
const QString _name;
public:
ErrorMsgDlg(const QString &name, QWidget *pQParent):
QDialog(pQParent),
_name(name)
{
QHBoxLayout *pQBox = new HBoxLayout("HBoxLayout");
pQBox->addWidget(
new Label("Label", "An unknown read error occured!"));
setLayout(pQBox);
setWindowTitle("Error!");
}
virtual ~ErrorMsgDlg()
{
qDebug() << _name + ".~ErrorMsgDlg()";
}
};
class DataReadCtrl: public QObject {
private:
const QString _name;
ErrorMsgDlg *const _pDlgErrorMsg;
public:
DataReadCtrl(const QString &name, QWidget *pQParent):
QObject(pQParent),
_name(name),
_pDlgErrorMsg(
new ErrorMsgDlg(name + "._pDlgErrorMsg", pQParent))
{
//simulate that DataReader emits an error msg
QTimer::singleShot(2000, [&]() {
onErrorTriggered();
});
}
virtual ~DataReadCtrl()
{
qDebug() << _name + ".~DataReadCtrl()";
}
void onErrorTriggered()
{
_pDlgErrorMsg->show();
}
};
class MainWindow: public QMainWindow {
private:
const QString _name;
DataReadCtrl *_pCtrlReadData;
public:
MainWindow(const char *name):
QMainWindow(),
_name(name),
_pCtrlReadData(nullptr)
{
_pCtrlReadData
= new DataReadCtrl(_name + "._pCtrlReadData", this);
//Close after 5 seconds.
QTimer::singleShot(5000, [&]() {
qDebug() << _name + ".close()";
close();
});
}
virtual ~MainWindow()
{
qDebug() << _name + ".~MainWindow()";
}
};
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
MainWindow winMain("winMain");
winMain.show();
// runtime loop
return app.exec();
}
and a minimal Qt project file testQParentship.pro:
SOURCES = testQParentship.cc
QT += widgets
Compiled and tested in cygwin64 on Windows 10:
$ qmake-qt5 testQParentship.pro
$ make && ./testQParentship
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQParentship.o testQParentship.cc
g++ -o testQParentship.exe testQParentship.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
After the QTimer::singleshot() in MainWindow is due, the main window is closed. The output of diagnostics illustrates that the object tree is destructed properly (instead of "thrown" away when OS releases process memory).
"winMain.close()"
"winMain.~MainWindow()"
"winMain._pCtrlReadData.~DataReadCtrl()"
"winMain._pCtrlReadData._pDlgErrorMsg.~ErrorMsgDlg()"
"HBoxLayout.~HBoxLayout()"
"Label.~Label()"

How to connect signal and slot in different classes in Qt?

I have two simple classes(class A and class B).
In a.h, I just declared a QPushButton:
QPushButton *testBtn = new QPushButton(this);
In b.h:
class B : public QMainWindow
{
Q_OBJECT
public:
explicit B(QWidget *parent = nullptr);
A testingA;
public slots:
void testing();
};
and b.cpp:
B::B(QWidget *parent) : QMainWindow(parent)
{
connect(testingA.testBtn, &QPushButton::clicked, this, &B::testing);
}
void B::testing()
{
qDebug() << "testing";
}
I am trying to connect the signal in class A to the slot in class B, but from the code I provide, it's not working.
So what is the right way to do it? Thanks
Edit:
According to PRIME's answer, I made a few changes.
In A's constructor, added:
connect(testBtn, &QPushButton::clicked, [this](){OnButtonClicked();});
to emit the own defined OnButtonClicked() signal;
and in B's construtor, changed to this:
connect(&testingA, &A::OnButtonClicked, this, &B::testing);
But when I clicked the button, the testing slot still not triggered.
Edit 2:
After doing some researches and trying a few times, I found that if I created B's object in A's constructor, and then connect A's signal to B's slot in A, it will work.
But I really can not figure out why I can not connect A's signal to B's slot in B.
This is what's in the main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
B b;
A w;
w.show();
return a.exec();
}
Is that because of some reasons that A's object is out of scope in B?
Can someone tell me where I did wrong? Thanks so much.
Don't do it like this, hide your button in the class A, emit your own defined signal from class A lets call it OnButtonClicked.
Cascading code(inside A's c'tor):
connect(testBtn , &QPushButton::clicked, [this](){OnButtonClicked();});
You will also have to declare this new signal in class A now:
So class A must have folowing besides whatever it has right now:
class A
{
Q_OBJECT
signals:
void OnButtonClicked();
};
No special slot is needed since you are using a Lambda as a slot for the signal OnButtonClicked.
Connection in class B( do it in the c'tor ):
connect(testingA, &A::OnButtonClicked, this, &B::testing);
You can connect signal-to-signal in your sender object, for example widget containing the button:
class MyWidget : public QWidget
{
Q_OBJECT
QPushButton *pushButton;
public:
explicit MyWidget(QWidget *parent = nullptr) : QWidget(parent), pushButton(new QPushButton(this)) {
connect(pushButton, &QPushButton::click, this, &MyWidget::buttonClicked);
}
signals:
void buttonClicked();
public slots:
};
By the way you would normally send signals by using emit keyword, e.g.:
emit buttonClicked();
Then the consumer:
class TestObject : public QObject
{
Q_OBJECT
public:
explicit TestObject(QObject *parent = nullptr) : QObject(parent) { }
public slots:
void onButtonClicked() {
qDebug() << "clicked";
}
};
And connect both instances:
MyWidget widget;
TestObject to;
QObject::connect(&widget, &MyWidget::buttonClicked, &to, &TestObject::onButtonClicked);
in your class A you should use the signal testing of the class B, if you clicked on your button the OnButtonClicked function will be activated
A:
public slots:
void OnButtonClicked();
void A::OnButtonClicked()
{
...
emit testing(1);
}
B:
signals:
void testing(int level);
then to connect both you can do this
connect(startButton, &QPushButton::clicked, board, &A::OnButtonClicked);

App does not close if I set QQuickView-WindowContainer as central widget

My application is designed in that way that different plugins can set the central widget of the main windows to show the desired content.
This works so far.
But if I set a QQuickView-WindowContainer as central widget, the app does not quit when I close the main window.
If I set a "normal" widget like QPushButton as central widget the appliation quits just fine. Why is that?
This is the code of a minimal example which shows this behaviour (MainWindow is a class created from the QtCreator wizard):
class AppCore : public QObject
{
Q_OBJECT
public:
explicit AppCore(QObject *parent = 0);
signals:
public slots:
void showMainWindow();
private:
MainWindow *m_mainWindow;
};
AppCore::AppCore(QObject *parent) :
QObject(parent)
{
}
void AppCore::showMainWindow()
{
QQuickView *view;
QWidget *container;
view = new QQuickView();
container = QWidget::createWindowContainer(view);
view->setSource(QUrl("qrc:/main.qml"));
m_mainWindow = new MainWindow();
//m_mainWindow->setCentralWidget(new QPushButton("Button"));
m_mainWindow->setCentralWidget(container);
m_mainWindow->show();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AppCore appCore;
appCore.showMainWindow();;
return a.exec();
}
This looks like a bug. I see a dead lock in debugger: v8::internal::RuntimeProfiler::WaitForSomeIsolateToEnterJS and QQmlDataLoader::shutdownThread wait for each other. I can't find a good workaround for this issue.
I found a dirty hack that solved the issue. If container is deleted a bit earlier, all works ok:
void MainWindow::closeEvent(QCloseEvent *e) {
QMainWindow::closeEvent(e);
if (e->isAccepted() && centralWidget()) {
delete centralWidget();
}
}
You probably should send a bug report. Note that m_mainWindow is not needed to reproduce the issue. Using container->show(); gives the same result.

SIGSEGV with QMainWindow singleton

The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!

Qt Signal from QRunnable not received/not connecting

I'm writing a Qt Application in C++. I have a QRunnable running in a QThreadPool, and it sends a signal to the main thread. The problem is, the connection doesn't work: the signal is never received by the main thread, even though I've verified that the code doing the emit is indeed called. Here is my code:
My QRunnable class:
class OfflineAnalysisThread : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
void sendMessage(QString &qmsg)
{
emit threadMessageCallback(qmsg);
}
signals:
void threadMessageCallback(QString &string);
};
And the calling class (main thread):
class OfflineAnalysisMain : public QObject
{
Q_OBJECT
public:
(...)
public slots:
void threadMsg(QString &string);
};
The code that instantiates the new QRunnables and starts them:
void OfflineAnalysisMain::myFunction()
{
OfflineAnalysisThread *newTask = new OfflineAnalysisThread();
QObject::connect(newTask, SIGNAL(threadMessageCallback(QString &)), this, SLOT(threadMsg(QString &)));
QThreadPool::globalInstance()->start(newTask);
}
So, from my QRunnable's run function, I call sendMessage and then I do QApplication::exec(). I have a breakpoint on the threadMsg slot implementation in OfflineAnalysisMain.cpp, and that function is never called.
What am I doing wrong?
UPDATE:
Definition of my OfflineAnalysisThread::run() function:
void OfflineAnalysisThread::run()
{
std::string myMsg("This is my message");
sendMessage(myMsg);
QApplication::exec();
}
I have also tried without the QApplication::exec();, without success.
Remove the call to QApplication::exec() from within run(). This is ideally called from within your main function.
In order to get your code to work, I had to write the following main function:
#include <QApplication>
#include <QMetaType>
#include <offlineanalysismain.h>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<QString>("QString&");
OfflineAnalysisMain* main = new OfflineAnalysisMain;
main->myFunction();
return app.exec();
}
Note the call to qRegisterMetaType, which allows Qt to pass a QString through a signal-slot connection that cross thread boundaries.

Resources