Displaying Client Packages on Server GUI
-
Hello all,
I am quite new to Qt (have been dabbling in it for about 3 weeks by looking through the Qt documentation, browsing through the forums, reading bits from C++ GUI Programming with QT 4, Second Edition, and following Youtube tutorials) and I've come across a problem I just can't seem to find the answer to. What I want to do with this program involves a server being set up via GUI, and receiving data constantly from a client to display in the GUI's textEdit or something similar. The problem I am running into is getting the data being sent from the client to actually show up in the GUI.
Some things to note before getting to my code:
-
I've tested this code without the GUI using just the console and everything works as intended. So I figured that in order to convert the display from console to GUI I could just replace the qDebug() output with the use of signal and slots and emit.
-
This code closely mirrors Voidrealms' tutorial on QTcpServer using multi threading that is available on Youtube.
-
My expertise in Qt is very limited as of right now, so if anything in the code looks like poor coding, please let me know because I want to learn as much as I can about creating GUI's in Qt.
So onto the code:
MyServer.h
@#include <QTcpServer>
#include <QDebug>
#include "mythread.h"class MyServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0);
//void StartServer();public slots:
protected:
void incomingConnection(qintptr socketDescriptor);signals:
void display(const QString);
};@MyServer.cpp
@#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
}/void MyServer::StartServer()
{
if(!this->listen(QHostAddress::Any, 4975))
{
qDebug() << "Could not start server";
}
else
{
qDebug() << "Listening...";
}
}/void MyServer::incomingConnection(qintptr socketDescriptor)
{
emit display(QString(socketDescriptor + " Connecting..."));
MyThread *thread = new MyThread(socketDescriptor, this);
connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
thread->start();
}@I think my problem starts in line 22 of the cpp file with the emit. The reason is because every time I try to connect with a client, I get a message in my GUI that says, "qRegisterNormalizedMetaType was called with a not normalized type name, please call qRegisterMetaType instead." the moment the client connects to the server. I have tried to look this up in the documentation and in the forums, but everything I read either isn't similar to my problem or just doesn't make sense to me.
Also, I have commented out the StartServer() because I decided to put that into the MainWindow.cpp just to get something to display. I'm sure there's a way to start it up via push button and with it being back in the MyServer.cpp (which is what I eventually want to do), but after spending hours on this problem without any results I needed something to display in the GUI to ease my frustration slightly.
MyThread.h
@#include <QThread>
#include <QTcpSocket>class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int ID, QObject *parent = 0);
void run();public slots:
void readyRead();
void disconnected();private:
QTcpSocket *socket;
int socketDescriptor;signals:
void error(QTcpSocket::SocketError socketerror);
void display2(const QString);
};@MyThread.cpp
@#include "mythread.h"
#include "mainwindow.h"MyThread::MyThread(int ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
}void MyThread::run()
{
emit display2(socketDescriptor + "Starting thread");
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
emit error(socket->error());
return;
}connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()),Qt::DirectConnection); connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()),Qt::DirectConnection); emit display2(QString(socketDescriptor + " Client Connected")); exec();
}
void MyThread::readyRead()
{
QByteArray Data = socket->readAll();
emit display2(socketDescriptor + " Data in: " + Data);socket->write("\r\nData Recieved\r\n");
}
void MyThread::disconnected()
{
emit display2(socketDescriptor + " has disconnected");
socket->deleteLater();
exit(0);
}@Currently, the display2() signal is not being used because I couldn't get it to connect to the mainwindow via signal and slots. Since I couldn't get the MyServer.cpp to display something in the GUI correctly, I figured that I would need to focus on the solution to that problem first and then the solution from that would probably apply to the MyThread.cpp as well.
Continued...
-
-
I also understand that there is a "more correct" method to implement threads because a QThread isn't a QObject or something; however, I would like to get this working before I begin optimizing my code.
MainWindow.h
@#include <QMainWindow>
#include <QThread>
#include <QTcpServer>
#include "myserver.h"
#include "mythread.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{
Q_OBJECTpublic:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();private:
Ui::MainWindow *ui;
QTcpServer *server;
QThread *thread;public slots:
void display1(const QString);
};@MainWindow.cpp
@#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myserver.h"
#include"mythread.h"
#include <QTcpServer>
#include <QtGui>
#include <QThread>MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
server = new MyServer();
if(!server->listen(QHostAddress::Any, 4975))
{
ui->textEdit-> setText(tr("Could not Connect"));
}
else
{
ui->textEdit->setText(tr("Listening..."));
}connect(server,SIGNAL(display(QString)),this,SLOT(display1(QString)));
}
MainWindow::~MainWindow()
{
delete ui;
}void MainWindow::display1(QString text)
{
ui->textEdit->append(tr(text.toUtf8().constData()));
}@So here is where I figured I would be able to establish my signal and slot connections for the server and threads to the GUI, but I couldn't get the program to compile and run probably because I lack a full understanding of threads. I tried to do something similar to the implementation I used for the server:
@thread = new MyThread();
connect(thread,SIGNAL(display2(QString)),this,SLOT(display1(QString)));@but Qt is telling me that there is no appropriate default constructor available.
Main.cpp
@#include "mainwindow.h"
#include <QApplication>
#include "myserver.h"int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();return a.exec();
}
@I haven't really touched the main.cpp and I don't know if I should be for this program.
I know I am probably asking for quite a lot of help and I realize that my code might seem convoluted to many of you, but I just want to say ahead of time thank you for reading through my code and assisting me with my problem. Anything to point me in the right direction will be greatly appreciated.
-
Hi and welcome to devnet,
Here is a short summary from a quick overview of your post/code:
QThread is a QObject
MyThread's constructor needs an int as a parameter
You can't add a qintptr to a string and get some automatic conversion to QString
You have a memory leak since you never delete the server variableHope it helps
-
Thank you for the tips. Getting rid of the qintptr in the emit got rid of that weird message and now allows the GUI to display "Connecting...".
About the int parameter, I assume it would be ideal in my case to have the parameter be the socketDescriptor value? I have been trying to pass around the socketDescriptor from MyThread with no luck so far. Although, I am confused on what the parameter is actually for and how it will allow me to connect MyThread to MainWindow.
-
It must be.
You should look again at the threaded fortune server example. It looks like you are mixing several concept here between the server and client concepts
It's an equivalent of the file descriptor but for a network socket.
-
So, after more browsing I found I could just connect to the object being created in MyServer by doing something like:
@connect(server>thread,SIGNAL(display2(const QString)),this,SLOT(display1(const QString))); connect(server>thread,SIGNAL(display5(QByteArray)),this,SLOT(display6(QByteArray)));@
in the MainWindow instead of trying to create a MyThread object in the MainWindow.
I have also cleaned up the MainWindow by doing:
@ ui->setupUi(this);
server = new Server();connect(server,SIGNAL(display(const QString)),this,SLOT(display1(const QString))); connect(server,SIGNAL(display3(int)),this, SLOT(display4(int))); server->StartServer(); connect(server->thread,SIGNAL(display2(const QString)),this,SLOT(display1(const QString))); connect(server->thread,SIGNAL(display5(QByteArray)),this,SLOT(display6(QByteArray)));
@
instead of including the if else statement. I made the appropriate changes to the qDebug and made them into emits for it to work.
However, I run into the issue of the thread not being created and executed until there is an incoming connection. Is it possible to connect an arbitrary thread to the MainWindow and then define and start it when I receive an incoming connection? If it is, how would I go about doing such a thing for my case?