I'm having some problem with understanding usage of parent pointer in QT4.
class firstClass : public QWidget
{
Q_OBJECT
public:
firstClass(QWidget *parent = 0);
~firstClass();
void doSomething();
private:
secondClass * myClass;
};
class secondClass : public QWidget
{
Q_OBJECT
public:
secondClass(QWidget *parent = 0);
void doSomethingElse();
};
I want to call doSomething() method while running doSomethingElse(). Is there any way to do it using parent pointer?
I tried parent->doSomething() but it doesn't work. It seems that Qt Creator is suggesting only methods from QObject class after parent->.
On the other hand I can't write it like secondClass(firstClass *parent = 0); - compilator returns error:
Thanks for any suggestions.
If you are positive that the parent of secondClass is always going to be firstClass then you can do this:
static_cast<firstClass *>(parent)->doSomething();
Alternatively you can use qobject_cast and check to make sure that parent is actually an instance of firstClass:
firstClass *myParent = qobject_cast<firstClass *>(parent);
if(myParent){
myParent->doSomething();
}
The more Qt-ish way to do this would be to use signals and slots, instead of trying to directly call a different function.
class firstClass : public QWidget
{
Q_OBJECT
public:
firstClass(QWidget *parent = 0);
~firstClass();
public slot:
void doSomething();
private:
secondClass * myClass;
};
class secondClass : public QWidget
{
Q_OBJECT
public:
secondClass(QWidget *parent = 0);
void doSomethingElse()
{
// ...
emit ( triggerDoSomething() );
// ...
}
signal:
void triggerDoSomething();
};
firstClass::firstClass(QWidget *parent) :
QWidget(parent), myClass(new secondClass(this))
{
// ...
bool connected = connect(myClass, SIGNAL(triggerDoSomething()),
SLOT(doSomething()));
assert( connected );
}
Related
I have a class which I am exposing to QML as follows:
#ifndef MYTYPE_H
#define MYTYPE_H
#include <QString>
#include <QObject>
class MyType : public QObject
{
Q_OBJECT
Q_ENUMS(TestEnum)
Q_PROPERTY(TestEnum foo READ foo WRITE setFoo NOTIFY fooChanged)
public:
enum class TestEnum
{
State1 = 1,
State2 = 2
};
MyType(QObject *parent = nullptr) :
QObject(parent),
mFoo(TestEnum::State1)
{
}
TestEnum foo() const
{
return mFoo;
}
void setFoo(TestEnum foo)
{
if (foo == mFoo)
return;
mFoo = foo;
emit fooChanged(mFoo);
}
signals:
void fooChanged(MyType::TestEnum blah);
private:
TestEnum mFoo;
};
Q_DECLARE_METATYPE(MyType::TestEnum)
#endif // MYTYPE_H
Here I have an enumeration type which I would like to expose to QML.
I register the type n my main function call as:
qmlRegisterType<MyType>("App", 1, 0, "MyType");
Now I have a signal in my qml file which I takes this enumeration parameter:
signal submitTextField(MyType::TestEnum state) // Compiler complains here
The signal is connected as:
QObject *topLevel = engine.rootObjects().value(0);
//QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
// This is just a class that implements the slot
HandleTextField handleTextField;
// connect our QML signal to our C++ slot
QObject::connect(topLevel, SIGNAL(submitTextField(MyType::TestEnum)),
&handleTextField, SLOT(handleSubmitTextField(MyType::TestEnum)));
The class that implements the slot is defined as:
class HandleTextField : public QObject
{
Q_OBJECT
public:
explicit HandleTextField(QObject *parent = 0);
public slots:
void handleSubmitTextField(MyType::TestEnum in);
void handleFooChanged(MyType::TestEnum in);
public:
MyType myType;
};
The syntax MyType::TestEnum is not valid. I am tempted to convert everything to ints and do away with the enumeration but wondering if there is a way to use this enumeration type in a QML signal. I can do MyType.State1 and MyType.State2 but unable to refer to the enumeration type.
Ok, it does not seem like this can be done with enums i.e. you have to use ints. I made the following change and it works:
class MyType : public QObject
{
Q_OBJECT
Q_ENUMS(TestEnum)
Q_PROPERTY(TestEnum foo READ foo WRITE setFoo NOTIFY fooChanged)
public:
enum TestEnum
{
State1 = 1,
State2 = 2
};
MyType(QObject *parent = nullptr) :
QObject(parent),
mFoo(TestEnum::State1)
{
}
TestEnum & foo()
{
return mFoo;
}
void setFoo(TestEnum foo)
{
if (foo == mFoo)
return;
mFoo = foo;
emit fooChanged(static_cast<int>(mFoo));
}
signals:
void fooChanged(int blah);
private:
TestEnum mFoo;
};
Q_DECLARE_METATYPE(MyType::TestEnum)
The slots need to be changed as well:
class HandleTextField : public QObject
{
Q_OBJECT
public:
explicit HandleTextField(QObject *parent = 0);
public slots:
void handleSubmitTextField(int in);
void handleFooChanged(int in);
public:
MyType myType;
};
We need to change the connections for int type:
QObject::connect(topLevel, SIGNAL(submitTextField(int)),
&handleTextField, SLOT(handleSubmitTextField(int)));
and finally the signal is declared as:
signal submitTextField(int text)
I have a little problem with the Qt class QGraphicsScene:
To detect the current mouse coordinates I made a new class QGraphicsScenePlus with QGraphicsScene as the base class. I have already redefined the slot function mouseMoveEvent(QGraphicsSceneMouseEvent* event) and the received coordinates seem to be correct. Now I want to notify the parent QMainWindow class, where the QGraphicsScenePlus object is stored, whenever the mouse coordinates change. What is the best way to do this? I already tried to define signals and slots, but it didn't work. The slot function wasn't found during the execution of the program.
Here is the code so far:
qgraphicssceneplus.h
#ifndef QGRAPHICSSCENEPLUS_H
#define QGRAPHICSSCENEPLUS_H
#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
class QGraphicsScenePlus : public QGraphicsScene {
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
public:
int mx = 0;
int my = 0;
};
#endif // QGRAPHICSSCENEPLUS_H
qgraphicssceneplus.cpp
#include "qgraphicssceneplus.h"
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
this->update();
}
Comment
I am not sure how you made the above code compiled.
1. Even though you subclass from a QObject, you still need the Q_OBJECT macro to keep meta-object compiler informed:
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT // <--- You miss this
public:
QGraphicsScenePlus(QObject* parent = 0);
2. It's not allowed to assign primitive value in C++ class definition, do it in the constructor instead:
public:
int mx /*= 0*/;
int my /*= 0*/;
};
Solution
As for your question:
What is the best way to do this? I already tried to define signals and slots, but it didn't work.
The best way is still Signals & Slots.
Code
qgraphicssceneplus.h
class QGraphicsScenePlus : public QGraphicsScene {
Q_OBJECT
public:
QGraphicsScenePlus(QObject* parent = 0);
public slots:
void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
signals:
void sendCoord(int,int); // for sending the information of coordinates
public:
int mx;
int my;
};
qgraphicssceneplus.cpp
QGraphicsScenePlus::QGraphicsScenePlus(QObject* parent) : QGraphicsScene(parent) {
mx = 0;
my = 0;
}
void QGraphicsScenePlus::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent) {
mx = mouseEvent->scenePos().x();
my = mouseEvent->scenePos().y();
emit sendCoord(mx, my); // emit the signal
this->update();
}
To catch the signal, define the slot in QMainWindow. For example:
public slots:
void receiveCoord(int x, int y);
and connect it to the signal of your graphic scene.
Demo
I am using QT framework. I have been using SIGNAL-SLOT for a while. I like it. :-)
But I cannot make it work when I use QThread. I always create new thread using “moveToThread(QThread …)” function.
Any suggestion? :-)
The error message is:
Object::connect: No such slot connection::acceptNewConnection(QString,int) in ..\MultiMITU600\mainwindow.cpp:14
Object::connect: (sender name: 'MainWindow')
I have read about similar problems but those were not connected to QThread.
Thanks, David
EDITED: you asked for source code
Here is one:
Here is the code:
The main class which contains the signal and the new thread:
mainwindow header:
class MainWindow : public QMainWindow
{
…
QThread cThread;
MyClass Connect;
...
signals:
void NewConnection(QString port,int current);
…
};
The constructor of the above class: .cpp
{
…
Connect.moveToThread(&cThread1);
cThread.start(); // start new thread
….
connect(this,SIGNAL(NewConnection(QString,int)),
&Connect,SLOT(acceptNewConnection(QString,int))); //start measuring
…
}
The class that contains the new thread and SLOT
Header:
class MyClass: public QObject
{
Q_OBJECT
….
public slots:
void acceptNewConnection(QString port, int current);
}
And the .cpp file of the above class:
void MyClass::acceptNewConnection(QString port, int current){
qDebug() << "This part is not be reached";
}
Finally I use emit in the class where the connection was made:
void MainWindow::on_pushButton_3_clicked()
{
…
emit NewConnection(port, 1);
}
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0);
public slots:
void acceptConnection(QString port, int current) {
qDebug() << "received data for port " << port;
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0) : QMainWindow(parent) {
myClass.moveToThread(&thread);
thread.start();
connect(this, SIGNAL(newConnection(QString,int)), &myClass, SLOT(acceptConnection(QString,int)));
emit newConnection("test", 1234);
}
signals:
void newConnection(QString, int);
private:
QThread thread;
MyClass myClass;
};
output:
received data for port "test"
Is your void MainWindow::on_pushButton_3_clicked() slot connected to a signal?
Also, for the sake of the clarity and readability of your code, keep the established naming convention and use lower case for object instances and member objects and methods.
I have
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void getData();
private:
Ui::MainWindow *ui;
Dialog *second;
};
and
class Dialog: public QDialog {
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0); QDialog * dialog;
QPushButton *pushButton;
QPushButton *pushButton_2;
};
and I can connect pushbuttons in class Dialog with function getData() in class MainWindow (Dialog is a child of class Mainwindow)
I tried
connect(*second->pushButton, SIGNAL(clicked()), this,
SLOT(getData()));
but I got
error: no matching function for call to
‘MainWindow::connect(QPushButton&, const char [11], MainWindow* const, const char [11])’
How do i connect them?
if the dialog is child of QMainWindow subclass (as it would be) you should have something like:
MainWindow::MainWindow(...)
{
....
m_dialog = new Dialog(this);// in .h file it is defined as: "Dialog *m_dialog;"
....
connect(m_dialog->pushButton, SIGNAL(clicked()), this,SLOT(getData()));
}
you don't have to write:
connect(*m_dialog->pushButton, SIGNAL(clicked()), this,SLOT(getData()));
take a look at this qt code:
Counter a, b;
QObject::connect(&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
a.setValue(12); // a.value() == 12, b.value() == 12
b.setValue(48); // a.value() == 12, b.value() == 48
as you can see you must use pointer and not QObject.
I have MainWindow and QNAMRedirect classes and I am trying to compile program but getting compiler error.
Here is QNAMRedirect class:
class QNAMRedirect : public QObject
{
Q_OBJECT
public:
explicit QNAMRedirect(QObject *parent = 0);
~QNAMRedirect();
signals:
public slots:
void doRequest();
void replyFinished(QNetworkReply* reply);
signals:
void finished(QString);
private:
QPointer<QNetworkAccessManager> _qnam;
QUrl _originalUrl;
QUrl _urlRedirectedTo;
QNetworkAccessManager* createQNAM();
};
and here is MainWindow class:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_request_clicked();
private:
Ui::MainWindow *ui;
};
and i am trying to connect NAMRedirect::finished(QString) signal to QTextEdit widget in MainWindow this way:
void MainWindow::on_request_clicked()
{
QNAMRedirect urlGet(this);
QObject::connect(urlGet,SIGNAL(finished(QString)),ui->textEdit,SLOT(setText(QString)));
urlGet.doRequest();
}
but i am getting compiler error:
error: no matching function for call to 'MainWindow::connect(QNAMRedirect&, const char*, QTextEdit*&, const char*)'
how can i fix that?
The reason for the compile error is that the two objects you pass to the connect() function need to be pointers. So using &urlGet (instead of just urlGet) will fix your compile error. However, as soon as your function returns this object will go out of scope and be destroyed, so I suggest you change your function to look something more like this:
QNAMRedirect *urlGet = new QNAMRedirect( this )
QObject::connect(urlGet,SIGNAL(finished(QString)),ui->textEdit,SLOT(setText(QString)));
urlGet->doRequest();
You will, of course, need to take measure that you're not leaking memory here.