I'm trying to change the value of a text field from another thread, but for some reason it does not work: There are 2 windows, the first window:

firstwindow.h:

#include "mythread.h" #include <QObject> class FirstWindow : public QObject { Q_OBJECT public: explicit FirstWindow(QObject *parent = nullptr); private: MyThread *myThread; public slots: void start(); }; 

firstwindow.cpp:

 #include "firstwindow.h" FirstWindow::FirstWindow(QObject *parent) : QObject(parent) { } void FirstWindow::start() { myThread = new MyThread(5); //передача значения в класс MyThread } 

firstwindow.qml:

 import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtQuick.Window 2.0 import FirstWindowModule 1.0 ApplicationWindow { visible: true width: 380 height: 240 id: firstwindow FirstWindow { id: obj; } //создание и вызов второго окна, вызов функции start(), создающей объект класса MyThread Button { text: "Start" onClicked: { var component = Qt.createComponent("main.qml"); console.log("Component Status:", component.status, component.errorString()); var window = component.createObject(firstwindow); window.show() obj.start(); } } } 

Second window:

mythread.h:

 #include "newclass.h" #include <QObject> #include <QThread> class MyThread : public QObject { Q_OBJECT Q_PROPERTY(QString firstNumber READ GetFirstNumber WRITE SetFirstNumber NOTIFY firstNumberChanged) private: QThread *thread; NewClass *newClass; QString firstNumber; int counter; private slots: void UpdateFirstValue (int i); public slots: void StartThread(int); public: explicit MyThread(int value, QObject *parent = nullptr); explicit MyThread(QObject *parent = nullptr); QString GetFirstNumber(); void SetFirstNumber(QString); signals: void firstNumberChanged(); }; 

mythread.cpp:

 #include "mythread.h" MyThread::MyThread(QObject *parent) : QObject(parent) { } MyThread::MyThread(int counter, QObject *parent) : QObject(parent) { this->counter = counter; StartThread(counter); //запуск функции создания и запуска потока } QString MyThread::GetFirstNumber() { return firstNumber; } void MyThread::SetFirstNumber(QString value) { firstNumber = value; } void MyThread::StartThread(int counter) { thread = new QThread; newClass = new NewClass(counter); newClass->moveToThread(thread); connect(newClass, SIGNAL(sendfirstvalue(int)), this, SLOT(UpdateFirstValue(int))); connect(thread, SIGNAL(started()), newClass, SLOT(Start())); thread->start(); } void MyThread::UpdateFirstValue (int i) { firstNumber = QString::number(i); emit firstNumberChanged(); } 

main.qml:

 import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtQuick.Window 2.0 import NameModule 1.0 ApplicationWindow { visible: true width: 380 height: 240 Rectangle { id: content TypeName { id: obj } ColumnLayout { height: parent.height anchors.horizontalCenter: content.horizontalCenter Rectangle { Layout.fillHeight: true Text { anchors.centerIn: parent id: firstNumber text: "f = " + obj.firstNumber font.bold: true onTextChanged: { console.log("firstNumberChanged"); } } } } } } 

The NewClass class, whose function works in the stream:

newclass.h:

 #include <QObject> class NewClass : public QObject { Q_OBJECT public: explicit NewClass(int value, QObject *parent = nullptr); signals: void sendfirstvalue(int); private slots: void Start(); private: int value; }; 

newclass.cpp:

 #include "newclass.h" #include <windows.h> #include "QDebug" NewClass::NewClass(int value, QObject *parent) : QObject(parent) { this->value = value; } void NewClass::Start() { qDebug() << "value" << value; for(int i = 0; i < value; i++) { qDebug() << "i" << i; emit sendfirstvalue(i); Sleep(1000); // from windows.h } } 

A bunch of FirstWindow and MyThread classes with their corresponding qml:

 qmlRegisterType<FirstWindow>("FirstWindowModule", 1, 0, "FirstWindow"); qmlRegisterType<MyThread>("NameModule", 1, 0, "TypeName"); 

The essence of the problem: 2 windows, in the first window (FirstWindow) there is a button that opens the second window (MyThread), and immediately starts the computation process in the new thread (the Start () function in the NewClass class. This function loops, every second sends an integer value back to the second MyThread window, and this value should be displayed in this window. It was determined that the problem is most likely in the creation of this second window, that either the thread starts before the window is shown, or something else. Thank you.

UPDATE: rewrote the question again and uploaded the project to https://github.com/sawyerhard/test2 . Problem not solved

  • Comments are not intended for extended discussion; conversation moved to chat . - PashaPash

3 answers 3

Since you didn’t bring your code in full, it’s hard to say why something doesn’t work for you. Therefore, I give my own example in which the value of a text field is changed by a separate stream.

The TextManager type TextManager immediately derived from QThread . It will only override the run method.

main.h

 #include <QObject> #include <QThread> class TextManager : public QThread { Q_OBJECT Q_PROPERTY(QString value READ getValue WRITE setValue NOTIFY valueChanged) public: TextManager(QObject *parent = 0); QString getValue() const; private: QString value; void run(); signals: void valueChanged(); public slots: void setValue(const QString &value); }; 

main.cpp

 #include <QGuiApplication> #include <QQmlApplicationEngine> #include <main.h> TextManager::TextManager(QObject *parent) : QThread(parent), value("init") { } QString TextManager::getValue() const { return value; } void TextManager::setValue(const QString &v) { value = v; } void TextManager::run() { for(int i = 0; i < 10; i++){ setValue(QString::number(i)); emit valueChanged(); msleep(300); } } int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<TextManager>("PropertyHandler", 1, 0, "TextManager"); QQmlApplicationEngine engine; engine.load(QUrl(QLatin1String("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } 

main.qml

 import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Window 2.0 import PropertyHandler 1.0 ApplicationWindow { visible: true width: 380 height: 240 Component.onCompleted: { setX(Screen.width / 2 - width / 2); setY(Screen.height / 2 - height / 2); } TextManager { id: txtmgr } Text { id: txtField anchors.centerIn: parent text: txtmgr.value } Button { text: "Start" onClicked: { txtmgr.start(); } } } 
  • added to the question all that was missing) - SWR

After all your additions and clarifications to the question managed to run your code. All corrections mark comments. It is strange that you have neither compilation errors nor qml debugger errors. Or you and silent about them.

The header file will not be. All in main.cpp .

main.cpp

 #include <QGuiApplication> #include <QQuickView> #include <QThread> #include <QTest> class NewClass : public QObject { Q_OBJECT public: explicit NewClass(QObject *parent = nullptr); signals: void sendfirstvalue(int); private slots: void Start(); }; class MyThread : public QObject { Q_OBJECT Q_PROPERTY(QString firstNumber READ GetFirstNumber WRITE SetFirstNumber NOTIFY firstNumberChanged) private: QThread *thread; NewClass *newClass; QString firstNumber; private slots: void UpdateFirstValue (int i); public slots: // это основная причина, почему не работало; вы определили его как private, но хотели вызывать из qml void mStartThread(); // переименовал StartThread -> mStartThread так как qml хочет вызывать функции, имена которых начинаются с нижнего регистра; работает и с верхним, но ругается public: explicit MyThread(QObject *parent = nullptr); QString GetFirstNumber(); void SetFirstNumber(QString); signals: void firstNumberChanged(); }; //-------------------------------------------------------- // конструкторы MyThread и NewClass, которые вы не указали //-------------------------------------------------------- MyThread::MyThread(QObject *parent) : QObject(parent) { } NewClass::NewClass(QObject *parent) : QObject(parent) { } //-------------------------------------------------------- QString MyThread::GetFirstNumber() { return firstNumber; } void MyThread::SetFirstNumber(QString value) { firstNumber = value; } void MyThread::mStartThread() { thread = new QThread; newClass = new NewClass(); newClass->moveToThread(thread); connect(newClass, SIGNAL(sendfirstvalue(int)), this, SLOT(UpdateFirstValue(int))); connect(thread, SIGNAL(started()), newClass, SLOT(Start())); thread->start(); } void MyThread::UpdateFirstValue (int i) { firstNumber = QString::number(i); emit firstNumberChanged(); } void NewClass::Start() { for(int i = 0; i < 3; i++) { emit sendfirstvalue(i); QTest::qSleep(1000); // у вас Sleep непонятно откуда - заменил на QTest::qSleep (в *.pro файле надо добавить QT += testlib) } } // ну main вы просто не приводили; приведу, чтобы было понятно, как можно запустить int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<MyThread>("NameModule", 1, 0, "TypeName"); QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:/main.qml")); view.show(); return app.exec(); } #include "main.moc" // так как нет заголовочного файла и классы определены тут же 

main.qml

 import QtQuick 2.0 import QtQuick.Layouts 1.1 import NameModule 1.0 import QtQuick.Controls 2.0 Rectangle { id: content TypeName { id: obj } // добавил кнопку для вызова - проверить же надо как-то Button { text: "start" onClicked: { obj.mStartThread(); } } ColumnLayout { height: parent.height anchors.horizontalCenter: content.horizontalCenter Rectangle { Layout.fillHeight: true Text { anchors.centerIn: parent id: firstNumber text: "f = " + obj.firstNumber font.bold: true onTextChanged: { console.log("firstNumberChanged"); } } } } } 
  • Both answers work, the problem is buried in the creation of the second window, that is, a button from the first window creates a second window and the flow starts automatically, apparently the flow starts working earlier than the window is shown and therefore there is no output, I don’t know how to fix it yet, for convenience finally uploaded an example on github github.com/sawyerhard/test2 - SWR
  • @SWR, then, it is better to open a new question with the described problem. - mkkik
  • the text field still does not change, as we would like, the problem is not solved
  • one
    Not resolved because it is not indicated. Create a minimalistic example describing the problem. Because you can only get into your question if you read the whole wall of comments. From the question it is not clear what exactly is not working for you. You can find out about the presence of the second window only from the code given on the github. - mkkik
  • re-edited the question in the header, attached everything that is - SWR

Problem solved) In general, the whole problem was in these 2 lines in the file firstwindow.qml:

 var window = component.createObject(firstwindow); 

and function call

 obj.start(); 

at which there was a repeated !!! the creation of the myThread object, since the main object was created in the line above (since the window is associated with the MyThread class), because of this data, which, although it came, was not displayed in the window.

Solution: 1. Remove the line from firstwindow.qml:

 obj.start(); 

2. Add the onCompleted method to the main.qml file, in which we start the flow execution:

 Component.onCompleted: { obj.startThread(5); } 

Thanks to all)