I'm quite new to Qt, but I got into it to start experimenting with making 2D games. I've got a extremely rough and simple game started, but I have an issue. Whenever the health gets to 0, the game doesn't end. I just want to know how to end the game and where to put this exit command before making a "Game Over" screen. My code is below, and from what I can grasp, I assume the QApplication::quit() goes in the Game.cpp file. Doing this by taking the health integer from Health.cpp and Health.h and putting it in Game.cpp. Any help is appreciated. Here is the code I feel the answers lie in, if more info is needed, ask.
Game.h
#ifndef GAME_H
#define GAME_H
#include <QGraphicsView>
#include <QWidget>
#include <QGraphicsScene>
#include "Player.h"
#include "Score.h"
#include "Health.h"
#include "Level.h"
#include "Main.h"
class Game: public QGraphicsView{
public:
Game(QWidget * parent=0);
QGraphicsScene * scene;
Player * player;
Score * score;
Health * health;
Level * level;
Main * close;
int end();
};
#endif // GAME_H
Game.cpp
#include "Game.h"
#include <QTimer>
#include <QGraphicsTextItem>
#include <QFont>
#include "Enemy.h"
#include <QMediaPlayer>
#include <QBrush>
#include <QImage>
#include <QApplication>
Game::Game(QWidget *parent){
// create the scene
scene = new QGraphicsScene();
scene->setSceneRect(0,0,800,600); // make the scene 800x600 instead of infinity by infinity (default)
setBackgroundBrush(QBrush(QImage(":/images/bg.png")));
// make the newly created scene the scene to visualize (since Game is a QGraphicsView Widget,
// it can be used to visualize scenes)
setScene(scene);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFixedSize(800,600);
// create the player
player = new Player();
player->setPos(400,500); // TODO generalize to always be in the middle bottom of screen
// make the player focusable and set it to be the current focus
player->setFlag(QGraphicsItem::ItemIsFocusable);
player->setFocus();
// add the player to the scene
scene->addItem(player);
// create the score/health
score = new Score();
scene->addItem(score);
health = new Health();
health->setPos(health->x(),health->y()+25);
scene->addItem(health);
level = new Level();
scene->addItem(level);Bull
level->setPos(level->x(),level->y()+50);
// spawn enemies
QTimer * timer = new QTimer();
QObject::connect(timer,SIGNAL(timeout()),player,SLOT(spawn()));
timer->start(2000);
// play background music
QMediaPlayer * music = new QMediaPlayer();
music->setMedia(QUrl("qrc:/sounds/bgsound.mp3"));
music->play();
show();
}
int Game::end(){
if (health == 0){
QApplication::quit();
}
return 0;
}
Health.h
#ifndef HEALTH_H
#define HEALTH_H
#include <QGraphicsTextItem>
class Health: public QGraphicsTextItem{
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
private:
int health;
};
#endif // HEALTH_H
Health.cpp
#include "Health.h"
#include <QFont>
#include <QApplication>
Health::Health(QGraphicsItem *parent): QGraphicsTextItem(parent){
// initialize the score to 0
health = 3;
// draw the text
setPlainText(QString("Health: ") + QString::number(health)); // Health: 3
setDefaultTextColor(Qt::red);
setFont(QFont("times",16));
}
void Health::decrease(){
health--;
setPlainText(QString("Health: ") + QString::number(health)); // Health: 2
}
int Health::getHealth(){
return health;
}
main.cpp
#include <QApplication>
#include "Game.h"
#include "Main.h"
Game * game;
int main(int argc, char *argv[]){
QApplication a(argc, argv);
game = new Game();
game->show();
return a.exec();
}
Your end() function is never called.
The best way to achieve what you want to is to use Qt's signal/slot mechanism. It amkes it easy to connect an event (signal) to an action (slot):
Add Q_OBJECT macro to Health and Game classes and make sure your compilation environment moc's the two header files
Declare in Health a signal named dead()
Emit the signal from Health::decrease()
Make Game::end() be a slot and be void
Connect Health::dead() to Game::end()
Then, Game::end() will be called as soon as Health reaches zero.
class Health: public QGraphicsTextItem
{
Q_OBJECT
public:
Health(QGraphicsItem * parent=0);
void decrease();
int getHealth();
signals:
void dead();
private:
int health;
};
...
class Game: public QGraphicsView{
Q_OBJECT
public:
...
public slots:
void end();
};
...
void Health::decrease(){
health--;
setPlainText(QString("Health: ") + QString::number(health));
if ( health == 0 )
emit dead();
}
...
Game::Game(QWidget *parent){
...
connect( health, SIGNAL(dead()), this, SLOT(end()) );
}
...
void Game::end(){
// no need to test health anymore, as signal is emited when health is zero
// do some extra stuff before exiting
QApplication::quit();
}
If end() only calls QApplication::quit(), you can remove it and diectly connect the signal to QApplication::quit(), like that:
connect( health, SIGNAL(dead()), qApp, SLOT(quit()) );
Also note that you were testing health == 0 in Game::end(), but health is a pointer, and, looking at your code, it will never be 0 (you maybe meant to write if ( health->getHealth() == 0 ).
In Health::decrease emit a signal or put the logic for it in where the "player is shot" area. But to do that, you to Health or the class with the logic to be a QObject so that it gets the signals and slots in the header. EDIT QGraphicsTextItem is already a QObject. See comments.
Connect the signal to the view's close() right after the Health class or Player class is instantiated.
http://doc.qt.io/qt-5/signalsandslots.html
Hope that helps.
Related
=====================OUTDATE=======================
I have a vector which contains threads, each thread is doing a while loop, for some reason, i need to delete the thread in the vector, to do this, i referenced this blog and write a test demo online. But when i write pthread_cancel() in Qt, it reports error: use of undeclared identifier 'pthread_cancel'. I have added LIBS += -lpthread in my .pro file and added #include <thread> in my .cpp file, this error still exists.
=====================UPDATE=====================
Afterwards, i trid to use QThread to achieve my goal. In brief, to start a qthread, i create a Worker class, then instantiate it and move it to QThread, connect &QThread::started with &Worker::process, process is the time consuming method, finnaly call thread->start();; to stop a qthread, i use a bool flag, and i store it with thread id in QMap, if the bool flag is set to false, qthread will break while loop, and emit a finished() signal and this signal will trigger &QThread::quit; to delete the qthread, i connect finished() signal with &Worker::deleteLater and &QThread::deleteLater.
The code are:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"
#include <QThread>
#include <QMap>
#include <QDebug>
QMap<int, bool> stateController;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
qDebug()<<"Main UI thread id is"<<(int)QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_add_clicked()
{
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//hold a place for blank item, in order to uniformly determine whether its text is empty afterwards
QTableWidgetItem *ckx = new QTableWidgetItem;
ckx->setCheckState(Qt::Unchecked);
ui->tableWidget->setItem(row,1,ckx);
}
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
if(column == 1){
bool state = ui->tableWidget->item(row,1)->checkState();
if(state){
if(ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is not thread id, then create the thread
QThread* thread = new QThread();
qDebug()<<"New created thread id is"<<(int)thread->currentThreadId(); //I found this thread id will equal to main ui thread id, so i use a sigal/slot to update thread id
Worker* worker = new Worker(row);
worker->moveToThread(thread);
connect( worker, &Worker::updateQThreadIDSignal, this, &MainWindow::updateQThreadID);
connect( thread, &QThread::started, worker, &Worker::process);
connect( worker, &Worker::finished, thread, &QThread::quit);
// automatically delete thread and worker object when work is done:
connect( worker, &Worker::finished, worker, &Worker::deleteLater);
connect( thread, &QThread::finished, thread, &QThread::deleteLater);
//start the thread
thread->start();
}
}else{
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is already the thread, then stop it
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
// qDebug()<<"get thread id is"<<thread_id;
QMutexLocker locker(&mx);
stateController[thread_id] = false;
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//Because thread will be delete later, so clear its thread id
}
}
}
}
void MainWindow::on_pushButton_delete_clicked()
{
QItemSelectionModel* selectionModel = ui->tableWidget->selectionModel();
QModelIndex index = selectionModel->currentIndex();
if(index.isValid()){
int row = index.row();
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//Before stop the thread, ensure it exist
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
if(ui->tableWidget->item(row,1)->checkState() == Qt::Checked){
//If not stopped yet, firstly stop it
QMutexLocker locker(&mx);
stateController[thread_id] = false;
}
stateController.remove(thread_id);
}
ui->tableWidget->removeRow(row);
}
}
void MainWindow::updateQThreadID(int row, QString id)
{
ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id.toInt())));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMutex>
#include <vector>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_add_clicked();
void on_tableWidget_cellClicked(int row, int column);
void on_pushButton_delete_clicked();
public slots:
void updateQThreadID(int row, QString id);
private:
Ui::MainWindow *ui;
QMutex mx;
};
#endif // MAINWINDOW_H
worker.cpp
#include "worker.h"
#include <QThread>
#include <QDebug>
#include <QMutexLocker>
extern QMap<int, bool> stateController;
Worker::Worker(int row) : row_index(row) {
qDebug()<<"Create new worker at thread "<<(int)QThread::currentThreadId();
}
Worker::~Worker() {
qDebug()<<"Destroy the worker instance";
}
void Worker::process() {
thread_id = (int)QThread::currentThreadId();
stateController.insert(thread_id, true);
// qDebug()<<"set thread id is"<<thread_id;
emit updateQThreadIDSignal(row_index,QString("%1").arg(thread_id)); //execute once, because if delete row happen, the row index will change
while(true)
{
count++;
QThread::sleep(2);//simulate time consuming operations
qDebug()<<thread_id<<"processing"<<count;
{//life scope of locker
QMutexLocker locker(&mx);
if(!stateController[thread_id])//In every loop, determine whether it can run, if not, exit the loop
{
return;
}
}
}
emit finished();
}
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject {
Q_OBJECT
public:
Worker(int row);
~Worker();
public slots:
void process();
signals:
void finished();
void updateQThreadIDSignal(int, QString);
private:
int thread_id;
int row_index;
QMutex mx;
int count = 0;
};
#endif // WORKER_H
To watch the demo video, click here.
If you have any advice, please let me know, thanks !
Even though the codes seems to work fine, but i still have a question : Why i wrote &Worker::deleteLater, but I never see the destructor of Worker is called ?
I'm building up an application, which receives data over the serial interface. So i implemented a class for the serial handling, which can successfully receive and send data. Now I try to move the data to the UI, to give it out to a console, but I need a thread for that and it seems more difficult than I expected.
So somehow I need to define a thread and start it at the beginning of the UserInterface creation and this thread should then poll a function for new data. I researched about creating a thread and connect it to a callback function, but it is always related to create a class, that inherits from QThread, which I cannot do for the Main UI.
How should I define a thread inside the Main UI, which I can use then to poll a function?
Edit: As recommended, a thread is not necessary here, but I don't know how to call a function inside a class without an object. In the mainWindow class, where all the UI stuff like labels and buttons sits, I created an object for serial communication. Inside this object, an interrupt is called, when new data is received. So I can for example queue this data inside this serial object, but still i need somehow to forward them.
Edit2: A first method that actually works was to implement a timer, which periodically calls an update function. But since the serial rx is interrupt driven, there must be a way for callback, such that I don't need to poll it.
As discussed in the comments, in this use-case it's preferable to not use threading, but exploit the Qt event loop and signal-slot mechanism. Here is the skeleton of the MainWindow and the SerialReciver classes, and how they are wired together in main.cpp. For simplicity, the SerialReceiver class just emits the signal every second with the current time, which will be appended to the editfield's content in the main window.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPlainTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void onSerialMessage(const QString &msg);
private:
QPlainTextEdit mTextField;
};
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
mTextField.setReadOnly(true);
setCentralWidget(&mTextField);
}
MainWindow::~MainWindow()
{
}
void
MainWindow::onSerialMessage(const QString &msg)
{
mTextField.appendPlainText(msg);
}
#endif // MAINWINDOW_H
serialreceiver.h:
#ifndef SERIALRECEIVER_H
#define SERIALRECEIVER_H
#include <QObject>
#include <QTimer>
class SerialReceiver : public QObject
{
Q_OBJECT
public:
explicit SerialReceiver(QObject *parent = nullptr);
signals:
void newMsg(const QString &msg);
public slots:
void onSerialReceived();
private:
QTimer mTimer;
};
#endif // SERIALRECEIVER_H
serialreceiver.cpp:
#include "serialreceiver.h"
#include <QDateTime>
SerialReceiver::SerialReceiver(QObject *parent) : QObject(parent)
{
mTimer.setInterval(1000);
mTimer.setSingleShot(false);
connect(&mTimer, &QTimer::timeout,this,&SerialReceiver::onSerialReceived);
mTimer.start();
}
void
SerialReceiver::onSerialReceived()
{
QDateTime now = QDateTime::currentDateTime();
emit newMsg(now.toString());
}
and main.cpp:
#include "mainwindow.h"
#include "serialreceiver.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SerialReceiver receiver;
MainWindow w;
QObject::connect(&receiver, &SerialReceiver::newMsg,
&w,&MainWindow::onSerialMessage);
w.show();
return a.exec();
}
I have a qt thread in my application which emits a Mat type image so that other threads can use it. the image is coming from camera by using VideoCapture Object of opencv library. now what i intend to do is getting this image from a rostopic, not from camera directly. in order to do that i must create a ros node in my thread and here i am stuck. is there anyone who has the experience to integrate ros node and qt?
here is my thread:
#include "../include/Ground_Station/camera.h"
#include <iostream>
using namespace std;
Camera::Camera()
{
}
void Camera::run()
{
VideoCapture cap;
cap.open(0);
while(1){
Mat image;
cap >> image;
cvtColor(image,image,CV_BGR2RGB);
emit ImgSignal(&image);
QThread::msleep(30);
}
}
and Camera.h:
#ifndef CAMERA_H
#define CAMERA_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <ros/ros.h>
#include <opencv2/opencv.hpp>
using namespace cv;
class Camera: public QThread
{
Q_OBJECT
public:
Camera();
void run();
bool Stop = false;
signals:
void ImgSignal(Mat*);
private:
public slots:
};
#endif // THREAD_H
Basically, your executable file containing the main() function must be your ros node and your QT application at the same time. In your "main.cpp"
you call ros::init(...) and subscribe to the topic you want to listen to. Your subscriber callback function may convert the ros image to Mat and emmit an ImgSignal every time it is called. To do all that, I'd create a RosImageProvider class, something along the lines ..
class RosImageProvider: public QObject
{
Q_OBJECT
public:
void ImageSubscriberCallback(const sensor_msgs::Image::ConstPtr& img);
...
signals:
void ImgSignal(Mat*);
};
I encountred the same problem when dealing with TCP/IP connection from a ROS node within Qt and my solution was to inherit directly from the QThread object, thus when initializing the class, you initialize the ROS node and implement the work TODO in callbacks and the thread run() function.
So finally, my code looked something like this :
#ifndef INCLUDE_TCPHANDLER_HPP_
#define INCLUDE_TCPHANDLER_HPP_
#include <ros/ros.h>
#include <QThread>
#include <string>
class TCP_Handler : public QThread
{
Q_OBJECT
private:
int init_argc;
char** init_argv;
ros::Publisher cmd_control_publisher;
ros::Subscriber feedback_subscriber;
public:
TCP_Handler()
{}
virtual ~TCP_Handler(){}
/**
* #brief ROS methods
*
*/
inline bool init_ros()
{
int argc =0; char** argv = new char*();
ros::init(argc,argv,"tcp_handler");
ros::NodeHandle n;
cmd_control_publisher = n.advertise<robot_common::cmd_control>("cmd_control", 1000);
feedback_subscriber = n.subscribe<robot_common::feedback>("wifibot_pose", 4, &TCP_Handler::FeedbackCallback , this);
return true;
}
void FeedbackCallback(const robot_common::feedback::ConstPtr& pose)
{
//.....
}
/**
* #brief Threading methods
*
*/
virtual void init(int, std::string ip_addr = "127.0.0.1") = 0;
virtual void run() = 0;
virtual void stop() = 0;
/**
* #brief TCP methods (Server/Client have to implement these folks)
*
*/
virtual bool Send_data(char* data, int size) = 0;
virtual int Receive_data(char* in_data, int size) = 0;
virtual bool Open_connection() = 0;
virtual void Close_connection() = 0;
};
#endif /* INCLUDE_TCPHANDLER_HPP_ */
This code is just a template of a Qt-threaded-ROS node for TCP connction as I don't know your specific needs. feel free to build your own !
Cheers,
I want a small program doing the following:
start a single-shot QTimer
when it times out, a QMessageBox is shown
if button "Continue" is clicked, the box is closed and the timer restarted
if button "Stop" is clicked, the box is closed and the application exited
The problem I have is that the event loop is left as soon as I hide the message box. The box is displayed only once. I reproduced my program in a console version and it runs as expected. Here is my code. Thanks in advance for your help.
main.c
#include <QtGui/QApplication>
#include "TimedDialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TimedDialog dialog(&app, SLOT(quit()));
dialog.run();
return app.exec();
}
TimedDialog.h
#ifndef TIMED_DIALOG_H
#define TIMED_DIALOG_H
#include <QObject>
#include <QTimer>
class QMessageBox;
class QPushButton;
class QAbstractButton;
class TimedDialog : public QObject
{
Q_OBJECT
public:
TimedDialog(
QObject const * receiver,
char const * method);
~TimedDialog();
void run(void);
signals:
void stop(void);
private:
QMessageBox* _box;
QPushButton* _buttonContinue;
QPushButton* _buttonStop;
QTimer _timer;
static int const DELAY = 2 * 1000; // [ms]
private slots:
void onTimeout(void);
void onButtonClicked(QAbstractButton * button);
};
#endif
TimedDialog.cpp
#include <assert.h>
#include <QMessageBox>
#include <QPushButton>
#include "TimedDialog.h"
TimedDialog::TimedDialog(
QObject const * receiver,
char const * method)
: QObject(),
_box(0),
_buttonContinue(0),
_buttonStop(0),
_timer()
{
_box = new QMessageBox();
_box->setWindowModality(Qt::NonModal);
_box->setText("Here is my message!");
_buttonContinue = new QPushButton("Continue");
_box->addButton(_buttonContinue, QMessageBox::AcceptRole);
_buttonStop = new QPushButton("Stop");
_box->addButton(_buttonStop, QMessageBox::RejectRole);
_timer.setSingleShot(true);
assert(connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimeout())));
assert(connect(_box, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(onButtonClicked(QAbstractButton *))));
assert(connect(this, SIGNAL(stop()), receiver, method));
}
TimedDialog::~TimedDialog()
{
delete _box;
}
void TimedDialog::onTimeout(void)
{
_box->show();
}
void TimedDialog::onButtonClicked(QAbstractButton * button)
{
_box->hide();
if (button == _buttonContinue)
{
_timer.start(DELAY);
}
else
{
emit stop();
}
}
void TimedDialog::run(void)
{
_timer.start(DELAY);
}
The created timer is being set as singleshot, which has already called timeout.
If you look at QTimer source code for the call to start() you can see it states: -
If singleShot is true, the timer will be activated only once.
You could fix and simplify the code with the class function QTimer::singleShot
I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?
The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...