how to force Qt mainWindow to wait for some changes - c++

I am designing UI for my opencv application and I'm new in Qt.
I have a QString in my Qt code that is a licence plate. and it can be change when a car arrive to our camera, but we don't know when it change.
and when car arrive we need to show it's plate on a QTableView on MainWindow.
how can I handle it in Qt?
I make my code simple here:
mainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
.
.
.
public slots:
void set_plate(QString p);
signals:
void plate_changed(QString newPlate);
private:
Ui::MainWindow *ui;
QString plate;
};
mainWindow.cpp
void MainWindow::set_plate(QString newPlate)
{
if(plate != newPlate){
plate = newPlate;
emit plate_changed(newPlate);
}
}
MainWindow::MainWindow(QString p, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
plate(p)
{
.
.
.
QTableWidgetItem* item2;
item2 = new QTableWidgetItem(plate);
ui->table->setItem(table->rowCount() - 1, 0, item2);
}
main.cpp
int main(int argc, char *argv[])
{
QString plate;
.
.
.
//some changes on plate
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
return a.exec();
}
thanks

When you detect a car, send a signal to your instance. Connect your emitted signal to your slot and that's all.
https://wiki.qt.io/Qt_for_Beginners#Creating_custom_signals_and_slots

Let's begin with a paraphrase of the code for main that you've posted
void someChangesOnPlate(QString &);
int main(int argc, char *argv[])
{
QString plate;
someChangesOnPlate(plate);
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
return a.exec();
}
It seems that someChangesOnPlate would be a plate detection code that runs continuously in a loop, taking images from the camera, detecting plates, and extracting the plate numbers.
The main mistake in your approach is: while the plate detection code is running, the application window isn't shown yet - the code after someChangesOnPlate hasn't executed yet! The execution is within someChangesOnPlate, after all.
What you need to do, instead, is to run someChangesOnPlate in a separate thread, and to have that thread invoke the main window's newPlate method in a thread-safe fashion. Given C++11, this is a very straightforward change:
void someChangesOnPlate(MainWindow *);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
std::thread thread(someChangesOnPlate, &w);
int rc = a.exec();
thread.join(); // wait for the thread to finish
return rc;
}
Within the someChangesOnPlate code, the thread-safe call to newPlate is done as follows:
void someChangesOnPlate(MainWindow * w) {
while (...) {
// process camera images
...
QString plate = ....;
...
QMetaObject::invoke(w, "newPlate", Qt::QueuedConnection, Q_ARG(QString, plate));
...
}
}
Finally, I understand that you want a new item to be added to the table whenever a new plate is indicated. Here's how to do it:
class MainWindow : public QMainWindow {
Q_OBJECT
Ui::MainWindow ui; // no need for it to be a pointer
QString m_lastPlate;
public:
MainWindow(QWidget * parent = 0) : QMainWindow(parent) {
ui.setupUi(this);
}
Q_SLOT void newPlate(const QString & plate) {
if (plate == m_lastPlate) return;
m_lastPlate = plate;
auto item = new QTableWidgetItem(plate);
ui->table->setItem(table->rowCount() - 1, 0, item);
}
}

Related

Can't output to QTextEdit

My program should:
collect some input from QLineEdits;
convert it into QStrings;
add it to some QStrings which are constant;
output the whole stuff in a QTextEdit when a button is clicked.
Below is the simplified model of the program. It can be compiled; I get no errors; however, it doesn't do what I need. It just fails to output and I have really no idea why. I've struggled too hard to get it show no errors and now I've run out of ideas. Can anybody help me please?
#include <QtGui>
#include <QtCore>
class MyObject : public QObject
{
Q_OBJECT
public:
QTextEdit text;
QString c;
public slots:
void onClicked() {
text.setText(c);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget mw;
mw.setWindowTitle("Main Window");
mw.resize(400, 400);
mw.show();
QLabel label ("Enter something:", &mw);
label.setAlignment(Qt::AlignHCenter);
label.show();
QLineEdit line (&mw);
line.show();
QString a = line.text();
QString b = "This line is to be added";
QString c = a+b;
QTextEdit text (&mw);
text.show();
QPushButton btn ("Convert", &mw);
MyObject obj;
QObject::connect(
&btn,
SIGNAL(clicked()),
&obj,
SLOT(onClicked()));
btn.show();
QVBoxLayout layout_mw;
layout_mw.addWidget(&label);
layout_mw.addWidget(&line);
layout_mw.addWidget(&btn);
layout_mw.addWidget(&text);
mw.setLayout(&layout_mw);
return app.exec();
}
#include "sample.moc"
According to the code you provide it seems that you do not know that:
Qt works asynchronously, for example the value of a that you get is before the window is displayed, what value will it have? Well, it will have an empty string, so at what moment should I ask for the text? right in the slot that is called when the button is pressed.
Variables with the same name do not imply that they are the same, for example you have 2 QTextEdit with the name of text, these are different objects.
So as you realize the objects (widgets) must have the same scope to be able to interact with each other, so I will create a class that inherits from QWidget and that has the other elements as attributes.
#include <QtGui>
#include <QtCore>
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent=nullptr):
QWidget(parent)
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(&label);
layout->addWidget(&line);
layout->addWidget(&button);
layout->addWidget(&textedit);
label.setText("Enter something:");
label.setAlignment(Qt::AlignHCenter);
button.setText("Convert");
connect(&button, SIGNAL(clicked()), this, SLOT(onClicked()));
}
private slots:
void onClicked(){
QString a = line.text();
QString b = "This line is to be added";
QString c = a+b;
textedit.setText(c); // or textedit.append(c);
}
private:
QLabel label;
QLineEdit line;
QPushButton button;
QTextEdit textedit;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Widget w;
w.show();
return app.exec();
}
#include "sample.moc"

Switching two mainwindows

I am new to QT GUI programming.
I am trying to test switching two mainwindows continously by using show and hide.
I have created a simple code in main.cpp
main(){
QApplication a(argc , argv)
Mainwinodw1 *window1 = new Mainwindow1();
Mainwinodw1 *window2 = new Mainwindow2();
for (;;)
{
window1->show();
delay();
window1->hide();
window2->show();
delay();
window2->hide();
}
return a.exec();
}
The test can display the windows only one time , but duirng the second iteration they dont show and hide.
Can somebody help to fix this.
Try to use Qt timers instead of hardcoded delay function.
main.cpp file:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mainwindow1 *window1 = new Mainwindow1();
Mainwindow2 *window2 = new Mainwindow2();
WindowSwitcher ws(window1, window2, 2000);
window1->show();
return a.exec();
}
WindowSwitcher source code:
#include "windowswitcher.h"
#include <QTimer>
WindowSwitcher::WindowSwitcher(QMainWindow *w1, QMainWindow *w2, int delay) : QObject(), window1(w1), window2(w2)
{
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(switchWindow()));
timer->start(delay);
}
void WindowSwitcher::switchWindow()
{
if (window1->isVisible())
{
window1->hide();
window2->show();
}
else
{
window1->show();
window2->hide();
}
}
WindowSwitcher header file:
#include <QObject>
#include <QMainWindow>
class WindowSwitcher : public QObject
{
Q_OBJECT
public:
explicit WindowSwitcher(QMainWindow *w1, QMainWindow *w2, int delay);
private:
QMainWindow *window1;
QMainWindow *window2;
public slots:
void switchWindow();
};

Qt crashes/doesn't appear when i use Qthread::sleep to update progress bar

I am kinda new to QT so i am wondering why is this invalid:
I have a progress bar and i want to update it by using a class that inherits QThread.
void mt::run(QProgressBar * asd){
for(int i = 0;i<100;i++){
asd->setValue(i);
QThread::sleep(100);
}
}
mt is a class that inherits QThread. run is overloaded with a QProgressBar argument. My main UI thread will send it's progressbar like this m.run(ui->progressBar);. If i will remove the QThread::sleep(100); then it will work fine but i won't be able to see the increment because the thread will be done so fast. But if i will put a little delay, my screen won't appear at all.
You can access and update GUI elements from the main thread only.
If you want to prepare some data inside a custom thread, you should use the signals/slots mechanism to send that data to your widgets.
Here's a basic example:
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QObject *parent = 0);
signals:
void valueChanged(int value);
protected:
void run();
}
void MyThread::run()
{
for (int i = 0; i < 100; i++)
{
emit valueChanged(i);
QThread::sleep(100);
}
}
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
QHbovLayout *layout = new QHbovLayout(this);
QProgressBar *pb = new QProgressBar;
layout->addWidget(pb);
MyThread *t = new MyThread(this);
connect(t, SIGNAL(valueChanged(int)), pb, SLOT(setValue(int)));
t->start();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// we are in the main thread here, so we can create a widget
MyWidget w;
w.show();
return a.exec();
}
QThread::sleep(100);
You are telling it to sleep for a 100 seconds - that's quite a long time. Perhaps you meant QThread::msleep(100)?

How to finish Qt programm from any place?

My example:
main.cpp:
QApplication a(argc, argv);
MainWindow w;
w.start();
return a.exec();
w.start():
if (cf.exec()){
this->show();
} else {
qDebug()<<"Need exit";
//here should be exit
}
At comment place, I tried to do: qApp->exit() and qApp->quit() and this->close() (but 'this' not shown and of cource close() is not working). How can I finish app from any place of code?
Whole code:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.start();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "CadrForm.h"
#include "TeacherForm.h"
#include "DepartmentForm.h"
#include "CategoriesForm.h"
#include "PostForm.h"
#include "RanksAndDegreesForm.h"
#include "TeachersRankAndDegreeForm.h"
#include "ConnectionForm.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
void start();
~MainWindow();
signals:
void widgetChanged(QWidget*);
private slots:
void on_actionCadr_triggered();
void resetMainLayout(QWidget* w);
void on_actionTeacher_triggered();
void on_actionDepartment_triggered();
void on_actionPost_triggered();
void on_actionCategories_triggered();
void on_actionRanksAndDegrees_triggered();
void on_actionTeachersRD_triggered();
private:
ConnectionForm cf;
CadrForm *cadrForm;
TeacherForm *teacherForm;
DepartmentForm *departmentForm;
CategoriesForm *categoriesForm;
PostForm *postForm;
RanksAndDegreesForm *ranksAndDegreesForm;
TeachersRankAndDegreeForm *teachersRankAndDegreeForm;
QWidget *current;
Ui::MainWindow *ui;
void addWidgetToMainLayout(QWidget *w);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
connect(this, SIGNAL(widgetChanged(QWidget*)), this, SLOT(resetMainLayout(QWidget*)));
ui->setupUi(this);
cadrForm = new CadrForm(this);
teacherForm = new TeacherForm(this);
departmentForm = new DepartmentForm(this);
categoriesForm = new CategoriesForm(this);
postForm = new PostForm(this);
ranksAndDegreesForm = new RanksAndDegreesForm(this);
teachersRankAndDegreeForm = new TeachersRankAndDegreeForm(this);
addWidgetToMainLayout(cadrForm);
addWidgetToMainLayout(teacherForm);
addWidgetToMainLayout(departmentForm);
addWidgetToMainLayout(categoriesForm);
addWidgetToMainLayout(postForm);
addWidgetToMainLayout(ranksAndDegreesForm);
addWidgetToMainLayout(teachersRankAndDegreeForm);
}
void MainWindow::start()
{
if (cf.exec()){
this->show();
} else {
qDebug()<<"Need exit";
qApp->quit();
qDebug()<<"still working";
}
}
void MainWindow::addWidgetToMainLayout(QWidget *w)
{
ui->mainLayout->insertWidget(0, w);
ui->mainLayout->itemAt(0)->widget()->hide();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resetMainLayout(QWidget *w)
{
int index;
if (current)
{
index = ui->mainLayout->indexOf(current);
ui->mainLayout->itemAt(index)->widget()->hide();
}
index = ui->mainLayout->indexOf(w);
if (index != -1) ui->mainLayout->itemAt(index)->widget()->show();
else {
addWidgetToMainLayout(w);
resetMainLayout(w);
}
current = w;
setWindowTitle(current->windowTitle());
}
void MainWindow::on_actionCadr_triggered()
{
emit widgetChanged(cadrForm);
}
void MainWindow::on_actionTeacher_triggered()
{
emit widgetChanged(teacherForm);
}
void MainWindow::on_actionDepartment_triggered()
{
emit widgetChanged(departmentForm);
}
void MainWindow::on_actionPost_triggered()
{
emit widgetChanged(postForm);
}
void MainWindow::on_actionCategories_triggered()
{
emit widgetChanged(categoriesForm);
}
void MainWindow::on_actionRanksAndDegrees_triggered()
{
emit widgetChanged(ranksAndDegreesForm);
}
void MainWindow::on_actionTeachersRD_triggered()
{
emit widgetChanged(teachersRankAndDegreeForm);
}
And ConnectionForm - it's just a QDialog with some GUI and without any additional code.
It looks like the problem is you're not allowed to call QApplication::quit() or QApplication::exit() until the QApplication event loop has actually started. The event loop gets started by QApplication::exec(), so you're calling quit()/exit() too soon for it to have an effect.
You can fix this either by moving the quit()/exit() call so that it's in the event loop (e.g. by moving your MainWindow::start() code to the QMainWindow::showEvent() slot), or by changing your MainWindow::start() to return a value, inspect that value in main, and exit (without calling QApplication::exec()`) if it's a value that indicates your process should exit early.
Since you start the dialog event loop "early" - which is blocking -, you do not get to the event loop of the application.
If this is an intentional design, you better call exit(3) and remove the application event loop.
If you want to have the application event loop running, then you will need to make sure that it runs before you get to the point of your dialog execution.
The quick fix would be to start a single shot QTimer right just before the application event loop is started and that would trigger your "start" method call.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.start();
QTimer::singleShot(200, w, SLOT(start()));
return a.exec();
}
and change the start to a slot, respectively.
In the long run, you may wish to consider a button and so on for bringing your dialog up, however.
The idiomatic way of queuing a method call until the event loop gets a chance to run is:
QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
Thus, your main would become:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
return a.exec();
}

Abnormal termination when calling `cvCreateCameraCapture(-1)`

My code as follow. When I execute cvCreateCameraCapture(-1) in openCamera, the app ends.
TIP: Abnormal program termination. during startup program exited with code 0X000135
Why? The computer is notebook, and inner-Camera.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
>
#include<highgui.h>
#include<cv.h>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void openCamera();
void readFrame();
void closeCamera();
void takingPhote();
private:
Ui::MainWindow *ui;
QTimer* timer;
QImage* image;
CvCapture* cam;
IplImage* frame;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
cam = NULL;
timer = new QTimer(this);
image = new QImage;
connect(ui->openCamera, SIGNAL(clicked()), this, SLOT(openCamera()));
}
void MainWindow::openCamera()
{
cam = cvCreateCameraCapture(-1);
// timer->start(33);
// connect(timer, SIGNAL(timeout()), this, SLOT(readFrame()));
}
Adding my previous comment as an answer since it helped you solve the problem:
I want you to replace the cvCreateCameraCapture() call for something else, like cvWaitKey(0);. If this is a runtime issue related to environment variables and Windows not finding OpenCV, this simple test will show. So, if it continues to crash then it might really be related to the environment configuration.