Please can some-one suggest on this question..? I have to send data from my TX thread to mainwindow using class derived from QEvent.
I want my RX thread to throw an event whenever some data is received so hat i can display that data in the Mainwindow.
I start a main thread when button start is pressed. I save the pointer to my mainwindow inside the object of main thread. I will use this pointer to post events to the mainwindow object.
When first time i enter the Qthread function dowork_rx(). Event is thrown & i am able to catch it in customEvent() handler. But when dowork_rx() while loop starts when i throws the event it does not trigger the customEvent() function.
Please suggest how to resolve this problem.
My qevent class :---
//String event derived class
template <typename T> class StringEvent : public QEvent
{
QString m_str;
public:
explicit StringEvent(const QString val) : QEvent(staticType()), m_str(val)
{
}
void setvalue(QString val)
{
m_str = val;
}
QString value() const
{
return m_str;
}
static QEvent::Type staticType()
{
static int type = QEvent::registerEventType();
return static_cast<QEvent::Type>(type);
/*
static int type;
if(type == 0)
{
type = QEvent::registerEventType();
}
return static_cast<QEvent::Type>(type);*/
}
static bool is(const QEvent * ev)
{
return ev->type() == staticType();
}
};
class UpdateEvent : public StringEvent<UpdateEvent>
{
public:
explicit UpdateEvent(QString val): StringEvent(val)
{
//qDebug() << "hello";
}
};
class ClearEvent : public StringEvent<ClearEvent>
{
public:
explicit ClearEvent(QString val): StringEvent(val)
{
}
};
Dowork function of the thread :----
// Common slot for the rx - thread
void RxThreadObject::dowork_rx()
{
int i =0;
qDebug() << "\nrx start \n";
myUpdateEvent_rx = new UpdateEvent("UpdateEventObject - dowork_rx");
//myUpdateEvent_rx->setvalue("first");
QCoreApplication::postEvent(m_pMainThreadObj->ptrmainwindow, myUpdateEvent_rx);
qDebug() << "\nrx throw event - done \n";
while(!m_bQuitRx)
{
SleepTimerDelay::sleep(2);
if(i==0){
//qDebug() << "\nrx throw event - done 11 \n";
myUpdateEvent_rx = new UpdateEvent("first");
myUpdateEvent_rx->setvalue("first");
QCoreApplication::postEvent(m_pMainThreadObj->ptrmainwindow, myUpdateEvent_rx);
i++;
}else{
//qDebug() << "\nrx throw event - done 22 \n";
myUpdateEvent_rx = new UpdateEvent("second");
myUpdateEvent_rx->setvalue("second");
QCoreApplication::postEvent(m_pMainThreadObj->ptrmainwindow, myUpdateEvent_rx);
i=0;
}
}
qDebug() << "\nrx end \n";
}
Event handler :----
/*!
** Custom event handler
*/
void MainWindow::customEvent(QEvent *event)
{
qDebug() << "oo customEvent";
if (UpdateEvent::is(event)) {
UpdateEvent *tempUpdateEvent = static_cast<UpdateEvent *>(event);
qDebug() << tempUpdateEvent->value();
}
else if (ClearEvent::is(event)) {
ClearEvent *tempClearEvent = static_cast<ClearEvent *>(event);
qDebug() << tempClearEvent->value();
}
}
/*!
** event filter handler
*/
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
qDebug() << "oo eventFilter";
if (UpdateEvent::is(event)) {
UpdateEvent *tempUpdateEvent = static_cast<UpdateEvent *>(event);
qDebug() << tempUpdateEvent->value();
}
else if (ClearEvent::is(event)) {
ClearEvent *tempClearEvent = static_cast<ClearEvent *>(event);
qDebug() << tempClearEvent->value();
}
return true;
}
Related
I have looked at the 5 Qt testing examples including the one about GUI events, but these examples are way too simple.
I want to test my program by launching it, simulating some clicks, and checking the value of instance variables that have been changed by those clicks.
I assume that this test below is illogical: a.exec() blocks the thread until the program is closed, and when the program is closed w has been deleted I think (or will be deleted later?).
So how to write system/GUI tests?
My test:
void LaunchProgramTest::LaunchProgramTestFunction() {
QApplication a(argc, argv);
MainWindow *w = new MainWindow();
w->show();
a.exec();
int testResult = w->myTestFunction();
qDebug() << testResult; //Prints big numbers like "-17891602" or "1753770528" as if testResult was not initialized
QVERIFY2(testResult == 3, "Incorrectly changed");
}
In mainWindow.h I declared a variable:
int testValue;
Mainwindow.cpp is the class for the main GUI of the program. In the constructor I added
testValue = 2;
Then in a function that is executed upon events I wrote
void MainWindow::on_actionTest_clicked() {
testValue = 3;
}
enter code hereSo)) you need to add QTest, add .pro
QT += testlib
and
#include <QTest>
I will show an example of my implementation for MousePress, the rest you can do yourself))
struct EventMK
{
int type;
QString m_widPath;
int _timer;
int width;
int height;
QPoint p;
QPoint g;
int button;
int buttons;
int modifiers;
int _key;
QString text;
void print(){
qDebug()<<"{ \n"
<<"type "<< type<<","<<"\n"
<<"Widget_Path "<< m_widPath<<","<<"\n"
<<"Timer "<< _timer<<","<<"\n"
<<"Width "<< width<<","<<"\n"
<<"Height "<< height<<","<<"\n"
<<"Pos_x "<< p.x()<<","<<"\n"
<<"Pos_y "<< p.y()<<","<<"\n"
<<"Global_x "<< g.x()<<","<<"\n"
<<"Global_y "<< g.y()<<","<<"\n"
<<"Button "<< button<<","<<"\n"
<<"Buttons "<< buttons<<","<<"\n"
<<"Modifiers "<< modifiers<<","<<"\n"
<<"Key "<< _key<<","<<"\n"
<<"Text "<< text<<"\n"
<<"}\n";
}
};
QWidget * _getWidget(EventMK ev)
{
QString wname = ev.m_widPath;
QStringList wpath = wname.split ( "/" );
return QWidgetUtils::getAWidget(&wpath);
}
void _postExecution(EventMK ev, QWidget *widget)
{
if (widget){
//set focus
QWidgetUtils::setFocusOnWidget(widget);
//end simulation
widget->setUpdatesEnabled ( true );
widget->update();
}
}
QPoint adaptedPosition(EventMK ev, QWidget *w)
{
if (w == nullptr)
return QPoint(ev.p.x(), ev.p.y());
int orig_w = ev.width;
int orig_h = ev.height;
int curr_w = w->width();
int curr_h = w->height();
int new_x = ev.p.x() * curr_w / orig_w;
int new_y = ev.p.y() * curr_h / orig_h;
return QPoint(new_x, new_y);
}
and function implementation
void executeMousePressEvent(EventMK ev)
{
QWidget* widget = _getWidget(ev);
if ( widget == nullptr )
{
qDebug()<<"error: "<<__LINE__<<__FUNCTION__;
return;
}
// _preExecutionWithMouseMove(ev, widget);
if (widget){
QTest::mousePress ( widget, (Qt::MouseButton)ev.button ,
(Qt::KeyboardModifier) ev.modifiers,
adaptedPosition(ev,widget));
}
_postExecution(ev, widget);
}
now left to fill struct EventMK , you need to populate it from MouseButtonPress events.
Here is my example
bool eventFilter(QObject *obj, QEvent *event)
{
///
/// process control
///
//window events
if (event->type() == QEvent::KeyPress)
{
handleKeyPressEvent(obj, event);
}
//mouse events
else if (event->type() == QEvent::MouseButtonPress)
{
handleMousePressEvent(obj, event);
}
else if (event->type() == QEvent::MouseButtonRelease)
{
handleMouseReleaseEvent(obj, event);
}
else if (event->type() == QEvent::MouseButtonDblClick)
{
handleMouseDoubleEvent(obj, event);
}
else if (event->type() == QEvent::Wheel)
{
handleWheelEvent(obj, event);
}
//keyboard events
else if (event->type() == QEvent::Close)
{
handleCloseEvent(obj, event);
}
///the event should continue to reach its goal...
return false;
}
and
void handleMousePressEvent(QObject *obj, QEvent *event)
{
QWidget *widget = isValidWidget(obj);
if (!widget){
return;
}
QMouseEvent *me = dynamic_cast< QMouseEvent*> ( event );
//create the event
if (widget != nullptr){
EventMK evkm;
evkm.type = QOE_MOUSE_PRESS; // set your type
evkm._timer = _timer.restart(); // add your QElapsedTimer
evkm.m_widPath = QWidgetUtils::getWidgetPath(widget);
evkm. width = widget->width();
evkm. height = widget->height();
QPoint p ( me->pos() );
QPoint g = widget->mapToGlobal ( p );
evkm. p = p;
evkm. g = g;
evkm. button = me->button();
evkm. buttons = me->buttons();
evkm. modifiers = me->modifiers();
evkm.print();
}
//send event if EventMK is valid
}
so, it turns out we can write a scenario and run what you wanted, thanks
If I call removeRows on records which were read from the database a ! will be displayed in the first column of the tableView.
The only thing which I would like to achieve is that this row will not be displayed in the view. I tried it with QSortFilterProxyModel but I don't know where I can get the flag which is used to display the ! in the first column. Is there a way to set a filter in QSortFilterProxyModel that it only contains the rows which don't have this flag?
From where does the view take the information, that the removed row is marked with a "!" ? This information might be hidden somewhere in the model, but I cannot find out where.
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
m_ui(new Ui::MainWindow),
m_model(new QSqlTableModel(this)),
m_proxyModel(new QSortFilterProxyModel(this))
{
m_ui->setupUi(this);
m_model->setTable("test");
m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
m_model->select();
m_proxyModel->setSourceModel(m_model);
m_ui->tableView->setModel(m_proxyModel);
qDebug() << "Select : Row count:" << m_model->rowCount();
connect(m_ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &MainWindow::on_selectionChanged);
}
MainWindow::~MainWindow()
{
delete m_ui;
}
void MainWindow::on_pushButtonNewRecord_clicked()
{
qDebug() << "New Record";
m_record = m_model->record();
m_record.setValue("firstname", "john");
m_record.setValue("lastname", "doe");
m_record.setValue("email", "john.doe#email.com");
m_model->insertRecord(-1, m_record);
qDebug() << "New Record : Row count:" << m_model->rowCount();
}
void MainWindow::on_pushButtonRemoveRow_clicked()
{
qDebug() << "Remove Row";
if (m_row >= 0) {
m_proxyModel->removeRow(m_row);
qDebug() << "Remove Record: Row count:" << m_model->rowCount();
}
for (int i = 0; i < m_model->rowCount(); i++) {
qDebug() << "\n";
qDebug() << "Remove Row: index :" << m_model->index(i, 0);
qDebug() << "Remove Row: isValid:" << m_model->index(i, 0).isValid();
qDebug() << "Remove Row: isDirty:" << m_model->isDirty(m_model->index(i, 0));
qDebug() << "Remove Row: flags :" << m_model->index(i, 0).flags();
qDebug() << "Remove Row: data :" << m_model->index(i, 0).data(Qt::DisplayRole);
qDebug() << "Remove Row: heaader:" << m_model->headerData(i, Qt::Vertical);
QVariant verticalHeader = m_model->headerData(i, Qt::Vertical);
if (verticalHeader == "!") {
qDebug() << "Deleted";
}
//qDebug() << m_model->record(i);
}
}
void MainWindow::on_pushButtonSubmit_clicked()
{
qDebug() << "Submit";
m_model->submitAll();
m_model->select();
}
void MainWindow::on_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
Q_UNUSED(deselected)
if (!selected.isEmpty()) {
m_row = selected.indexes().first().row();
}
}
You have to implement a QSortFilterProxyModel that filters the rows that are Dirty and whose vertical header text is "!", You must also call the invalidate() method to force the application of the filter.
dirtyfilterproxymodel.h
#ifndef DIRTYFILTERPROXYMODEL_H
#define DIRTYFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <QSqlTableModel>
class DirtyFilterProxyModel : public QSortFilterProxyModel
{
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if(QSqlTableModel *source_model = qobject_cast<QSqlTableModel *>(sourceModel())){
QModelIndex ix = source_model->index(source_row, 0, source_parent);
QString row_header_item = source_model->headerData(source_row, Qt::Vertical, Qt::DisplayRole).toString();
return !(source_model->isDirty(ix) && row_header_item == QLatin1String("!"));
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
};
#endif // DIRTYFILTERPROXYMODEL_H
mainwindow.h
// ...
class DirtyFilterProxyModel;
// ...
class MainWindow : public QMainWindow
{
// ...
private:
Ui::MainWindow *m_ui;
DirtyFilterProxyModel *m_proxyModel;
// ...
mainwindow.cpp
#include "dirtyfilterproxymodel.h"
// ...
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
m_ui(new Ui::MainWindow),
m_model(new QSqlTableModel(this)),
m_proxyModel(new DirtyFilterProxyModel(this))
{
// ...
}
void MainWindow::on_pushButtonNewRecord_clicked()
{
// ...
m_model->insertRecord(-1, m_record);
m_proxyModel->invalidate();
}
// ...
void MainWindow::on_pushButtonRemoveRow_clicked()
{ if (m_row >= 0) {
m_proxyModel->removeRow(m_row);
m_proxyModel->invalidate();
}
}
I'm trying to make client and server using QTcpSocket and QTcpServer.
So, what happens to server.
I run the server, it starts listening (successfully [checked by myself])
I run client, enter 127.0.0.1 for IP address and 30000 for port
Client says that connection estabilished
Server doesn't do anything, just keep waiting
Parts of my program:
//server-work.h
#ifndef SERVERWORK_H
#define SERVERWORK_H
#include <QtCore>
#include <QSqlError>
#include <QDebug>
#include <QSqlQuery>
#include <unistd.h>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtSql/QSqlDatabase>
#include "lssclient.h"
class LSSClient;
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
class LTWorkWithClients : public QThread
{
//Q_OBJECT
public:
LTcpServer* server;
LTWorkWithClients(QObject* parent = 0, LTcpServer *server = 0):
QThread(parent)
{
this->server = server;
}
protected:
void run() {
qDebug() << "started";
server->workWithIncomingConnection();
}
};
QSqlDatabase db; // clients in database
LTWorkWithClients* t_workWithClients;
QQueue<quintptr> clientsToBeAttached;
QList<LSSClient*> clients;
LResult workWithIncomingConnection ();
LResult serverInit ();
LResult createDatabase ();
static QTextStream& qStdout ();
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
protected:
private:
};
#endif // SERVERWORK_H
I know that this nested thread class is strongly wrong way to do this thing, but i don't have much time to do it correctly
// server-work.cpp [PART]
LResult LTcpServer::serverInit()
{
checkError;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("serverDB");
if (!db.open()) {
qDebug() << "Error opening database...";
qDebug() << db.lastError().text();
return LVError;
} else {
qDebug() << "Database successfully opened";
}
if(!this->listen(QHostAddress::Any, 30000)){
qDebug() << "Error starting listening...";
return LVError;
} else {
qDebug() << "Start listening successfully";
}
t_workWithClients = new LTWorkWithClients(this, this);
t_workWithClients->start();
return LVSuccess;
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << Q_FUNC_INFO << " new connection";
clientsToBeAttached.enqueue(socketDescriptor);
qDebug() << "here1";
}
LResult LTcpServer::workWithIncomingConnection()
{
bool toExit = false;
while (!toExit) {
checkError;
qDebug() << "1";
if (clientsToBeAttached.length() != 0) {
quintptr eachClientDescriptor = clientsToBeAttached.dequeue();
qDebug() << "2";
LSSClient* client = new LSSClient(this);
client->server = this;
client->socket->setSocketDescriptor(eachClientDescriptor);
qDebug() << "3";
client->registered = false;
client->server = this;
qDebug() << client->socket->localAddress();
connect(client->socket, SIGNAL(readyRead()), client, SLOT(onSokReadyRead()));
connect(client->socket, SIGNAL(connected()), client, SLOT(onSokConnected()));
connect(client->socket, SIGNAL(disconnected()), client, SLOT(onSokDisconnected()));
connect(client->socket, SIGNAL(error(QAbstractSocket::SocketError)),client, SLOT(onSokDisplayError(QAbstractSocket::SocketError)));
clients.append(client);
}
usleep(1000000);
}
return LVSuccess;
}
So, server just keep writing 1 (nothing more) every second, but client says that it is connected to the server.
This structure might help...
in your ltcpserver.h file:
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit LTcpServer(QObject * parent = 0);
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
private:
QThread *myThread;
};
and in your ltcpserver.cpp:
LTcpServer::LTcpServer(QObject * parent) : QTcpServer(parent)
{
if(this->listen(QHostAddress::Any,30000))
{
qDebug() << "server started...";
}
else
{
qDebug() << "server could not be started...";
}
myThread = new QThread();
myThread->start();
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
LSSClient * yourClient = new LSSClient(socketDescriptor);
yourClient->moveToThread(myThread);
clients->append(yourClient);
}
and in your lssclient.h
class LSSClient: public QObject
{
Q_OBJECT
public:
explicit LSSClient(qintptr socketDescriptor,QObject * parent = 0);
private:
void setupSocket(qintptr socketDescriptor);
QTcpSocket * socket;
public slots:
void readyRead();
void disconnected();
};
and in your lssclient.cpp
LSSClient::LSSClient(qintptr socketDescriptor,QObject * parent) : QObject(parent)
{
setupSocket(qintptr socketDescriptor);
}
void LSSClient::setupSocket(qintptr socketDescriptor)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(sDescriptor);
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
}
void LSSClient::readyRead()
{
// do whatever you want here with incoming data
}
void LSSClient::disconnected()
{
// do what happens to client when disconnected
}
I wanna make a simple Qt app which can perform task like image below:
I have learnt Fortune Server examples and actually I want this app is just like the combination of Fortune Server and Fortune Client.
dialog.cpp
void Dialog::on_btnListen_clicked(bool checked)
{
if(checked)
{
listener = new ServerSock(this);
if(!listener->listen(QHostAddress::LocalHost,ui->boxPort->value()))
{
QMessageBox::critical(this,tr("Error"),tr("Cannot listen: %1").arg(listener->errorString()));
ui->btnListen->setChecked(false);
return;
}
else
{
qDebug() << "Server is listening to port" << listener->serverPort();
ui->btnListen->setText(tr("Listening"));
this->setWindowTitle(tr("Listening and Running"));
}
}
else
{
listener->close();
listener->deleteLater();
ui->tmbListen->setText(tr("Listen again"));
this->setWindowTitle(tr("Taking a rest"));
}
}
serversock.cpp:
#include "serversock.h"
ServerSock::ServerSock(QObject *parent) :
QTcpServer(parent)
{
}
void ServerSock::incomingConnection(int descriptor)
{
thread = new Threading(descriptor,this);
connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
thread->start();
}
threading.cpp:
#include "threading.h"
Threading::Threading(int descriptor, QObject *parent) :
QThread(parent)
{
this->descriptorSocket = descriptor;
}
void Threading::run()
{
qDebug() << "Thread is started...";
socketThread = new QTcpSocket();
if(!socketThread->setSocketDescriptor(this->descriptorSocket))
{
emit error(socketThread->error());
return;
}
connect(socketThread,SIGNAL(readyRead()),this,SLOT(readyToRead()),Qt::DirectConnection);
connect(socketThread,SIGNAL(disconnected()),this,SLOT(unconnected()),Qt::DirectConnection);
qDebug() << descriptorSocket << "Connected";
exec(); //loop
}
void Threading::readyToRead()
{
QByteArray data = socketThread->readAll();
socketOut = new QTcpSocket();
socketOut->connectToHost("192.168.0.1",8080);
if(socketOut->waitForConnected(5000))
{
QByteArray query("GET http:// mysite. com/page HTTP/1.1\r\nHost: anothersite.com\r\r\r\n" + data); //example
socketOut->write(query);
socketOut->write("\r\r\r\n");
socketOut->waitForBytesWritten(1000);
socketOut->waitForReadyRead(3000);
outPut = socketOut->readAll();
if(socketOut->error() != socketOut->UnknownSocketError)
{
qDebug() << socketOut->errorString();
socketOut->disconnectFromHost();
this->quit();
socketThread->abort();
}
else
{
socketOut->close();
}
}
else
{
qDebug() << "Cannot connected";
}
if(!outPut.isNull())
socketThread->write(outPut);
qDebug() << descriptorSocket << " Data in: " << data;
void Threading::unconnected()
{
qDebug() << "Disconnected";
socketThread->abort();
exit(0);
deleteLater();
}
The problem is that I don't know how to return data from remote host to the local client, like the image below:
it sends request, but there is no response. How to accomplish this?
I do not know what the heck is wrong with my code that it never Dequeus the queue, instead isEmpty always meets true.
class ConcurrentQueue
{
private:
QQueue<QByteArray> dataStore;
public:
void Enqueue(QByteArray value);
QByteArray Dequeue();
bool isEmpty();
private:
QMutex mutex;
};
void ConcurrentQueue::Enqueue(QByteArray value)
{
qDebug() << dataStore.length();
mutex.lock();
dataStore.enqueue(value);
mutex.unlock();
qDebug() << dataStore.length();
}
QByteArray ConcurrentQueue::Dequeue()
{
// mutex.lock();
// return dataStore.dequeue();
// mutex.unlock();
QByteArray tmp;
mutex.lock();
if(!dataStore.isEmpty())
{
tmp = dataStore.dequeue();
}
mutex.unlock();
return tmp;
}
bool ConcurrentQueue::isEmpty()
{
return dataStore.isEmpty();
}
next a timer is connected to a slot to Enqueu a packet every lt's say 10 milliseconds:
QByteArray built((char*)data, len) ;
//qDebug() << built.toHex();
qDebug() << "EnQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ";
queue.Enqueue(built);
A thread regularly checks if this queue is not empty it dequeues the queue and does something, but isEmplty always returns true
if(queue.isEmpty())
{
qDebug() << "#####################################";
return;
}
//NEVER COMES HERE
QByteArray rd15Bytes = queue.Dequeue();
here's the thread:
Write::Write()
{
}
void Write::run(){
while(1)
{
rs.writeToSerialPort(); // in this function above always isemplty is true
this->msleep(10);
}
}