How to communicate between QDialog Window and QMainWindow with Qt C++ - c++

I am an application using Qt Creator in C ++. The int main () function is as follows.
I am starting a QDialog Window where I am getting the "url" variable content.
How can I get this variable into the mainwindow.cpp file.
QApplication a(argc, argv);
MainWindow *w; //Put it here in case you have several cases where you want to initialize it
QLoginDialog d; //Your login dialog
if(d.exec()==QDialog::Accepted)
{
if(d.isLogged()) //Check the variable used to validate the login
{
w = new MainWindow;
w->show();
}
else
{
//Handle bad login
return -1; //Don't forget to return something here
}
}
else
{
//Handle dialog not validated
return -1; //Don't forget to return something here
}
return a.exec();
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Uİ::MainWindow)
{
QDialog s;
s.show();
s.setmodel(true);
if(s.exec()==QDialog::Accepted)
{
if(s.URL=="true")
{
ui.setupUi(this);
}
}
}
QDialog.cpp=Start.cpp source code:
#include "start.h"
#include "ui_start.h"
Start::Start(QWidget *parent) :
QDialog(parent),
ui(new Ui::Start)
{
ui->setupUi(this);
}
Start::~Start()
{
delete ui;
}
void Start::on_pushButton_2_clicked()
{
QString dirName=QFileDialog::getExistingDirectory(
this,
tr("Select a Directory"),
QDir::currentPath());
if(!dirName.isNull())
ui->lineEdit_2->setText(dirName);
}
void Start::on_pushButton_3_clicked()
{
URL=ui->lineEdit->text();
Directory=ui->lineEdit_2->text();
if(URL.isEmpty() && Directory.isEmpty())
{
QMessageBox::warning(this,tr("Error"),tr("Please, fill in the blanks"));
}
else if(URL.isEmpty())
{
QMessageBox::warning(this,tr("Error"),tr("is not a valid URL or Path!!"));
}
else if(Directory.isEmpty())
{
QMessageBox::warning(this,tr("Error"),tr("is not a select directory!!"));
}
ControlConfiguration();
}
void Start::ControlConfiguration()
{
QString configPosition= ui->lineEdit_2->text();
QString str1="CHECKOUT_HOME";
QString str2="new_checkout.csh";
QString str3="setup_prjsvn.csh";
QMessageBox *msgBox=new QMessageBox(this);
int sayac=0;
QDir path(configPosition);
QStringList files=path.entryList(QDir::Files);
for(int i=0; i<files.length(); i++)
{
if(files[i].compare(str1)==0)
{
sayac=sayac+1;
}
}
for(int i=0; i<files.length(); i++)
{
if(files[i].compare(str2)==0)
{
sayac=sayac+1;
}
}
for(int i=0; i<files.length(); i++)
{
if(files[i].compare(str3)==0)
{
sayac=sayac+1;
}
}
if(sayac>=3)//Attention Flurent. if true, open QMainWindow
{
QMessageBox::information(this,tr(" "),tr("Configuration Directory"));
//s_path=ui->lineEdit->text();
this->hide();
s_path="true";
URL=ui->lineEdit_2->text();
}
else
{
msgBox->setInformativeText("Would you like to configure?");
msgBox->setStandardButtons(QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes);
msgBox->setDefaultButton(QMessageBox::Yes);
int ret = msgBox->exec();
switch(ret){
case QMessageBox::Yes:
Configuration();
break;
case QMessageBox::No:
//ui->locationEdit->clear();
break;
case QMessageBox::Cancel:
break;
}
}
}
void Start::Configuration()
{
QString projePosition= ui->lineEdit_2->text(); // Proje konumu alınır.
QProcess* process=new QProcess(this);
QMessageBox *msgBox=new QMessageBox(this);
process->setWorkingDirectory(projePosition);
QString svn_export="svn export http://atlas/svn/prjsvn/trunk/common/common_bin/istanbul/new_checkout.csh";
QString s_newcheckout="source new_checkout.csh";
QString s_prjsvn="source setup_prjsvn.csh";
process->start("tcsh -c \""+svn_export+";"+s_newcheckout+";"+s_prjsvn+"\"");
process->waitForBytesWritten();
process->waitForFi
}

You should have a proper look at signals and slots, to pass variables between objects. The documentation is here : http://doc.qt.io/qt-4.8/signalsandslots.html
An other way would be to execute the QDialog inside your MainWindow, that would be the best practice. Use controls in the scope where they are useful. You should not have to use dialogs in the main function.
So, have a look at both solutions. The best, for simple variables, being to execute your dialog inside the class where the value will be used, the second being the use of signals and slots if values have to be passed between complex classes.
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w; //Put it here in case you have several cases where you want to initialize it
QLoginDialog d; //Your login dialog
if(d.exec()==QDialog::Accepted)
{
if(d.isLogged()) //Check the variable used to validate the login
{
w = new MainWindow(d.getUrl()); //I guess the URL comes from your login dialog, so make a function that returns it
w->show();
}
else
{
//Handle bad login
return -1; //Don't forget to return something here
}
}
else
{
//Handle dialog not validated
return -1; //Don't forget to return something here
}
return a.exec();
}
mainwindow.cpp
//Don't forget to add the "QString sUrl" to your mainwindow.h
MainWindow::MainWindow(QString sUrl, QWidget *parent): QMainWindow(parent), ui(new Uİ::MainWindow)
{
ui.setupUi(this);
qDebug()<<s.URL; //It will be displayed here
}
Your dialog.cpp
//Use this to return the boolean value that represents if the path is valid or not.
bool QDialog::isLogged()
{
return this->s_path.equals("true");
}

A standard generated main file for a qt application contains the following lines:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The main window is created there.
So in your case you could create the main window before your return.
By adding a QString as parameter in the constructor the url would be available in the mainwindow.
so the mainWindow.cpp constructor changes to:
MainWindow::MainWindow(QString url, QWidget *parent) :
QMainWindow(parent), ui(new Uİ::MainWindow)
{
ui.setupUi(this);
//Place your code here that uses the url,
}
so the mainWindow.h constructor changes to:
MainWindow::MainWindow(QString url = "", QWidget *parent = 0);
and the main.cpp changes to:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString url; //Fill this from your dialog.
MainWindow w(url);//Pass the url to the main window
w.show();
return a.exec();
}

If all you want to do is to ask for an input string, i suggest you to have a look at QInputDialog
Example:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
bool ok;
QString message = QInputDialog::getText
(0, "Input","URL:", QLineEdit::Normal,"", &ok);
qDebug()<<message;
ui->setupUi(this);
}

Related

Pass variable from mainwindow to another qt c++ forms

I want to pass three strings (cellTitle,cellPoem,cellGroup) from mainwindows to another dialog. I know when i initiate the second form the values become zeros. I read somewhere it's possible with slots but i don't know how.
mainwindows.h
public:
QString cellTitle,cellPoem,cellGroup;
mainwindows.cpp
void MainWindow::on_tableView_pressed(const QModelIndex &index)
{
cellText = ui->tableView->model()->data(index).toString();
QSqlQuery * qry2 = new QSqlQuery(mydb);
qry2->prepare("select * from Poems where Title='"+cellText+"'");
qry2->exec();
while(qry2->next()){
cellTitle = qry2->value(1).toString();
cellPoem = qry2->value(2).toString();
cellGroup = qry2->value(3).toString();
ui->textEdit->setText(qry2->value(2).toString());
}
}
void MainWindow::on_btnUpdate_clicked()
{
frmUpdate frmupdate;
frmupdate.setModal(true);
frmupdate.exec();
}
frmupdate.cpp
#include "frmupdate.h"
#include "ui_frmupdate.h"
#include <mainwindow.h>
frmUpdate::frmUpdate(QWidget *parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow mainwindow;
ui->lineEdit->setText(mainwindow.cellTitle);
ui->lineEdit_2->setText(mainwindow.cellGroup);
ui->textEdit->setText(mainwindow.cellPoem);
}
frmUpdate::~frmUpdate()
{
delete ui;
}
void frmUpdate::on_btnUpdate_clicked()
{
}
void frmUpdate::on_pushButton_2_clicked()
{
this->close();
}
frmUpdate::frmUpdate(QWidget *parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow mainwindow;
You here have created a new, temporary MainWindow instance only with default constructor being called. Of course, this new instance is then created with empty default texts:
ui->lineEdit->setText(mainwindow.cellTitle);
ui->lineEdit_2->setText(mainwindow.cellGroup);
ui->textEdit->setText(mainwindow.cellPoem);
}
Easiest now would be passing the original main window as parameter:
frmUpdate::frmUpdate(QWidget* parent, MainWindow* mainWindow) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
}
If the parent is the main window, you can simply cast:
frmUpdate::frmUpdate(QWidget* parent) :
QDialog(parent),
ui(new Ui::frmUpdate)
{
ui->setupUi(this);
MainWindow* mainWindow = qobject_cast<MainWindow*>(parent);
if(mainWindow)
{
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
}
else
{
// appropriate error handling
}
}
You might search the main window from parent as well:
for(;;)
{
MainWindow* mainWindow = qobject_cast<MainWindow*>(parent);
if(mainWindow)
{
ui->lineEdit->setText(mainwindow->cellTitle);
ui->lineEdit_2->setText(mainwindow->cellGroup);
ui->textEdit->setText(mainwindow->cellPoem);
break;
}
parent = parent->parent();
if(!parent)
{
// appropriate error handling
break;
}
}
All above assuming that MainWindow inherits from QObject...

Cannot change QAction's icon

I'm trying to toggle QAction's icon. It depends on context of a specific table. Actually, it's working whenever I start message.cpp, but it wouldn't change when I'm on message.cpp. I expect updateIcon() will change my icon if I click on m_action4, but it doesn't. Could I repaint QAction?
Firstly, I set variable on header:
message.h:
private:
QAction *m_action4;
Here is my code on source:
message.cpp:
QSqlQuery query0;
m_action4 = new QAction(QIcon(":/images/silent1.png"), tr("Mute"), this);
m_muteActive = false;
query0.prepare("SELECT state FROM mute_state WHERE p_id=?");
query0.addBindValue(m_pid);
query0.exec();
if (query0.next() && query0.value(0) == "1" )
{
{
m_muteActive = true;
m_action4->setIcon(QIcon(":/images/speaker.png"));
}
}
m_actionBar->addButton(m_action4);
connect(m_action4, SIGNAL(triggered()), this, SLOT(muteMessages()));
muteMessages()
{
QSqlQuery query;
query.prepare("UPDATE mute_state SET state=? , duration= ? , type=? WHERE p_id=?");
if (m_muteActive)
{
query.addBindValue("0");
query.addBindValue("0");
m_muteActive = false;
}
else
{
query.addBindValue("1");
query.addBindValue("525949");
m_muteActive = true;
}
query.addBindValue("private");
query.addBindValue(m_id);
if (query.exec())
qDebug()<<"query was executed";
}
QTimer::singleShot(100 , this, SLOT(updateIcon()));
}
updateIcon()
{
if (m_muteActive)
m_action4->setIcon(QIcon(":/images/silent1.png"));
else
m_action4->setIcon(QIcon(":/images/speaker.png"));
}
The code you've posted works fine. Here it is, after removing the SQL queries that are not necessary to demonstrate it:
#include <QApplication>
#include <QAction>
#include <QToolBar>
#include <QGridLayout>
#include <QPainter>
class Ui : public QWidget {
QGridLayout m_grid;
QToolBar m_actionBar;
QIcon m_silent, m_speaker;
QAction m_action4;
bool m_muteActive;
QPixmap drawText(const char * text, int size = 64) {
QPixmap pix(size, size);
QPainter p(&pix);
p.setFont(QFont("helvetica", size*0.8));
p.fillRect(pix.rect(), Qt::white);
p.drawText(pix.rect(), QString::fromUtf8(text));
return pix;
}
public:
Ui() :
m_grid(this),
m_silent(drawText("🔇")),
m_speaker(drawText("🔊")),
m_action4(tr("Mute"), this),
m_muteActive(false)
{
m_grid.addWidget(&m_actionBar, 0, 0);
m_actionBar.addAction(&m_action4);
connect(&m_action4, &QAction::triggered, this, &Ui::muteMessages);
updateIcon();
}
Q_SLOT void muteMessages() {
m_muteActive = !m_muteActive;
updateIcon();
}
Q_SLOT void updateIcon() {
m_action4.setIcon(m_muteActive ? m_silent : m_speaker);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Ui ui;
ui.show();
return a.exec();
}

how to force Qt mainWindow to wait for some changes

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);
}
}

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();
}

Possible to make QDialog shake in OSx

Since Qt is using Cocoa under OSX, is it possible to make a modal QDialog to shake if the user enters the wrong password for example? Im not able to find anything about it but it would be really nice to implement on mac.
Thanks!
I'm not aware of a built-in way to do it, but you could implement the shaking yourself, like this:
header.h
#include <QtGui>
class ShakyDialog : public QDialog
{
Q_OBJECT
public slots:
void shake()
{
static int numTimesCalled = 0;
numTimesCalled++;
if (numTimesCalled == 9) {
numTimesCalled = 0;
return;
}
vacillate();
QTimer::singleShot(40, this, SLOT(shake()));
}
private:
void vacillate()
{
QPoint offset(10, 0);
move(((shakeSwitch) ? pos() + offset : pos() - offset));
shakeSwitch = !shakeSwitch;
}
bool shakeSwitch;
};
main.cpp
#include "header.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
ShakyDialog dialog;
QHBoxLayout layout(&dialog);
QPushButton button("Push me.");
layout.addWidget(&button);
QObject::connect(&button, SIGNAL(clicked()), &dialog, SLOT(shake()));
dialog.show();
return app.exec();
}