Initialization of the constructor of a QThread C++ with QString parameter - c++

is it possible to initialize a new QThread with a parameter?? I created two threads in MainWindow. Now i want initialize the Thread "mySave" with a QString. But it doesn't work.
void MainWindow::on_startButton_clicked()
{
thread = new QThread();
mThread = new myThread();
threadSave = new QThread();
mSave = new mySave("HelloWorld");
....
}
I change the line mSave = new mySave() to mySave = new mySave("HelloWorld") and the constructor of mySave-Class to
mySave::mySave(QObject *parent, QString stringFromMainWindow)
: QObject{parent}, m_string{stringFromMainWindow}
{
this->stringMySave = stringFromMainWindow;
}
mySave.h
class mySave : public QObject
{
Q_OBJECT
public:
explicit mySave(QObject *parent = nullptr, QString stringFileName = NULL);
private:
QFile file;
QString m_string {};
....
But i become a fault!
mainwindow.cpp:57:17: error: no matching constructor for initialization of 'mySave'
mysave.h:9:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const char [6]' to 'const mySave' for 1st argument
mysave.h:13:14: note: candidate constructor not viable: no known conversion from 'const char [6]' to 'QObject *' for 1st argument
What's wrong...??
Without QString parameter everthing works fine:
void MainWindow::on_startButton_clicked()
{
thread = new QThread();
mThread = new myThread();
threadSave = new QThread();
mSave = new mySave();
connect(thread, SIGNAL(finished()), mThread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(mThread, SIGNAL(emitData(const QByteArray &)), this, SLOT(setEditText(const QByteArray &)));
mThread->moveToThread(thread);
thread->start();
mSave->moveToThread(threadSave);
threadSave->start();
QMetaObject::invokeMethod(mThread, "interfaceSerial");
QMetaObject::invokeMethod(mSave, "startFile", Q_ARG(QString, fileName));
qDebug() << "Main open " << QThread::currentThread();
dataTimer.start(0); // Interval 0 means to refresh as fast as possible
}
mySave-Thread constructor
mySave::mySave(QObject *parent)
: QObject{parent}
{
qDebug() << "Thread open " << QThread::currentThread();
}
How can i set a QString parameter in the constructor of a new QThread....??
Thanks & Bye bye

The problem was solved...you have to write
class mySave : public QObject
{
Q_OBJECT
public:
explicit mySave(QString stringFileName = NULL, QObject *parent = nullptr);
private:
QFile file;
The last parameter has to be the QObject!!

Look at your mySave constructor signature...
explicit mySave(QObject *parent = nullptr, QString stringFileName = NULL);
The first parameter passed must be a QObject * (or something implicitly convertible to a QObject *) and the second parameter passed must be a QString. If you want mySave to be constructible using a QString only then you must provide a suitable constructor. The obvious option would be to simply reverse the order of the passed parameters...
explicit mySave(QString stringFileName = QString(), QObject *parent = nullptr);
Having said that, the most commonly used constructor calls for classes of this nature would probably be...
/* Default constructor: no text or parent. */
mySave ms1;
/* Text only. */
mySave ms2("Some text...");
/* Parent object only. */
QObject *parent = ...;
mySave ms3(parent);
/* Pass both text and parent object. */
mySave ms4("Some text...", parent);
All of these cases can be provided by the following two constructors...
mySave::mySave (const QString &stringFileName = QString(), QObject *parent = nullptr)
: QObject(parent)
, m_string(stringFileName)
{
...
}
mySave::mySave (QObject *parent)
: QObject(parent)
{
...
}
Or, if you prefer, make the second a delegating constructor...
mySave::mySave (QObject *parent)
: mySave(QString(), parent)
{}

Related

no matching conversion for functional-style cast from 'const QString' to 'QTreeWidgetItem'

I am building a small application using QTreeWidgetItem and QTreeWidgetItem for practicing them and for practicing how to best and where use them. This is a small application where I am trying to assign an icon to a QTreeWidget using a helper function.
Now for some reasons I get the following error :
no matching conversion for functional-style cast from 'const QString' to 'QTreeWidgetItem',
below the code:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QTreeWidgetItem *createItem(const QString &name, const QString &iconPath);
QString name() const {
return m_Name;
}
QString iconPath() const {
return m_Path;
}
void setName(const QString &name)
{
m_Name = name;
}
void setPath(const QString &path)
{
m_Path = path;
}
private:
Ui::MainWindow *ui;
QString m_Name;
QString m_Path;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto *top1 = createItem("Images", "/path/to/icon.png");
auto *top2 = createItem("Path", "/path/to/icon.png");
top1->addChild(createItem("Original", "/path/to/icon.png"));
top1->addChild(createItem("Sample", "/path/to/icon.png"));
top2->addChild(createItem("Left Side", "/path/to/icon.png"));
top2->addChild(createItem("Right Side", "/path/to/icon.png"));
ui->treeWidget->addTopLevelItems({ top1, top2 });
}
MainWindow::~MainWindow()
{
delete ui;
}
QTreeWidgetItem *MainWindow::createItem(const QString &name, const QString &iconPath)
{
auto *item = QTreeWidgetItem(name); // <-- Error Here
item.setIcon(0, QIcon(iconPath));
return item;
}
Now this is a compiler error and it seems that the constructor is missing QTreeWidgetItem and therefore is preventing me from using the helper function I created to help me define name and path for the small icon.
I researched the problem and came across this source and also I read the additional source.
Thanks for helping me shedding light on this issue.

How to run a QThread from QWizardPage and access field()

I need some advice to access the field(QString name) variable in QWizardPage from a QThread. I'm building some kind of an installer and I want to do the installing work in a separate Thread.
My purpose:
When reached the commit/install page, I want to execute code to do the "installing" and update the QWizardPage with my progress, until its finished.
The install function is dependent on many field() variables from other QWizardPages. Therefore I tried to execute this install function from a QThread, which is defined in an inner class from my QWizardPage. The problem is, the field()-function i a non-static member and so it's not working. And so I'm out of ideas to run my install-function parallel to my WizardPage.
I tried something like this:
InstallPage.h
class InstallPage : public QWizardPage
{
Q_OBJECT
class WorkerThread : public QThread
{
Q_OBJECT
void run() override;
};
public:
InstallPage(QWidget *parent = 0);
private:
QLabel *lProgress;
WorkerThread *installer;
void install();
};
InstallPage.c
InstallPage::InstallPage(QWidget *parent)
: QWizardPage(parent)
{
...
installer = new WorkerThread(this);
installer->start();
}
void InstallPage::WorkerThread::run()
{
if(field("checkBox1").ToBool())
{
doStuff();
}
}
//QT-Creator says at field("checkBox1"):
//error: call to non-static member function without an object argument
I'm also open for any other idea to make my installer work. Maybe someone knows something I haven't thought of.
Another approach is to create a worker (QObject) that lives in another thread that performs the heavy task and notifies the status of that task through signals:
#include <QtWidgets>
class InitialPage: public QWizardPage
{
public:
InitialPage(QWidget *parent = nullptr): QWizardPage(parent)
{
QSpinBox *spinbox = new QSpinBox;
QLineEdit *lineedit = new QLineEdit;
QVBoxLayout *lay = new QVBoxLayout(this);
lay->addWidget(spinbox);
lay->addWidget(lineedit);
registerField("value1", spinbox);
registerField("value2", lineedit);
}
};
class InstallWorker: public QObject
{
Q_OBJECT
public:
InstallWorker(QObject *parent=nullptr): QObject(parent)
{
}
public Q_SLOTS:
void install(int param1, const QString & param2)
{
Q_EMIT started();
for(int i=0; i < 100; i++){
qDebug() << __PRETTY_FUNCTION__ << i << param1 << param2;
QThread::msleep(100);
Q_EMIT progressChanged(i);
}
qDebug()<< __PRETTY_FUNCTION__ << "finished";
Q_EMIT finished();
}
Q_SIGNALS:
void started();
void progressChanged(int value);
void finished();
};
class InstallPage: public QWizardPage
{
Q_OBJECT
public:
InstallPage(QWidget *parent = nullptr): QWizardPage(parent),
label(new QLabel), progressbar(new QProgressBar)
{
QVBoxLayout *lay = new QVBoxLayout(this);
lay->addWidget(label);
lay->addWidget(progressbar);
progressbar->setMinimum(0);
progressbar->setMaximum(100);
thread = new QThread(this);
worker.moveToThread(thread);
connect(&worker, &InstallWorker::started, this, &InstallPage::onStarted);
connect(&worker, &InstallWorker::finished, this, &InstallPage::onFinished);
connect(&worker, &InstallWorker::progressChanged, this, &InstallPage::onProgressChanged);
thread->start();
}
~InstallPage(){
thread->quit();
thread->wait();
}
void initializePage(){
start_install();
}
private Q_SLOTS:
void start_install(){
int param1 = field("value1").toInt();;
QString param2 = field("value2").toString();
QMetaObject::invokeMethod(&worker, "install", Qt::QueuedConnection, Q_ARG(int, param1), Q_ARG(QString, param2));
}
void onStarted(){
for(QWizard::WizardButton which: {QWizard::BackButton, QWizard::NextButton, QWizard::CancelButton})
if(QAbstractButton * button = wizard()->button(which))
button->setEnabled(false);
}
void onFinished(){
for(QWizard::WizardButton which: {QWizard::BackButton, QWizard::NextButton, QWizard::CancelButton})
if(QAbstractButton * button = wizard()->button(which))
button->setEnabled(true);
wizard()->next();
}
void onProgressChanged(int value){
progressbar->setValue(value);
label->setNum(value);
}
private:
InstallWorker worker;
QThread *thread;
QLabel *label;
QProgressBar *progressbar;
};
class FinalPage: public QWizardPage
{
public:
FinalPage(QWidget *parent = nullptr): QWizardPage(parent)
{
}
};
#include "main.moc"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWizard wizard;
wizard.addPage(new InitialPage);
wizard.addPage(new InstallPage);
wizard.addPage(new FinalPage);
wizard.show();
return app.exec();
}

How to subclass in Qt?

I'd like to subclass QListWidgetItem, but I don't get what I'm doing wrong.
I subclassed QListWidget without any trouble using the same principles.
This is my header file :
#ifndef LSPROLISTITEM_H
#define LSPROLISTITEM_H
#include <QObject>
#include <QListWidgetItem>
class LsproListItem : public QListWidgetItem
{
Q_OBJECT
public:
explicit LsproListItem(QString &text, QObject *parent = 0);
signals:
public slots:
};
#endif // LSPROLISTITEM_H
and this is my cpp file :
#include "lsprolistitem.h"
#include <QListWidgetItem>
LsproListItem::LsproListItem(QString & text, QObject *parent) :
QListWidgetItem(text, parent)
{
}
I don't get the argument from my custom constructor, to create an object based on QListWidgetItem..
I try to create is this way :
LsproListItem *simpleText = new LsproListItem("Lorem ipsum");
But this fails with :
appcms.cpp: error : no matching constructor for initialization of 'LsproListItem'
LsproListItem *simpleText = new LsproListItem("Lorem ipsum");
^ ~~~~~~~~~~~~~
lsprolistitem.h:7: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'const char [12]' to 'const LsproListItem' for 1st argument
class LsproListItem : public QListWidgetItem
^
lsprolistitem.h:: candidate constructor not viable: no known conversion from 'const char [12]' to 'QString &' for 1st argument
explicit LsproListItem(QString &text, QObject *parent = 0);
^
Quick solution(not the best): don't use reference:
public:
explicit LsproListItem(QString text, QObject *parent = 0);
//...
LsproListItem::LsproListItem(QString text, QObject *parent) :
Or
public:
explicit LsproListItem( const QString &text, QObject *parent = 0);
//...
LsproListItem::LsproListItem( const QString &text, QObject *parent) :
But there is another mistake. Remove Q_OBJECT macro because QListWidgetItem is not a QObject subclass and you can't use here signal and slots.
To prove: http://qt-project.org/doc/qt-5/qlistwidgetitem.html

QT Connection between classes

I think i have some troubles getting this right: I have a QMainWindow class. In my programm I want to create other classes e.g. for input handling, computation...
Now first from my mainwindow class i want to send to my fileselector (file handler) class to open a file dialog, thus save the selected files internally. Unfortunately I am having troubles to connect the slots.
main window:
MA_FEX::MA_FEX(QWidget *parent)
: QMainWindow(parent), fileSelector(this)
{
ui.setupUi(this);
//this works:
fileSelector.openFiles(this);
//this doesn't:
connect(ui.actionOpenFiles, SIGNAL(triggered()), fileSelector, SLOT(openFiles(this)));
}
MA_FEX::~MA_FEX()
{
}
mainwindow header:
class MA_FEX : public QMainWindow
{
Q_OBJECT
public:
MA_FEX(QWidget *parent = 0);
~MA_FEX();
private:
Ui::MA_FEXClass ui;
FileSelection fileSelector;
};
file coordination class:
FileSelection::FileSelection(QObject *parent)
: QObject(parent)
{
}
FileSelection::~FileSelection()
{
}
void FileSelection::openFiles(QWidget *parent){
QStringList files = QFileDialog::getOpenFileNames(
parent,
"Select one or more files to open",
"c:",
"Images (*.csv *.txt )");
}
header:
class FileSelection : public QObject
{
Q_OBJECT
public:
FileSelection(QObject *parent);
~FileSelection();
public slots:
void openFiles(QWidget *parent);
private:
};
Am I missing something ? Executing i get Error C2664 on the connect line saying that Parameter 3 'FileSelection' cannot be converted to 'const QObject'.
Look at the declaration of the QObject::connect:
QObject::connect(const QObject * sender, const char * signal,
const QObject * receiver, const char * method,
Qt::ConnectionType type = Qt::AutoConnection);
It takes pointers, so you need to pass a pointer to fileSelector.
Another problem there is incompatible SIGNAL and SLOT. The slot specification in connect is declaration, so you cannot pass arguments as you did with this. If you use Qt 5 and C++11 you can do that by passing lambda instead of slot specification:
QObject::connect(ui.actionOpenFiles, &QAction::triggered,
[this]() { fileSelector.openFiles(this); });
For Qt 4 you need to create wrapping slot in your MA_FEX class which takes no arguments and which will invoke the slot of the fileSelector:
class MA_FEX {
...
Q_SLOT void openFileSelector() { fileSelector.openFiles(this); }
...
public:
MA_FEX(QWidget *parent) : QMainWindow(parent), fileSelector(this) {
ui.setupUi(this);
connect(ui.actionOpenFiles, SIGNAL(triggered()), SLOT(openFileSelector()));
}
...
};

Qt Signals and Slots Confusion

I have been reading about Qt signals and slots and I am trying to get this to work, but until now without success. I hope someone can point me in the right direction.
I have two files, homeCommand.cpp and messagelogcommand.cpp. I have a QPlainTextEdit object in messagelogcommand.cpp that I want to update from homeCommand.cpp.
How can I do this using signals and slots? My signal is being called, as my QDebug is being printed out once a second, however the widget does not update.
This is what I am trying to do:
In MessageLogCommand.h
class MessageLogCommand : public QWidget
{
Q_OBJECT
public:
explicit MessageLogCommand(QWidget *parent = 0);
QLabel *homeLabel;
QPlainTextEdit *messageLog;
public Q_SLOTS:
void updateWidgets(const QString &text);
};
homeCommand.h
class homeCommand : public QWidget
{
Q_OBJECT
Q_SIGNALS:
void textChanged(const QString &text);
public:
explicit homeCommand(QWidget *parent = 0);
public slots:
void run(void);
void getHealthStatusPacket(void);
homeCommand.cpp
homeCommand::homeCommand(QWidget *parent) : QWidget(parent)
{
...
//Timer
QTimer *timer = new QTimer(this);
timer->setSingleShot(false);
connect(timer, SIGNAL(timeout()), this, SLOT(run()));
timer->start(1000);
setLayout(layout);
}
void homeCommand::run(void)
{
getHealthStatusPacket();
}
void homeCommand::getHealthStatusPacket(void)
{
...
Q_EMIT textChanged("ZOMG");
}
In MessageLogCommand.cpp
MessageLogCommand::MessageLogCommand(QWidget *parent) : QWidget(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
//Sub-system Label
homeLabel = new QLabel("GSS Message Log");
QFont subsystemFont = homeLabel->font();
subsystemFont.setPointSize(12);
subsystemFont.setBold(true);
homeLabel->setFont(subsystemFont);
layout->addWidget(homeLabel, 0, 0);
//Event Log
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
layout->addWidget(messageLog, 2,0);
setLayout(layout);
}
void MessageLogCommand::updateWidgets(const QString &text)
{
qDebug() << "Here";
messageLog->appendPlainText(text);
}
In main.cpp
MessageLogCommand s;
homeCommand m;
QObject::connect(&m, SIGNAL(textChanged(QString)), &s, SLOT(updateWidgets(QString)));
A very basic example is:
class MainClass:public QObject //class must be derived from QObject!
{
Q_OBJECT //this macro must be in the class definition
//so the moc compiler can generate the necessary glue code
public:
void doSomething() {
...
Q_EMIT textChanged(someText);
}
Q_SIGNALS:
void textChanged(const QString &text);
};
class SubClass:public QObject
{
Q_OBJECT
public Q_SLOTS:
void onTextChanged(const QString &text) { //do not inline
//do something
}
};
int main()
{
QApplication a;
MainClass m;
SubClass s;
QObject::connect(&m, SIGNAL(textChanged(QString)),
&s, SLOT(onTextChanged(QString))); //const and & are removed from
//the arguments
return a.exec(); //run the event loop
}
So, there are 2 things important:
1. Signals and slots must be declared in a class derived from QObject
2. The classes containing signals and slots declarations must add the Q_OBJECT macro to the class declaration
To keep it simple for you: always declare your classes containing signals or slots in a header file (never in a .cpp file).
A very good starting point for signals and slots is: http://woboq.com/blog/how-qt-signals-slots-work.html but also the official Qt doc does it: http://qt-project.org/doc/qt-4.8/signalsandslots.html
Basically what happens: you declare some special methods (signals and slots), at the compilation phase Qt generates extra CPP files which take care of your methods (moc) then everything is compiled and linked together and at the end when Qt or someone else emits a signal it will go to the corresponding slot.
I try to explain it.
In main.h you should to declare a signal:
signals:
void textChanged(const QString& text);
And in messagelog.h you should to declare a slot:
public slots:
void updateWidgets(const QString& text);
In main.cpp you should emit this signal:
void TheMethod() {
emit this->textChanged("Your text/value");
}
In messagelog.cpp you should get this value:
// Note: Normalized signal/slot signatures drop the consts and references.
connect(&a, SIGNAL(textChanged(QString)), this, SLOT(updateWidgets(QString)));
void updateWidgets(const QString& text) {
messageLog = new QPlainTextEdit();
messageLog->setFixedHeight(500);
messageLog->setFixedWidth(600);
messageLog->setPlainText(text)
layout->addWidget(messageLog, 2,0);
}
I think it should works.
UPDATE:
Complete example: https://dl.dropboxusercontent.com/u/29647980/test.zip