GUI Freezes using QProcess during data acquisition - qt

PROBLEM DEFINITION: I have an external application called runSensor that communicates with a sensor. The sensor sends its data over UDP. Using the terminal, runSensor has two arguments to communicate with the sensor for data acquisition:start and stop.
Once at the terminal I call: $ runSensor start, a sample output is as follows:
[Time 07:20:11:000]: Device PoweredOn.
[Time 07:20:11:010]: x=1.231, y=-0.022, z=0.001
[Time 07:20:11:015]: x=1.235, y=-0.024, z=0.001
[Time 07:20:11:020]: x=1.241, y=-0.024, z=0.002
[Time 07:20:11:025]: x=1.258, y=-0.027, z=0.002
I need to call start and stop using a QT-UI. For that, I have a QDialog as follows:
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
this->socketHandler = std::make_shared<udpHandler>();
this->runSensorStartProcess = std::make_shared<QProcess>();
this->runSensorStopProcess = std::make_shared<QProcess> ();
//--------------------------
// SIGNAL - SLOT
//--------------------------
connect(ui->startButton, SIGNAL(clicked()), this, SLOT(onStartButtonClicked()));
connect(ui->stopButton, SIGNAL(clicked()), this, SLOT(onStopButtonClicked()));
connect(this->socketHandler.get(), SIGNAL(sendUdpContent(QString)), this, SLOT(updateMessageBrowser(QString)));
connect(this->runSensorStartProcess.get(), SIGNAL(readyReadStandardError()), this, SLOT(printError()));
}
I use QProcess to call the start and stop of runSensor application. When I push the GUI's start button, data acquisition starts, but the the GUI freezes and I cann't click on the stop button.
CODE EXTRACTS: Here is how I implemented the start button click:
void Dialog::onStartButtonClicked()
{
this->runSensorStartProcess->start("start");
//this->runSensorStartProcess->waitForFinished(-1);
//--------------------------
// udp socket handler starts picking data and write it into a file
//--------------------------
if (!this->runSensorStartProcess->waitForStarted())
{
qWarning() << "Warning: Cannot start Cygwin process!";
}
}
stop button click implementation is similar:
void Dialog::onStopButtonClicked()
{
if(this->runSensorStartProcess.get() != NULL)
{
this->runSensorStartProcess->close();
}
this->runSensorStopProcess->start("stop");
if (!this->runSensorStopProcess->waitForStarted())
{
qWarning() << "Warning: Cannot stop Cygwin!";
}
}
Question:
How can I keep th GUI responsive after runSensorStartProcess starts?
How can I stop that process on demand (in fact by starting runSensorStartProcess)?
Do I need a separate thread for runSensorStartProcess?

Don't use any of the waitForXxx methods. That's all. Yes, it's that simple.
Note that for every waitForXxx method there's a signal you can attach to and thus react to the event you're looking for.
Aren't QProcess::kill and QProcess::terminate what you need?
Never. See also answer 1 and answer 2.

Related

Qt6.2 network connection in the same LAN failed

I'm trying to write an app with Qt 6.2.4, and now I'm writing the internet-related part.Then something confused me.
I turned on Mobile Hotspot ,and my teammate and I both connected to it. After I started the server, we opened the client widget, only to find that the connection failed.Below are the code related to it.
server (Acctually it's provided by other person.To say frankly, I'm not familar with Qt's server)
NetworkServer::NetworkServer(QObject* parent)
: QTcpServer(parent)
, disconnMapper(new QSignalMapper(this))
, recvMapper(new QSignalMapper(this)) {
connect(this, &QTcpServer::newConnection, this, &NetworkServer::newconnection);
connect(this->disconnMapper, &QSignalMapper::mappedObject, this, &NetworkServer::disconnect);
connect(this->recvMapper, &QSignalMapper::mappedObject, this, &NetworkServer::receiveData);
this->listen(QHostAddress::Any, 2000);
}
client
mul_initwidget::mul_initwidget(QWidget *parent) :
QWidget(parent),
isConnected(false),
ui(new Ui::mul_initwidget),
username("user1")
{
ui->setupUi(this);
this->socket = new NetworkSocket(new QTcpSocket(), this);
qDebug()<<"mul_init create socket at" << (void*)&socket;
connect(socket, &NetworkSocket::receive, this, &mul_initwidget::receive);
//connect(socket->base(), &QAbstractSocket::disconnected, [=]() {
// QMessageBox::critical(this, tr("Connection lost"), tr("Connection to server has closed"));
//});
connect(socket->base(), SIGNAL(connected()), this, SLOT(setConnected()));
connect(socket->base(), SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(setDisconnected(QAbstractSocket::SocketError)));
ui->label_2->hide();
socket->hello(IP,PORT);
if(isConnected)
ui->label->setText("Welcome, "+username);
else
ui->label->setText("Unconnected.");
}
Please comment if u think it's not enough to find out what's wrong, and I will add more code if I can.

Qt QUdpsocket audiostreaming

I am trying to clone the audio streaming model of QTCpsocket but now using QUdpsocket (virtual connection), though it looks like the code is being executed , nevertheless, effectively its not doing the job, I cant get streamed audio captured;
Main focus point is: is it possible to start a QAudioOutput with a QUDpsocket ???
Yet to clearly mention that this code works fine with a TCP socket!
Code snippet:
in server.h file
private:
QUdpSocket *socketUDP;
and in .CPP file
udpServer::udpServer(QObject *parent) : QObject(parent)
{
socketUDP = new QUdpSocket(this);
serverAddress = QHostAddress("192.168.1.8");
//socketUDP->bind(serverAddress, 1357);
socketUDP->bind(1357, QUdpSocket::ShareAddress);
socketUDP->open(QIODevice::ReadOnly);
connect(socketUDP, &QUdpSocket::readyRead, this, &udpServer::playStreamedAudio);
}
then the playstream() method:
void udpServer::playStreamedAudio() {
// set the QAudioFormat parameters of output audio device.
my_QAudioFormat = new QAudioFormat;
my_QAudioFormat->setSampleRate(48000);
my_QAudioFormat->setChannelCount(1);
my_QAudioFormat->setSampleSize(8);
my_QAudioFormat->setCodec("audio/pcm");
my_QAudioFormat->setByteOrder(QAudioFormat::LittleEndian);
my_QAudioFormat->setSampleType(QAudioFormat::UnSignedInt);
//
// get default audio output device
audiOutputDevice = QAudioDeviceInfo::defaultOutputDevice();
audiooutput = new QAudioOutput(audiOutputDevice,my_QAudioFormat, this);
// attach to socket!
qDebug() << "Playaing AudioStream";
socketUDP->open(QIODevice::ReadOnly);
audiooutput->start(socketUDP); // the Audio output device shall listen to server socket for audio
}
It turns out that UDP sockets may not suitability be interfaced as QioDevices... seems they are not intended to be, the packets are better be written to a file and then processed.

I can't quit properly my apps if I use mysql connection

If I do not use connection I can properly exit.
In Pdv.h file
namespace Pdv {
...
extern QSqlDatabase db;
...
}
In LoginDialog.cpp file
QSqlDatabase Pdv::db;
...
Pdv::db= QSqlDatabase::addDatabase("QMYSQL3");
Pdv::db.setHostName(Pdv::DB_URL);
Pdv::db.setUserName(Pdv::DB_USER);
Pdv::db.setPassword(Pdv::DB_PASS);
Pdv::db.setDatabaseName(Pdv::DB_DB);
if(!Pdv::db.open()) {
...
// Checking user login/password and retrieve many variables
...
In mainwindow.cpp file
...
void MainWindow::closeEvent(QCloseEvent *event) {
...
if(Pdv::db.isOpen()) {
qDebug() << "Opened 1";
Pdv::db.close();
qDebug() << Pdv::db.lastError();
if(Pdv::db.isOpen())
qDebug() << "Opened 2";
}
Pdv::app->quit(); // or QApplication::quit();
}
I got this error in QTCreator console
Opened 1
QSqlError("", "", "")
Le programme s'est terminé subitement.
/home/cosmic/src/build-Pdv-Desktop-Debug/Pdv crashed.
A idea?
To make proper exit with usage of QSqlDatabase, you need preferably:
remove all instances of QSqlDatabase objects (because as you copy them, they will keep connection open).
As second condition, you need to use QSqlDatabe::removeDatabase() call. (also this call will make qDebug message if database is still in use occasionally - some QSqlDatabase object is left somewhere - it will help to identify a problem).
If you close and delete your MainWindow, and your program then crashes, then other parts of the program must be trying to use the MainWindow pointer even though it is destroyed.
I think the problem is the line of code Pdv::app->quit(); Try with QApplication::quit(); instead or review the code in Pdv::app->quit();.

Qt TCP/IP socket connection check

I am writing Qt TCP/IP client. I want to check the connection state with server before send data to sever.
As far my knowledge I can do this by following methods
Use a bool 'ConnectionState', set this variable when connected with
sever and reset this variable on disconnected() signal. Now before
sending data to server (client->write()) check the value of this
variable.
use this 'client->state() == QTcpSocket::ConnectedState' way to check the connection state.
Which is good practice. Or any other method to this.
Thanks In advance.
QTCPSocket is derived from QAbstractSocket, which provides a state() function. This returns one of the following enums: -
enum SocketState { UnconnectedState, HostLookupState, ConnectingState, ConnectedState, ..., ListeningState }
So, assuming m_pSocket is a QTcpSocket, you would simply do this to check if it is connected:-
bool connected = (m_pSocket->state() == QTcpSocket::ConnectedState);
You could add a boolean and keep track of the state, but if a network error occurs you need to ensure that it is always in-sync with the actual connection state.
You can use errorOccurred signal and It's just enough for this signal define a slot in client. when an error occurs, a signal trigger and you can receive notify in slot function.
In client.h
/* define a slot for client */
public slots:
void errorOccurred(QAbstractSocket::SocketError error);
In client.c
/*client constructor*/
Client::Client(QObject *parent) {
/*some other code here*/
connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
this, SLOT(errorOccurred(QAbstractSocket::SocketError)));
/*and maybe some other code here*/
}
and in client.c write implementation for errorOccurred:
void Client::errorOccurred(QAbstractSocket::SocketError error) {
qDebug() << "error in connection: " << socket->errorString();
}
OUTPUT:
error in connection: "Connection refused"

How to start video-suite in MeeGo / Nokia N9 from Qt code?

I am having problems with launching Nokia's own video player from my application that I just don't seem to be able to solve.
My first attempt included calling
Qt.openUrlExternally(url)
from QML and that seemed to do the trick just fine, except that it opened the browser every time and used it instead of the video-suite (native player).
Next I tried cuteTube -approach where I start new process like this:
QStringList args;
args << url;
QProcess *player = new QProcess();
connect(player, SIGNAL(finished(int, QProcess::ExitStatus)), player, SLOT(deleteLater()));
player->start("/usr/bin/video-suite", args);
That worked, except that it required video-suite to be closed upon calling player->start, otherwise it did nothing.
My third attempt involved starting the video-suite via QDBus, but that didn't work any better:
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
QDBusMessage message = QDBusMessage::createMethodCall(
"com.nokia.VideoSuite",
"/",
"com.nokia.maemo.meegotouch.VideoSuiteInterface",
"play");
message.setArguments(args);
message.setAutoStartService(true);
QDBusConnection bus = QDBusConnection::sessionBus();
if (bus.isConnected()) {
bus.send(message);
} else {
qDebug() << "Error, QDBus is not connected";
}
The problem with this is that it requires video-suite to be up and running - autoStartService parameter didn't help either. If video-suite isn't running already, the call opens it just fine but, alas, no video starts to play.
Eventually I tried using also VideoSuiteInterface, but even having the program compile with it seemed to be difficult. When I eventually managed to compile and link all relevant libraries, the results didn't differ from option 3 above.
So, is there a way to use either VideoSuiteInterface directly or via DBus so that it would start video playback regardless of the current state of the application?
The solution was actually simpler than I really thought initially; the VideoSuiteInterface -approach worked after all. All it took was to use it properly. Here are the full sources should anyone want to try it themselves.
player.h:
#ifndef PLAYER_H
#define PLAYER_H
#include <QObject>
#include <maemo-meegotouch-interfaces/videosuiteinterface.h>
class Player : public QObject {
Q_OBJECT
private:
VideoSuiteInterface* videosuite;
public:
Player(QObject *parent = 0);
Q_INVOKABLE void play(QString url);
};
#endif // PLAYER_H
player.cpp:
#include "player.h"
#include <QObject>
#include <QStringList>
#include <QtDeclarative>
Player::Player(QObject *parent) : QObject(parent) {}
void Player::play(QString url) {
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
videosuite = new VideoSuiteInterface();
videosuite->play(urls);
}
In addition you may want to connect some signals to make the UI more responsive, but basically that should do the trick.
Finally, you need to remember to add following to your .pro file and you are good to go:
CONFIG += videosuiteinterface-maemo-meegotouch

Resources