So let's suppose I've got a regular Qt class MyQtClass and a class MyClass with ONLY static members. If I want to access the ui of MyQtClass I have to use Signals and Slots. So I create a static Signal (static so I can just invoke it like MyClass::mySignal();) and a slot in the Qt class. How can I connect the static signal from MyClass with the slot from the Qt class, without having an object of MyClass, since it has only got static members?
I know that classes with only static members isn't considered as a good design in c++ but I'm too far into the project by now and I want to know if there's a way to do it with only static members.
Thanks in Advance!
Code:
MyQtClass.h:
#include "ui_MyQtClass.h"
class MyQtClass : public QMainWindow
{
Q_OBJECT
public:
MyQtClass(QWidget *parent = Q_NULLPTR);
Q_SLOT void mySlot();
private:
Ui::MyQtClassClass ui;
};
MyClass.h:
#pragma once
#include <QtWidgets/QMainWindow>
class MyClass : public QObject
{
public:
static void myFunction1();
static void myFunction2();
/*--- More Stuff ---*/
Q_SIGNAL static void mySignal();
};
As indicated in this thread it is not possible to emit static signals since it is always associated with a QObject, as an alternative they create a singleton that would be equivalent to what you want.
#include <QtCore>
class Receiver: public QObject
{
Q_OBJECT
public:
using QObject::QObject;
Q_SLOT void mySlot(){
qDebug()<< __PRETTY_FUNCTION__;
QCoreApplication::quit();
}
};
class Sender: public QObject
{
Q_OBJECT
using QObject::QObject;
public:
static Sender& instance(){
static Sender m_instance;
return m_instance;
}
static void myFunction1(){
emit instance().mySignal();
}
Q_SIGNAL void mySignal();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Receiver r;
QObject::connect(&Sender::instance(), &Sender::mySignal, &r, &Receiver::mySlot);
QTimer::singleShot(1000, &Sender::myFunction1);
return a.exec();
}
#include "main.moc"
Related
I implemented a hierarchy of classes to handle sensor interaction in a multithreaded QThread-based manner, as how it is recommended in Qt documentation. Here I have the header file types.h with the abstract base sensor reader class:
#include <QtCore>
class QAbstractSensorReader: public QObject
{ Q_OBJECT
protected slots:
virtual void ReadData() = 0;
public slots:
virtual void RunPoll() = 0;
signals:
void acquired();
};
In the file serial.h implementing the actual sensor reader I have the following text:
#include "types.h"
class QBaseSerialSensorReader: public QAbstractSensorReader
{
Q_OBJECT
private:
/*===*/
protected:
QTextStream ttyout;
QTimer* poll_timer;
virtual void ReadData();
public:
QBaseSerialSensorReader(const QString device);
virtual ~QBaseSerialSensorReader();
virtual void RunPoll();
};
The signal acquired() is emitted in the ReadData() handler when the data packet is assembled completely during the sensor poll. The slot RunPoll() is used to initialize and start a timer. Then I implemented the controller class:
#include "serial.h"
class QSensor: public QObject
{
Q_OBJECT
private:
QThread reader_thread;
QBaseSerialSensorReader* reader;
public:
QSensor()
{
reader = new QBaseSerialSensorReader();
reader->moveToThread(&reader_thread);
connect(&reader_thread, &QThread::finished, reader, &QObject::deleteLater);
connect(this, &QSensor::RunReader, reader, &QAbstractSensorReader::RunPoll);
connect(reader, &QBaseSerialSensorReader::acquired, this, &QSensor::Packet);
reader_thread.start();
}
void Start() {emit RunReader();}
virtual ~QSensor();
public slots:
void Packet(){ttyout << "ACQUIRED!";}
signals:
void RunReader();
};
Then the application:
#include "controller.h"
int main(int argc, char** args)
{
QCoreApplication app(argc, args);
QSensor sensor();
sensor.Start();
sleep(10);
return 0;
}
exploits the hierarchy.
The CMake file contains the following text:
find_package(Qt5 REQUIRED COMPONENTS Core SerialPort)
set(CMAKE_AUTOMOC ON)
qt5_wrap_cpp(MOC_SOURCES
include/types.h
include/serial.h
include/contoller.h
)
set(LIBRARY_SOURCES
${MOC_SOURCES}
src/util.cpp
src/serial.cpp
src/controller.cpp
)
add_library(sensor-serial SHARED ${LIBRARY_SOURCES})
target_link_libraries(sensor-serial Qt5::Core Qt5::SerialPort)
add_executable(library-init-test
tests/library-init-test.cpp
)
target_link_libraries(library-init-test
Qt5::Core Qt5::SerialPort
sensor-serial
)
The problem is that the signal QSensor::RunReader is successfully connected to QAbstractSensorReader::RunPoll slot: the virtual function QBaseSerialSensorReader::RunPoll() is called. The timer is also started and the ReadData() function works emitting the acquired signal. But this signal then does not seem to be connected to the QSensor::Packet() slot neither from QAbstractSensorReader nor from QBaseSerialSensorReader namespace.
Could you please try to explain what wrong is happening with this code?
You are not entering application event loop. Remove sleep from main function and call QCoreApplication::exec. I.e. replace these lines
sleep(10);
return 0;
with
return app.exec();
In the main.cppi'm creating a singleton type of a class to use it in qml with the following function:
qmlRegisterSingletonType<DataloopWrapper>("com.xpto.connector", 1, 0, "DataloopWrapper",&DataloopWrapper::qmlInstance);
a bit down on the main.cpp i call a function of another object where i want to call a function from that singleton
maybe something like this qmlTranslator.loadLanguage(lang, DataloopWrapper::qmlInstance); is possible?
I'm declaring QmlTranslatorclass the following way:
#ifndef QMLTRANSLATOR_H
#define QMLTRANSLATOR_H
#include <QObject>
#include <QTranslator>
#include <QQmlEngine>
#include <QGuiApplication>
class QmlTranslator : public QObject
{
Q_OBJECT
public:
QmlTranslator(QQmlEngine *engine, QGuiApplication *app);
Q_INVOKABLE void selectLanguage(QString language);
void InstallTranslator();
void loadLanguage(QString language, QObject*(QQmlEngine*,QJSEngine*) objDataloop);
virtual ~QmlTranslator();
signals:
void languageChanged();
private:
QTranslator *_translator;
QQmlEngine *_engine;
QGuiApplication *_app;
};
#endif // QMLTRANSLATOR_H
I'm not finding a way to pass DataloopWrapper::qmlInstanceas argument. At least it gives error in void loadLanguage(QString language, QObject*(QQmlEngine*,QJSEngine*) objDataloop);on the qmlTranslator definition.
From a public: Members of DataloopWrapperi have the defenition of qmlInstance, it's this:
class DataloopWrapper : public QObject, public something::DataloopCBHandler,
public something::DataloopTransferCBHandler
{
Q_OBJECT
public:
explicit DataloopWrapper(QObject *parent = nullptr);
virtual ~DataloopWrapper();
static QObject *qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
return new DataloopWrapper;
}
DataloopWrapper::qmlInstance is a function, that you need to call in order to get a pointer to a QObject.
For for any function you want to pass this object, you need to make it accept a pointer to a QObject (type QObject*), and don't forget to call DataloopWrapper::qmlInstance.
Translated into code:
class QmlTranslator : public QObject
{
...
void loadLanguage(QString language, QObject* objDataloop);
...
};
...
qmlTranslator.loadLanguage(lang, DataloopWrapper::qmlInstance(aQMLEngineObjectPointer, aQJSEnginePointer));
I'm new to programming. I can not understand how to make a reference to the methods of another class.
I have several files and classes:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtCore/QtGlobal>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class Valve;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void openValve(int id);
void closeValve(int id);
private:
Ui::MainWindow *ui;
Settings *settings;
Valve *valve;
};
class A {
...
private:
void start();
}
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowFlags(Qt::CustomizeWindowHint);
this->setFixedSize(this->geometry().width(),this->geometry().height());
//класс для 7 клапанов
valve = new Valve(7);
}
MainWindow::~MainWindow()
{
delete settings;
delete ui;
}
void MainWindow::valveSwitch(int id)
{
if (valve->getState(id))
closeValve(id);
else
openValve(id);
}
void MainWindow::openValve(int id)
{
QString str = "Valve №" + QString::number(id);
valveButton[id-1]->setEnabled(false);
if (valve->open(id)) {
valveButton[id-1]->setEnabled(true);
//valveButton[id-1]->setPalette(QPalette(Qt::green));
//valveButton[id-1]->setStyleSheet(VALVE_OPEN_COLOR);
QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON);
valveButton[id-1]->setStyleSheet(style);
ui->mainLabel->setText(str + " open! :)");
}
else {
valveButton[id-1]->setEnabled(true);
ui->mainLabel->setText("Cant open " + str);
remoteDisconnect();
}
}
void MainWindow::closeValve(int id)
{
QString str = "Valve №" + QString::number(id);
valveButton[id-1]->setEnabled(false);
if (valve->close(id)) {
valveButton[id-1]->setEnabled(true);
//valveButton[id-1]->setPalette(style()->standardPalette());
valveButton[id-1]->setStyleSheet("");
ui->mainLabel->setText(str + " close! :)");
}
else {
valveButton[id-1]->setEnabled(true);
ui->mainLabel->setText("Cant close " + str);
remoteDisconnect();
}
}
A::A
{
}
A::~A
{
}
void A::start()
{
//MainWindow::openValve(2);
//valve.open(3);
}
How do I access MainWindow class methods openValve/closeValve from class A?
Or how can I access an instance valve of a class Valve of MainWindow's constructor from class A?
//MainWindow::openValve(2);
//valve.open(3);
At very first:
openValve is not static, so you need an instance of MainWindow to be able to call it:
MainWindow* mw_ex0;
// alternatively, if more appropriate:
MainWindow& mw_ex1;
mw_ex0->openValve(2);
mw_ex1.openValve(2);
The MainWindow instance could be a parameter of your function start or a member variable of class A – depending on your concrete needs.
Same applies if you want to access the valve member (valve is a pointer, so you need operator->): mw_ex0->valve->open(3); or mw_ex1.valve->open(3);).
However, you need to grant class A access to those currently private members; three options:
Make A a friend class of MainWindow - this allows A to access MainWindow's private members (might apply for Valve class, too, if open is not public).
Make the appropriate functions public (MainWindow::openValve and Valve::open); to access the valve member of MainWindow, too, you could make it public, too, but it is in general not recommendable to make the internals of a class publicly available to the outside world - someone might simply change your valve member to something else - and your program is broken... So rather provide a simple getter for.
Make A an inner class of MainWindow. Then it gets access to its outer class members implicitly (depending on the requirements for class A, this might not be suitable – up to you to decide...).
Sidenotes:
In your constructor, you do not initialise the settings member.
You do not clean up the valve member in your destructor (potential memory leak).
To avoid having to clean up, you could to incorporate valve directly in your class - this is not always suitable, but might be a good option here (up to you to decide, just showing the alternative):
class MainWindow
{
Valve valve;
};
MainWindow::MainWindow()
: valve(7) // calls constructor directly
{ }
Be aware that you now do use operator. to access the valve's members (mw_ex0->valve.open(3);). Advantage is that Valve will no be automatically cleaned up together with MainWindow. Alternatively, a std::unique_ptr could be used to hold the pointer to your Valve instance, then you get automatic cleanup, too.
You should pass a MainWindow object into the A::start method:
class A {
...
private:
void start(MainWindow & w);
}
void A::start(MainWindow & w) {
w._MainWindow_method_name_here_();
}
Or you should declare a static method in MainWindow class:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static void aStaticMethod();
};
void MainWindow::aStaticMethod() {
...
}
void A::start() {
MainWindow::aStaticMethod();
}
To access protected/private methods of MainWindow you should declare the A class as a friend of MainWindow:
class MainWindow : public QMainWindow
{
friend class A;
...
};
Update
I create a new class for it to work in a separate thread, and call its methods from the main class (by clicking on the button). Accordingly, I need class A to open / close valves, etc.
The "true Qt way" is to use signals & slots mechanism.
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// Transform open/closeValve methods into slots
// (a method that can be assigned as an event handler)
//
public slots:
void openValve(int id);
void closeValve(int id);
private:
Ui::MainWindow *ui;
Settings *settings;
Valve *valve;
};
// This class should be a descendant of QObject
//
class A : public QObject
{
Q_OBJECT
// Transform this method to a slot, so it can be called
// as regular method, or can be assigned as an event handler,
// for instance, as QPushButton::click handler.
//
public slots:
void start();
// Add signals
//
signals:
void openValveSignal(int id);
void closeValveSignal(int id);
}
void A::start()
{
// do something and then emit the signal to open valve,
// MainWindow::openValve(2) will be called
emit openValveSignal(2);
...
// do something and then emit the signal to close valve,
// MainWindow::closeValve(3) will be called
emit closeValveSignal(3);
}
// connects A signals with MainWindow slots,
// so when you `emit A::***Signal()` then corresponding
// `MainWindow::***` method will be called
//
void initialize(MainWindow * pWnd, A * pA)
{
QObject::connect(pA, &A::openValveSignal, pWnd, &MainWindow::openValve);
QObject::connect(pA, &A::closeValveSignal, pWnd, &MainWindow::closeValve);
}
You can call a->start() method from MainWindow methods as usual. Or you can connect button clicked signal with A::start method, for instance:
void initialize(MainWindow * pWnd, QAbstractButton * pBtn, A * pA)
{
// C++11 lambda function is used here because A::start has no arguments
QObject::connect(pBtn, &QAbstractButton::clicked, [pA](){ pA->start(); });
QObject::connect(pA, &A::openValveSignal, pWnd, &MainWindow::openValve);
QObject::connect(pA, &A::closeValveSignal, pWnd, &MainWindow::closeValve);
}
so when you click a button then A::start method will be called automatically. And then MainWindow::open/closeValve methods will be called from A::start method.
Declare openValve as public method and valve as public object (open must be public too)
Then use as:
MainWindow mainWindow;
mainWindow.openValve(2);
mainWindow.valve.open(3);
I've got a c++ code including GUI, in which I need to run a time consuming loop for optimization.
class OptimizationAlgorith(data *data);
{
private:
var var1;
var var2;
public:
method1();
method2();
..
timeConsumingMethod(data);
}
this need to be called in a GUI class like following:
class QRegistration: public QWidget
{
Q_OBJECT
private:
data *m_data;
QPushButton *m_button_run;
OptimizationAlgorithm *m_optimizationalgorithm;
WorkerThread *m_workerThread;
QThread *m_thread;
..
private slots:
void on_pushButton_run_clicked();
void registrationDone();
I need to move the timeConsumingMethod into a seperate thread than main thread, so that the GUI does not freez while timeConsumingMethodis running.
I have made a new class "WorkerThread" using the official documentation of Qt, which looks like:
class WorkerThread : public QObject
{
Q_OBJECT
public:
WorkerThread(ApplicationData* data, QOptimizationAlgorithm * OptimizationAlgorithm);
~WorkerThread();
public slots:
void run(data* data);
signals:
void finished();
private slots:
private:
OptimizationAlgorithm *m_OptimizationAlgorithm;
ApplicationData *m_data;
}
How shoud I now implement my run()in WorkerThread? Can I simply write:
void WorkerThread::run(data *m_data)
{
m_optimization.timeConsumingMethod(m_data);
emit finished();
}
or do I have to copy the whole definition of timeConsumingMethod in run()? Why/Why not?
You don't need to do any explicit thread management, Qt already does it for you. Use QtConcurrent::run to do the work in a worker thread from the thread pool.
You should also decouple the controller that manages the work, and the UI. The knowledge of how to couple these objects should be separate from the objects themselves. This allows more flexibility in the design of the UI and the controller, and helps avoid several classes of errors that stem from accessing non-thread-safe methods from incorrect threads.
Complete example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/threadwork-simple-40865259
#include <QtWidgets>
#include <QtConcurrent>
struct ApplicationData {};
struct OptimizationAlgorithm {
void timeConsumingMethod(QSharedPointer<ApplicationData>) {
QThread::sleep(3);
}
};
class Controller : public QObject {
Q_OBJECT
QSharedPointer<ApplicationData> m_data{new ApplicationData};
OptimizationAlgorithm m_algorithm;
public:
Q_SLOT void run() {
QtConcurrent::run([this]{
emit busy();
m_algorithm.timeConsumingMethod(m_data);
emit finished();
});
}
Q_SIGNAL void busy();
Q_SIGNAL void finished();
};
class Registration : public QWidget {
Q_OBJECT
QVBoxLayout m_layout{this};
QLabel m_status{"Idle"};
QPushButton m_run{"Run"};
public:
Registration() {
m_layout.addWidget(&m_status);
m_layout.addWidget(&m_run);
connect(&m_run, &QPushButton::clicked, this, &Registration::reqRun);
}
Q_SIGNAL void reqRun();
Q_SLOT void onBusy() { m_status.setText("Running"); }
Q_SLOT void onFinished() { m_status.setText("Idle"); }
};
void setup(Registration *reg, Controller *ctl) {
using Q = QObject;
Q::connect(reg, &Registration::reqRun, ctl, &Controller::run);
Q::connect(ctl, &Controller::busy, reg, &Registration::onBusy);
Q::connect(ctl, &Controller::finished, reg, &Registration::onFinished);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Controller ctl;
Registration reg;
setup(®, &ctl);
reg.show();
return app.exec();
}
#include "main.moc"
I have a problem with accessing ui elements from another class(with instance). I have a second QMainWindow in my application, I can access in secondWindow.cxx class all ui elements but not in read.cxx class. My code looks like following. Where is my mistake? Thank you for your help.
-------------------------------secondWindow.h------------------------------------
#ifndef __secondWindow_h
#define __secondWindow_h
#include "ui_secondwindow.h"
class secondWindow : public QMainWindow
{
friend class read;
igstkStandardClassBasicTraitsMacro(secondWindow, QMainWindow);
Q_OBJECT
public:
igstkStateMachineMacro();
secondWindow();
virtual ~secondWindow();
void createSignalAndSlots();
public slots:
void secondWindowTest();
protected:
private:
Ui::secondMainWindow m_secondWindowUI;
};
#endif
-------------------------------secondWindow.cxx------------------------------------
#include "secondWindow.moc"
#include "secondWindow.h"
#include "read.h"
secondWindow::secondWindow() :m_StateMachine(this)
{
m_secondWindowUI.setupUi(this);
createSignalAndSlots();
}
void secondWindow::createSignalAndSlots()
{
connect(m_secondWindowUI.pushButton1, SIGNAL(clicked()),this, SLOT(secondWindowTest()));
connect(m_secondWindowUI.pushButton2, SIGNAL(clicked()), read::instance(), SLOT(readTest()));
}
void secondWindow::secondWindowTest()
{
m_secondWindowUI.pushButton1->setEnabled(true); //OK
}
secondWindow::~secondWindow(){}
---------------------------------read.h--------------------------------------
#pragma once
#include "secondWindow.h"
class read : public QObject
{
Q_OBJECT
public:
static read *instance();
read();
virtual ~read() {}
public slots:
void readTest();
protected:
secondWindow *m_readUI;
static read *m_read;
private:
};
---------------------------------read.cxx--------------------------------------
#include <read.moc>
#include "secondWindow.h"
#include "read.h"
read *read::m_read= NULL;
read::read()
{
m_readUI = dynamic_cast<secondWindow*>( QApplication::instance() );
}
read *read::instance()
{
if(m_read == NULL)
m_read = new read();
return m_read;
}
void read::readTest()
{
m_readUI->m_secondWindowUI.qlabelTest->setText("test"); //segmentation fault
}
You are casting a QApplication::instance(), which is a QApplication * deriving from QCoreApplication * deriving from QObject *. That won't work, it's not a secondWindow *, not even a QMainWindow *, not even a QWidget *.
Apart from that, your coding style is rather strange -- in Qt, it's customary to use CamelCase for classes, not thisStuff which usually applies to functions and methods. Including <read.moc> is just wrong. Why is read::m_read static? Finally, the coupling between the two window classes is set up in a strange way (accessing global stuff like QApplication just to get a reference to another window smells ugly code). A much better and more obvious approach is to either wrap all of your windows in a parent object or setting up the dependencies explicitly, perhaps like this:
MainWindow *mainWindow = new MainWindow();
SecondWindow *second = new SecondWindow(mainWindow);
UtilityWindow *utilityWin = new UtilityWindow(second);