PDA

View Full Version : QTcpSocket parent-child constructor woes (also cross-thread talk)



amdreallyfast
25th May 2014, 17:16
I spent about 10 hours yesterday with Qt stuff and I'm kind of exhausted, so I'm really bad at searching for answers on my own right now. If you guys could help me out, that would be appreciated.

The basic idea is that I want to start up TCP socket communication (it reads accelerometer data from a microcontroller), and I want to start up a QGLWidget to do other stuff. The QTcpSocket starts up in it's own thread (apparently on its own) though and can't be set as the QObject child of the QGLWidget, or at least that was my conclusion based on the threading errors that popped up. Then I tried to get a basic QTcpSocket to work and it broke. I am failing here.

What is wrong with the following code? I spits out the following runtime error:



QObject: Cannot create children for a parent that is in a different thread.
(Parent is in my_TCP_Q_socket_with_readyRead(*some address*), parent's thread is QThread(*some address*), current thread is QThread(*some address*)


For the record, I am I using QtCreator now. I figured out how to move between Visual Studio and QtCreator, so I just picked one.
Here is main.cpp:


#include <QTcpSocket>
#include <QObject>

#include <iostream>
using std::cout;
using std::endl;


class my_TCP_Q_socket_with_readyRead : public QObject
{
public:
explicit my_TCP_Q_socket_with_readyRead(QObject *parent = 0) :
QObject(parent)
{
m_socket_ptr = new QTcpSocket(this); // complains about parent-child threading
//m_socket_ptr = new QTcpSocket(0); // no error (??but what is it doing? it is silent??)
}


private:
Q_OBJECT

QTcpSocket *m_socket_ptr;
};


#include "main.moc"

int main(int argc, char *argv[])
{
my_TCP_Q_socket_with_readyRead s;

return 0;
}


What am I doing wrong? I found that this code doesn't complain if I provide a 0 (integer zero) as the argument to the QTcpSocket, but why?


As a related followup question, is it possible to use signals and slots to pass data from the thread that has the QTcpSocket to the thread that contains my QGLWidget? I think I can figure out how to make signals and slots work to call a function in QGLWidget once my custom QTcpSocket object is done reading data, but I don't know how to pass data from one to the other. Or am I missing the way this works? I haven't discovered how or when Qt starts threads on its own (which it clearly does considering that the error shown above specifies two threads).

anda_skoa
25th May 2014, 20:02
What am I doing wrong?

No idea, your code is obviously more than what you have posted.



I found that this code doesn't complain if I provide a 0 (integer zero) as the argument to the QTcpSocket, but why?

0 is the value of a null pointer, so no parent.



As a related followup question, is it possible to use signals and slots to pass data from the thread that has the QTcpSocket to the thread that contains my QGLWidget?

Yes, though you most likely don't need threads here at all (Qt's networking code operates event based by default).



I think I can figure out how to make signals and slots work to call a function in QGLWidget once my custom QTcpSocket object is done reading data, but I don't know how to pass data from one to the other.

Signals can carry arguments. Since it is unlikely that the data received via socket is directly usable by a QGLWidget, you will probably want to receive it in a slot that interprets the data.
Can of course be in a slot of a class derived from QGLWidget, though it is probably cleaner to use a dedicated connection/data handling object instead.

Cheers,
_

amdreallyfast
25th May 2014, 21:40
...your code is obviously more than what you have posted.


Nope. That code is all my test code in it's entirety. I just pasted it back into QtCreator and it gave me the same error. Does it work for you?

anda_skoa
25th May 2014, 22:48
Ah, then you need to create a Qt application object, e.g. a QCoreApplication instance, before creating the QTcpSocket,

Cheers,
_

amdreallyfast
25th May 2014, 23:08
Funny thing about that: I tried both the QApplication (that one took awhile to figure out the .pro file) and QCoreApplication, and they both give the same error. The error comes from the QTcpSocket constructor, not from the application. The bizarre part is that it seems that the QTcpSocket was created anyway, and while QCoreApplication ignores it, Qapplication goes ahead anyway and is happy with my QObject::connect(...) stuff and it works, so I don't know what it's complaining about.

Bottom line: My code works, but something, somewhere, is still not ok.

Note: This is a QConsole project. Here is my .pro file:


QT += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = testing_1
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app


SOURCES += main.cpp

HEADERS +=


INCLUDEPATH += tmp/moc/release_shared

unix|win32: LIBS += -L$$PWD/../../../../../Qt/4.8.5/lib/ -lQtCore4

INCLUDEPATH += $$PWD/../../../../../Qt/4.8.5/include
DEPENDPATH += $$PWD/../../../../../Qt/4.8.5/include




Here is my latest experimental code if you're interested:


#include <QApplication>
#include <QtCore/QCoreApplication>

#include <iostream>
using std::cout;
using std::endl;

#include <QtDebug>
#include <QObject>
#include <QtNetwork/QTcpSocket>


class my_TCP_Q_socket_with_readyRead : public QObject
{
public:
explicit my_TCP_Q_socket_with_readyRead(QObject *parent = 0) :
QObject(parent)
{
// ??why are you not ok taking "this" as an argument ?!
m_socket_ptr = new QTcpSocket(this);

m_socket_ptr->connectToHost("10.10.10.126", 5);
if (!(m_socket_ptr->waitForConnected((5000))))
{
qDebug() << "not connected";
m_socket_ptr = NULL;
}
else
{
qDebug() << "connected";
}

QObject::connect(
m_socket_ptr,
SIGNAL(readyRead()),
this,
SLOT(read_it()));
}


// http://qt-project.org/wiki/Qt_for_beginners_Signals_and_slots_2
// "Even if the signal is declared as a method, there is no
// need to implement it. The meta-object compiler is used to
// do this."
Q_SIGNAL void done_reading(int num);

private:
Q_OBJECT

QTcpSocket *m_socket_ptr;
QByteArray m_arr;

Q_SLOT void read_it()
{
static int read_count = 0;
qint64 bytes_available = m_socket_ptr->bytesAvailable();

if (bytes_available > 0)
{
read_count += 1;

qDebug() << "Reading '" << bytes_available << "' bytes";
m_arr = m_socket_ptr->readAll();
qDebug() << m_arr;
}

emit done_reading(read_count);
}
};


class my_class : public QObject
{
public:
explicit my_class(QObject *parent = 0) :
QObject(parent)
{

}

Q_SLOT void say_something(int num)
{
cout << "hey there! number is '" << num << "'" << endl;
}

private:
Q_OBJECT
};


#include "main.moc"

int main(int argc, char *argv[])
{
int app_ret_val = 0;
//QApplication app(argc, argv);
QCoreApplication app(argc, argv);

my_TCP_Q_socket_with_readyRead s;
my_class mc;

QObject::connect(&s, SIGNAL(done_reading(int)), &mc, SLOT(say_something(int)));

app_ret_val = app.exec();


return app_ret_val;
}


I've been trying to hunt down how the basic QTcpSocket constructor is supposed work with the "this" argument. It is supposed to "just work" from the demos that I have seen, so I don't know where to to do when it doesn't work. Any more ideas?

anda_skoa
26th May 2014, 08:13
Have you tried not using the blocking I/O methods, i.e. any of the "waitFor..." ones?

Cheers,
_