PDA

View Full Version : cannot write to QListWidget or QLineEdit



landonmkelsey
11th August 2008, 22:09
I have isolated the problem as follows:

I have some old old code for a TCP/IP server.

I cannot use QTCPIPServer or any Qt network programs!

I must use Qt 4 designer to make a gui to communicate with the TCP/IP server!

I press a button and a slot program calls the TCP/IP constructor.

The TCP/IP constructor calls the usual socket, bing, listen accept.

The program continues to work as a server but the code to write to a QListWidget or QLineEdit object does not work.

I've even tried putting the constructor in its own thread.

I've tried various placements of QApplication::processEvents();


#include "tcpip.h"
#include "tcpip_server.cpp"
#include "tcpip_client.cpp"
#include <iostream>
//#include <QtDebug>
tcpip::tcpip(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
connect( ui.pushButtonStartTCPServer, SIGNAL(clicked()), this, SLOT(StartTCPServer()) );
connect( ui.pushButtonStartTCPClient, SIGNAL(clicked()), this, SLOT(StartTCPClient()) );

ui.listWidgetServer->addItem(QString("server constructor")); ///works here

}

tcpip::~tcpip()
{
}
void tcpip::StartTCPServer()
{
ui.listWidgetServer->addItem(QString("server StartTCPServer")); // not here

// QApplication::processEvents();
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortServer->text();
port = qstr.toInt(&ok);
//qDebug()<<" server port "<<port;
ui.lineEditServerStatus->setText("server started");

QApplication::processEvents();

tcpipThread tcpipThreadStart(ui, port);
tcpipThreadStart.run();
tcpipThreadStart.wait(ULONG_MAX);

}
void tcpip::StartTCPClient()
{
ui.listWidgetClient->addItem(QString("client StartTCPClient"));
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortClient->text();

//QApplication::processEvents();
ushort port = qstr.toInt(&ok);
//qDebug()<<"client port = "<<port;
tcpip_client* p_client = new tcpip_client((int)19999,port,FALSE, ui);

str_client(p_client, ui); /* process the request */
close();
}


}
void tcpip::currChanged(QWidget*){};

void tcpipThread::run()
{
tcpip_server* p_serv = new tcpip_server((int)19999,port,tcpip_server::str_ech o, ui);
qDebug()<<"oops...back from CTOR";
delete p_serv;
}

jacek
11th August 2008, 23:06
tcpipThread tcpipThreadStart(ui, port);
tcpipThreadStart.run();
tcpipThreadStart.wait(ULONG_MAX);
To start the thread you have to invoke QThread::start(), not run(). And don't wait for the thread here, because you will block the event loop and your GUI won't work.

landonmkelsey
12th August 2008, 01:13
Thanks I'll try that !

Strange that QApplication::processEvents(); didn't help!

getting a message from qtcentre but it states that popup blocker is the problem.

I think I have the code as you recommended. Still doesn't work!

The tcp/ip section still works under the cover of the gui.

BTW the gui features (close, etc) are also locked up!

Can't be far from success!:)

The Qt documentation example for QThread uses run().




// tcpip.h
#ifndef TCPIP_H
#define TCPIP_H
#include <QThread>
#include <QtGui/QWidget>
#include "ui_tcpip.h"
class tcpip_client;
class tcpip : public QWidget
{
Q_OBJECT

public:
tcpip(QWidget *parent = 0);
~tcpip();

private:
Ui::tcpipClass ui;
ushort port;
private slots:
void StartTCPServer();
void StartTCPClient();
void str_client(tcpip_client* tcpip_x, Ui::tcpipClass ui);
void currChanged(QWidget*);
};
class tcpipThread : public QThread
{
Ui::tcpipClass ui;
ushort port;
public:
tcpipThread( Ui::tcpipClass uiparm, unsigned portParam):ui(uiparm),port(portParam)
{}
void run(){}
void start();
};

#endif // TCPIP_H

// tcpip.cpp

#include "tcpip.h"
#include "tcpip_server.cpp"
#include "tcpip_client.cpp"
#include <iostream>
//#include <QtDebug>
tcpip::tcpip(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
connect( ui.pushButtonStartTCPServer, SIGNAL(clicked()), this, SLOT(StartTCPServer()) );
connect( ui.pushButtonStartTCPClient, SIGNAL(clicked()), this, SLOT(StartTCPClient()) );

ui.listWidgetServer->addItem(QString("server constructor"));

}

tcpip::~tcpip()
{
}
void tcpip::StartTCPServer()
{
ui.listWidgetServer->addItem(QString("server StartTCPServer"));

// QApplication::processEvents();
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortServer->text();
port = qstr.toInt(&ok);
//qDebug()<<" server port "<<port;
ui.lineEditServerStatus->setText("server started");

QApplication::processEvents();

tcpipThread tcpipThreadStart(ui, port);
tcpipThreadStart.start();
// tcpipThreadStart.wait(ULONG_MAX);

}
void tcpip::StartTCPClient()
{
ui.listWidgetClient->addItem(QString("client StartTCPClient"));
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortClient->text();

//QApplication::processEvents();
ushort port = qstr.toInt(&ok);
//qDebug()<<"client port = "<<port;
tcpip_client* p_client = new tcpip_client((int)19999,port,FALSE, ui);

str_client(p_client, ui); /* process the request */
close();
}
//
#define MAXLINE 512

// str_client is the client processing program
// particular to the application and depends on
// what the server is doing
void tcpip::str_client(tcpip_client* tcpip_x, Ui::tcpipClass ui)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
bool done=FALSE;
while (!done)
{
cout<<"enter keyboard string"<<endl;
cin.getline(sendline,256);
n = strlen(sendline);
if(n==0) break;
sendline[n] = '\n'; /* newline terminate */
sendline[n+1] = 0; /* newline terminate */
n++;
// use our client object to write to the server
ui.listWidgetClient->addItem(QString("client constructorstr_client"));
tcpip_x->tcp_write(sendline,n);
cout<<"sendline:"<<sendline<<endl;
/*
* Now read a line from the socket and write it to
* our standard output.
*/

n = tcpip_x->tcp_read(recvline);
recvline[n] = '\n'; /* null terminate */
recvline[n+1] = 0; /* null terminate */
n++;
cout<<"bytes received "<<n;
cout<<"client received:echo = "<<recvline<<endl;
}

}
void tcpip::currChanged(QWidget*){};

void tcpipThread::start()
{
tcpip_server* p_serv = new tcpip_server((int)19999,port,tcpip_server::str_ech o, ui);
qDebug()<<"oops...back from CTOR";
delete p_serv;
}

wysota
12th August 2008, 07:47
You are creating your thread on stack, so it goes out of scope immediately. I doubt it is what you want. Then your str_client performs an endless loop, blocking Qt's event loop from processing events hence the GUI freeze. So currently you should observe your GUI freezing and your server not working.

jacek
12th August 2008, 14:38
getting a message from qtcentre but it states that popup blocker is the problem.
You can access your private messages by clicking "User CP" link in the top-left or "Private Messages" in the top-right corner.

landonmkelsey
12th August 2008, 19:18
You are creating your thread on stack, so it goes out of scope immediately. I doubt it is what you want. Then your str_client performs an endless loop, blocking Qt's event loop from processing events hence the GUI freeze. So currently you should observe your GUI freezing and your server not working.

The server continues to work but maybe you've given me a critical clue!

Thanks!

The gui is truly locked up!

It is actually str_echo that works in the server.

Later I must straighten out all this code!

ah legacy code!

problem str_echo is not called until a client "calls" in.

The gui fails/locks up before then!

I did fix this...thanks!

tcpipThread* ptcpipThreadStart = new tcpipThread(ui, port);
ptcpipThreadStart->start();

the listen(), accept() blocks are now in their own thread



void tcpipThread::start()
{
tcpip_server* p_serv = new tcpip_server((int)19999,port,tcpip_server::str_ech o, ui);
qDebug()<<"oops...back from CTOR";
delete p_serv;
}


The problem still exists!

It is unusual that I cannot write to QListWidget or QLineEdit even if I put a sleep(10) before the server is instantiated in its own thread!

landonmkelsey
14th August 2008, 18:47
note the use of dup2 to try another file descriptor
note that even putting a sleep(10) ahead of all this does not allow write to
QLineEdit and QListWidget



#include "inet.h"
#include <iostream>
#include <sstream>
#include <exception>
using namespace std;
#include "thread.cpp"
#include "sock_io.cpp"
#include "tstash.h"
#include <QtDebug>

typedef void* (*p_VOID_FUNCT)(void*);
class tcpip_server {
static int socketfd, newsocketfd;
socklen_t clilen;
struct sockaddr_in cli_addr, serv_addr;
ushort port;
// struct sock_addr_in accept_ip_struct;
int accept_ip_address;
int client_ip_address;
public:
static bool running;

static void* str_echo(void* p_void);
// struct sock_addr_in client_ip_struct;
public:

tcpip_server(int accept_ip_addr,
ushort port_port,
p_VOID_FUNCT p_void_funct, Ui::tcpipClass ui):
accept_ip_address(accept_ip_addr),
port(port_port)

{

int setreuse=1;
int istatus;

//
// server constructor section
//

/*
* Open a TCP socket (an Internet stream socket).
*/
if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0";
return;
}
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0))"<<socketfd;
int errorDup = dup2(socketfd,20);
qDebug()<<"errorDup"<<errorDup;
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0))"<<socketfd;
/*
* Bind our local address so that the client can send to us.
*/

memset((char *) &serv_addr,0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_TCP_PORT);

/********************* set up so several server processes **************/
/***** can use the same port ******************************************/

if(istatus = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,
(char *) &setreuse, sizeof(setreuse)))
{
qDebug()<<"setsockopt";
return;
}


if (bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
qDebug()<<"bind";
return;
}

listen(socketfd, 5);

tstash<sock_io> vector_psio;
void* p_void = NULL;
running = true;
while(1)
{

clilen = sizeof(cli_addr);
qDebug()<<"enter accept()";
newsocketfd = accept(socketfd, (struct sockaddr *) &cli_addr,
&clilen);
// (unsigned int*)&clilen);
qDebug()<<"newsocketfd"<<newsocketfd;
qDebug()<<"exit accept()";
if (newsocketfd < 0)
{

return;
}


sock_io* p_sio = new sock_io( newsocketfd);
p_void = (void*)p_sio;

tthread* p_thread = new tthread( p_void_funct, p_void);

p_thread->run();

}


}
// destructor
~tcpip_server()
{
close(socketfd); /* close original socket */

}
};// end of class declaration

/*
* Read a stream socket one line at a time, and write each line back
* to the sender.
*/

#define MAXLINE 512
bool tcpip_server::running = true;
int tcpip_server::socketfd = 0;
int tcpip_server::newsocketfd = 0;
void* tcpip_server::str_echo(void* p_void)
{

sock_io* p_sio = (sock_io*)p_void;
int n;
char line[MAXLINE];
const char* pline = line;
bool exitNow = false;
do
{


n = p_sio->tcp_read(line);
// cout<<n<<"characters received"<<endl;
if(!n)
{
running = false;
close(socketfd);
close(newsocketfd);
qDebug()<<"str_echo tried to close";
exit(0);
}
line[n] = '\n';
line[n+1] = 0;
n++;
QString qstr(pline);
qstr.trimmed();
qDebug()<<"_____"<<qstr<<"_________";

if (qstr == QString("close"))
{
qDebug()<<"close detected";
running = false;
close(socketfd);
close(newsocketfd);
exitNow = true;
break;
}

p_sio->tcp_write(line, n);
} while(1);

void* p_void_exit=0;
// destruct thread object, work done

delete p_sio;

pthread_exit(p_void_exit);
if (exitNow) exit(0);
return p_void_exit;

}

wysota
14th August 2008, 21:04
Ok, could you pinpoint where in your code exactly the GUI gets frozen? You might do it using a debugger or by placing qDebug() statements in your code to see where the execution stops. It's hard for us to trace your code as there are many function calls to 3rd party code, so you have to do it yourself.

jacek
14th August 2008, 21:20
void tcpipThread::start()
{
tcpip_server* p_serv = new tcpip_server((int)19999,port,tcpip_server::str_ech o, ui);
qDebug()<<"oops...back from CTOR";
delete p_serv;
}

If tcpipThread is a QThread subclass, this should be in run().

The Storm
14th August 2008, 22:52
http://doc.trolltech.com/4.4/qthread.html
Read more about the threads, you must put your code in to the run() overloaded function and to start the thread via the start() method, then you code in run() will begin to execute. ;)

landonmkelsey
15th August 2008, 17:37
:)

Thanks...I will be working on this today and tonight!

The Qt4 docs say that start is a slot and the QThread example describes run() in the little example..

I *will* switch as you have directed!!!! Thanks!

The TCP/IP server mechanism works in spite of this problem.

What mystifies me is that the problem persists even if I put a sleep(10) ahead of the tcpip_server code!

Thanks again!

:D

I got the program to work using some well placed:


QApplication::processEvents(); (see tcpip.cpp):D


inside the server code...who knows which one made it work!

The code hangs up in accept() as it should in TCP/IP server code.

waiting for a client. Accept hangs up Qt 4 tight!

I did the run/start thread code as suggested!

I think it is working!

Thanks!


tcpip.h


#ifndef TCPIP_H
#define TCPIP_H
#include <QThread>
#include <QtGui/QWidget>
#include "ui_tcpip.h"
class tcpip_client;
class tcpipThread;
class tcpip : public QWidget
{
Q_OBJECT

public:
tcpip(QWidget *parent = 0);
~tcpip();


private:
Ui::tcpipClass ui;
ushort port;
tcpipThread* ptcpipThreadStart;
private slots:
void StartTCPServer();
void StartTCPClient();
void str_client(tcpip_client* tcpip_x, Ui::tcpipClass ui);
void currChanged(QWidget*);
};

class tcpipThread : public QThread
{
Ui::tcpipClass ui;
ushort port;
public:
tcpipThread( Ui::tcpipClass uiparm, unsigned portParam):ui(uiparm),port(portParam)
{}
void run();

};

#endif // TCPIP_H

tcpip.cpp


#include "tcpip.h"
#include "tcpip_server.cpp"
#include "tcpip_client.cpp"
#include <iostream>
//#include <QtDebug>
tcpip::tcpip(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
connect( ui.pushButtonStartTCPServer, SIGNAL(clicked()), this, SLOT(StartTCPServer()) );
connect( ui.pushButtonStartTCPClient, SIGNAL(clicked()), this, SLOT(StartTCPClient()) );
connect( ui.pushButtonClose, SIGNAL(clicked()), this, SLOT(localClose()) );

ui.listWidgetServer->addItem(QString("server constructor"));

}
//
tcpip::~tcpip()
{
delete ptcpipThreadStart;
}
void tcpip::StartTCPServer()
{
ui.listWidgetServer->addItem(QString("server1 StartTCPServer"));

QApplication::processEvents();
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortServer->text();
port = qstr.toInt(&ok);
//qDebug()<<" server port "<<port;
ui.lineEditServerStatus->setText("server started");

QApplication::processEvents();

tcpipThread* ptcpipThreadStart = new tcpipThread(ui, port);
ptcpipThreadStart->start();


}
// ignore the following
void tcpip::StartTCPClient() // not part of the server...ignore
{
ui.listWidgetClient->addItem(QString("client StartTCPClient"));
bool ok = true;
QString qstr = ui.lineEditTCPIPServerPortClient->text();

//QApplication::processEvents();
ushort port = qstr.toInt(&ok);
//qDebug()<<"client port = "<<port;
tcpip_client* p_client = new tcpip_client((int)19999,port,FALSE, ui);

str_client(p_client, ui); /* process the request */
close();
}
//
#define MAXLINE 512

// str_client is the client processing program
// particular to the application and depends on
// what the server is doing
void tcpip::str_client(tcpip_client* tcpip_x, Ui::tcpipClass ui)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
bool done=FALSE;
while (!done)
{
cout<<"enter keyboard string"<<endl;
cin.getline(sendline,256);
n = strlen(sendline);
if(n==0) break;
sendline[n] = '\n'; /* newline terminate */
sendline[n+1] = 0; /* newline terminate */
n++;
// use our client object to write to the server
ui.listWidgetClient->addItem(QString("client constructorstr_client"));
tcpip_x->tcp_write(sendline,n);
cout<<"sendline:"<<sendline<<endl;
/*
* Now read a line from the socket and write it to
* our standard output.
*/

n = tcpip_x->tcp_read(recvline);
recvline[n] = '\n'; /* null terminate */
recvline[n+1] = 0; /* null terminate */
n++;
cout<<"bytes received "<<n;
cout<<"client received:echo = "<<recvline<<endl;
}

}
void tcpip::currChanged(QWidget*){};

void tcpipThread::run()
{
tcpip_server* p_serv = new tcpip_server((int)19999,port,tcpip_server::str_ech o, ui);
qDebug()<<"should not happen before client calls in...back from CTOR";
delete p_serv;
}


tcpip_server.cpp


#include "inet.h"
#include <iostream>
#include <sstream>
#include <exception>
using namespace std;
#include "thread.cpp"
#include "sock_io.cpp"
#include "tstash.h"
#include <QtDebug>

typedef void* (*p_VOID_FUNCT)(void*);
class tcpip_server {
static int socketfd, newsocketfd;
socklen_t clilen;
struct sockaddr_in cli_addr, serv_addr;
ushort port;
// struct sock_addr_in accept_ip_struct;
int accept_ip_address;
int client_ip_address;
Ui::tcpipClass ui;
public:
static bool running;
void localClose();
static void* str_echo(void* p_void);
// struct sock_addr_in client_ip_struct;
public:

tcpip_server(int accept_ip_addr,
ushort port_port,
p_VOID_FUNCT p_void_funct, Ui::tcpipClass uip):
accept_ip_address(accept_ip_addr),
port(port_port),
ui(uip)

{

int setreuse=1;
int istatus;

//
// server constructor section
//

/*
* Open a TCP socket (an Internet stream socket).
*/
if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0";
return;
}
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0))"<<socketfd;
int errorDup = dup2(socketfd,20);
qDebug()<<"errorDup"<<errorDup;
qDebug()<<"socketfd = socket(AF_INET, SOCK_STREAM, 0))"<<socketfd;
/*
* Bind our local address so that the client can send to us.
*/

memset((char *) &serv_addr,0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_TCP_PORT);

if(istatus = setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,
(char *) &setreuse, sizeof(setreuse)))
{
qDebug()<<"setsockopt";
return;
}


if (bind(socketfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
qDebug()<<"bind";
return;
}

listen(socketfd, 5);

tstash<sock_io> vector_psio;
void* p_void = NULL;
running = true;
while(1)
{
QApplication::processEvents();

clilen = sizeof(cli_addr);

newsocketfd = accept(socketfd, (struct sockaddr *) &cli_addr,
&clilen);

if (newsocketfd < 0)
{

return;
}


sock_io* p_sio = new sock_io( newsocketfd);
p_void = (void*)p_sio;

tthread* p_thread = new tthread( p_void_funct, p_void);

p_thread->run();

}


}
// destructor
~tcpip_server()
{
close(socketfd);

}
};// end of class declaration
#define MAXLINE 512
bool tcpip_server::running = true;
int tcpip_server::socketfd = 0;
int tcpip_server::newsocketfd = 0;
void* tcpip_server::str_echo(void* p_void)
{

sock_io* p_sio = (sock_io*)p_void;
int n;
char line[MAXLINE];
const char* pline = line;
bool exitNow = false;
do
{


n = p_sio->tcp_read(line);

if(!n)
{
running = false;
close(socketfd);
close(newsocketfd);

exit(0);
}
line[n] = '\n';
line[n+1] = 0;
n++;
QString qstr(pline);
qstr.trimmed();
qDebug()<<"_____"<<qstr<<"_________";

if (qstr == QString("close"))
{
qDebug()<<"close detected";
running = false;
close(socketfd);
close(newsocketfd);
exitNow = true;
break;
}

p_sio->tcp_write(line, n);
} while(1);

void* p_void_exit=0;
delete p_sio;

pthread_exit(p_void_exit);
if (exitNow) exit(0);
return p_void_exit;

}
void tcpip_server::localClose()
{

running = false;
close(socketfd);
close(newsocketfd);
}

wysota
17th August 2008, 20:39
A general rule is that if you use Qt's networking mechanism in a thread (QThread), you need to start its event loop by calling QThread::exec() with all its consequences.

landonmkelsey
18th August 2008, 08:37
program is now working perfectly (for the desired current state)

thanks!

I'll try the exec()