QLabel won't update from Slot
-
Forgive me, I am a complete beginner. I am trying to learn how to receive a message from a client and display on the server ui. I have that figured out. My problem is when trying to update the UI with that message. For right now, I am not worrying about the exact message, but just having the UI update when a message is received. However, my UI will not update. Here is the relevant code:
Line that calls the slot from another class:
connect(socket, SIGNAL(readyRead()), &mw, SLOT(fillText()));
mw is a MainWindow Object
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" int num; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); itemLabel->setText("Label Created"); ui->gridLayout->addWidget(itemLabel, 0, 0); } MainWindow::~MainWindow() { delete ui; } void MainWindow::fillText() { qDebug() << "inside fillText function "; num = arc4random(); itemLabel->setText("updated number to show SLOT is working: " + QString::number(num)); qDebug() << "item Label's text: " + itemLabel->text(); this->setStyleSheet("background-color: green;"); QWidget::repaint();//was a suggestion I saw, but does not work }
mainwindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QLabel> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); QLabel *itemLabel = new QLabel(); QLabel *label2; private slots: void fillText(); void signalTest(); private slots: signals: private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
Thanks for all the help!!
quick edit: I know textFill() is called because
qDebug() << "inside fillText function ";
works, and
qDebug() << "item Label's text: " + itemLabel->text();
actually prints out "item Label's text: updated number to show SLOT is working: (random num) every time I send a message from my client.
-
Hi
in this line
connect(socket, SIGNAL(readyRead()), &mw, SLOT(fillText()));
what is mw ?anyway, it sounds like the slot works so the connection is ok.
so which part is not updating?
itemLabel->setText sounds like its updating as you see the random number ?Ahh you mean how to read the actual massage from socket and pass that along ?
-
@mrjj Hello, mw is a MainWindow object I initialized in the header file of this other class.
So, qDebug tells me that the label's text value is indeed updating. However, in the actual GUI window, the the text for itemLabel remains "Label Created," which according to this line:
qDebug() << "item Label's text: " + itemLabel->text();
is not the case.
No, I have not yet tried to work on the actual message, just trying to get the GUI to update when a message is received is my worry for now.
-
Hi
But is this the classic gotcha then?You already have one mainwindow, you look at but then create a
new one called mw (which you don't call show on) and you connect to that
but its not the one that is actually showing ?To fix this , you can connect where you create the "otheclass" that has the socket
like if you create it in Mainwindow
TheOTherclass * other = new TheOTherclass(this)
connect(other->socket, SIGNAL(readyRead()), this, SLOT(fillText())); -
@mrjj ohhhhh I see what I did now.
How would I write this line since my other class has a qintptr argument:
qDebug() << "item Label's text: " + itemLabel->text();mythread.h:
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> #include <QTcpSocket> #include <QObject> #include "mainwindow.h" class MyThread : public QThread { Q_OBJECT public: explicit MyThread(qintptr ID, QObject *parent = 0); void run(); signals: void error(QTcpSocket::SocketError socketerror); public slots: void readyRead(); void disconnected(); private: QTcpSocket *socket; qintptr socketDescriptor; MainWindow mw; }; #endif // MYTHREAD_H
mythread.cpp(contains old connect code, but I will take it out and put connect in MainWindow):
#include "mythread.h" MyThread::MyThread(qintptr ID, QObject *parent) : QThread(parent) { this->socketDescriptor = ID; } void MyThread::run() { qDebug() << "Thread started"; socket = new QTcpSocket(); if(!socket->setSocketDescriptor(this->socketDescriptor)) { // something's wrong, we just emit a signal emit error(socket->error()); return; } connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection); connect(socket, SIGNAL(readyRead()), &mw, SLOT(fillText())); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); qDebug() << socketDescriptor << " Client connected"; exec(); } void MyThread::readyRead() { QByteArray Data = socket->readAll(); qDebug() << socketDescriptor << " Data in: " << Data; socket->write("Data reply: " + Data); } void MyThread::disconnected() { qDebug() << socketDescriptor << " Disconnected"; socket->deleteLater(); exit(0); }
thank you so much!!
-
Hi
What about making a new signal like the
void error(QTcpSocket::SocketError socketerror);but then instead
void DataReady(QString text );
and then in
void MyThread::readyRead()
{
QByteArray Data = socket->readAll();
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write("Data reply: " + Data);
emit DataReady(QString(Data)); // we got something to show in MainWindow
}and then in Mainwindow (the real one) you connect the new signal DataReady
to some slot and there you do the itemLabel->text(); thing as MainWindow has that
Qlabel and it's NOT allowed to fiddle with Widgets across threads and MyThread is such a beast so
you should not call setText or any function on Widgets that are in MainWindow.Also, Do you really need a new Thread ?
QTcpSocket is already async and will send signal when to read new data so
it won't block the main GUI thread.
If you later plan on doing heavy calculation/processing on the incoming data it's fine but
just had to ask :) -
@mrjj oh yes that would work, and I could probably manage with one thread but I will keep it like this for now and optimize later.
So in MainWindow, I would do this:MyThread * other = new MyThread(this)
connect(other, SIGNAL(dataReceived(QString Data??)), this, SLOT(fillText()));But how would I initialize “*other” since has a required arg? That is my confusion.
I need other so I can specify the sender object.
or do you mean DataReady signal should belong to MainWindow?
My first QT and c++ project, sorry.
-
Hi
Yes but one never shows the param name in the connect soMyThread * other = new MyThread(this)
connect(other, SIGNAL(dataReceived(QString)), this, SLOT(fillText()));( I assume that dataReceived is your name for DataReady example)
and you should change the filltext from
void fillText()
->
void fillText(QString data);As in - add new parameter to your slot, to use the data.
- But how would I initialize “*other” since has a required arg? That is my confusion.
You mean the connect or the
MyThread * other = new MyThread(this)
part ?- My first QT and c++ project, sorry.
Then it goes pretty well I must say :)
When you feel for it, you should have a look at the new way to connect
https://wiki.qt.io/New_Signal_Slot_Syntax -
MyThread * other = new MyThread(this)
When I use this, I get the "no matching constructor for initialization of "MyThread." I think this is because the param needs to be of type qintptr, right?So I tried something. I tried to grab the MyThread object that is initialized in my server files header. I will attach. I used extern and added this line to my mainwindow.cpp. However, this would give me linker error when compiling.
myserver.h:
#ifndef MYSERVER_H #define MYSERVER_H #include <QTcpServer> class MyServer : public QTcpServer { Q_OBJECT public: MyServer(QObject *parent = 0); void startServer(); protected: void incomingConnection(qintptr socketDescriptor); }; #endif // MYSERVER_H
myserver.cpp:
#include "myserver.h" #include "mythread.h" MyServer::MyServer(QObject *parent) : QTcpServer(parent) { } void MyServer::startServer() { int port = 1234; if(!this->listen(QHostAddress::Any, port)) { qDebug() << "Could not start server"; } else { qDebug() << "Listening to port " << port << "..."; } } void MyServer::incomingConnection(qintptr socketDescriptor) { // We have a new connection qDebug() << socketDescriptor << " Connecting..."; MyThread *threadly = new MyThread(socketDescriptor, this); // connect signal/slot // once a thread is not needed, it will be beleted later connect(threadly, SIGNAL(finished()), threadly, SLOT(deleteLater())); threadly->start(); }
In mainwindow.cpp, I added
extern const MyThread* threadly;
and
connect(threadly, SIGNAL(dataSignal()), this, SLOT(fillText()));
It would give a linker error at this line. I read online that I must #include mainwindow.moc, but QT could not find that file.
However, if you believe that this is the wrong way to tackle this, and instead initialize another MyThread object in mainwindow, I will do that instead, but the correct way as using (this) as the param does not work for me.
And again, thank you so much for the help!
PS: the error detail for using MyThread(this) is: no matching constructor for initialization of 'MyThread'
note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'MainWindow *' to 'const MyThread' for 1st argument
note: candidate constructor not viable: no known conversion from 'MainWindow *' to 'qintptr' (aka 'long long') for 1st argument -
@rahulb1218
You have said:My first QT and c++ project, sorry.
@mrjj oh yes that would work, and I could probably manage with one thread but I will keep it like this for now and optimize later.
Why in the world are you soldiering on using threads? They are probably the single hardest part of Qt (or other toolkit) to get right, and you are now having problems with them. I would not dream of using threads if I were new to C++ & Qt.
I don't know what you are trying to achieve but these Fortune examples do
QTcpSocket
without any threads:If you do want (really need!) to use threads have you had a look at:
-
I'm working on a project where I need to able to send a string from one device to another. So, the first thing I did was look up was examples of one script talking to another. One of the first ones I found used threads. I will however try this, thank you!
-
@rahulb1218
Depends whether these "scripts" were for Qt or not. Qt's TCP/socket code is inherently asynchronous, whereas other examples/toolkits are likely to be synchronous and so require threads.I did not say using threads was necessarily wrong (depends exactly what you have to do in your proposed thread). What I did say is that if I were new to both Qt & C++ I would not choose to use threading if I could possibly help it! :)