How to get the result of QDialog::show()? - qt

I want to convert exec usages to show method in my projects. Because, when I use the exec for windows (dialogs) I can not open another window. This is the basic difference between exec() and show() method.
The exec and show work in different ways and I am wondering how can I change the below code with using show() instead of exec().
For example:
int result = exampleWindow->exec();
if ( result == QDialogButtonBox::Ok )
{
exampleWindow->UpdateCalibrationData(&data);
exampleWindow->UpdateFilterData(&filterData);
exampleWindow();
}

show() shows a non-modal window;
exec() shows a modal window.
If you want to get the result of show(), then go with Qt signals/slots:
ExampleWindow::ExampleWindow(QWidget *parent) : QDialog(parent)
{
// Assuming the QDialogButtonBox name is "buttonBox":
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
MainWindow.h:
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
void updateData();
}
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
connect(exampleWindow, SIGNAL(accepted()), this, SLOT(updateData()));
}
void MainWindow::updateData()
{
// Your code:
exampleWindow->UpdateCalibrationData(&data);
exampleWindow->UpdateFilterData(&filterData);
exampleWindow();
}

show() simply makes the dialog window visible. It is a QWidget method.
exec(), when provided in a class, always spins an event loop. In case of dialogs specifically, it'll make the dialog visible before spinning the event loop.
You could implement a functionally equivalent exec() yourself, as follows:
void myExec(QDialog * dialog) {
QStateMachine sm;
QState s1(&sm), s2(&sm);
sm.setInitialState(&s1);
QEventTransition transition(dialog, QEvent::Close);
s2.addTransition(&transition);
QEventLoop loop;
QObject::connect(&s2, &QState::entered, &loop, &QEventLoop::quit);
sm.start();
dialog->show();
loop.exec();
}
Generally speaking, you should never use exec() to create a nested event loop, since you're exposing a lot of your own code to possible reentrancy requirements. In case of dialogs, it is always possible to show a modal dialog box without using exec(), so there's really no point to it.

exec() method shows modal dialog as described here
You can use for example closeEvent() of your dialog. In it you can write something like:
void ExmpleWin::closeEvent(QCloseEvent *event)
{
if (/*Your condition*/) {
emit signalUpdateMyData();
event->accept();
}
}
Also you have to connect signal signalUpdateMyData() with apropriate slot where you can make:
exampleWindow->UpdateCalibrationData(&data);
exampleWindow->UpdateFilterData(&filterData);
exampleWindow();

Related

How to achieve exclusive (e.g. Radio Button) type behavior with QGraphicObject?

I'm working with Qt (v 5.3) again after sometime away. As a learning exercise I am prototyping a module using QGraphicView in order to understand better how to use it.
The functionality is simple: I have several QGraphicObjects which function like buttons with states and behaviors:
OFF - image panel hidden; default button art
ON - image panel
displayed; highlight button art
At startup all buttons are in an OFF state
A clicked button will toggle it's state (non-Exclusive)
If a different button is already in an ON state, it must be turned off (Exclusive)
Everything is data driven and created dynamically at runtime.
So that is my little learning exercise. What I am trying to sort out is an efficient messaging mechanism to handle the "radio button sometimes" exclusive behavior and sending a message to a group of objects without strongly coupling them.
I've looked at signals and slots but that gets tedious if there are many connections to make.
QSignalMapper which seems somewhat better
QEvent is probably the most solid approach but I've had trouble finding good learning examples.
I am making this more complicated than need be but as I say, it's a learning exercise to get used to Qt again.
So my question (finally): is there an approach I am overlooking or one of these mentioned which would be better (e.g most flexible, maintainable, scalable). Not looking for code per se, but an understanding of how to go about coding something like this using the Qt framework.
Here's an image of the thing:
Signal and slots is the method I would use here. However, rather than connect each button to every other button, you can create an intermediate, Controller class.
The Controller class can either aggregate, or be a parent to all of the buttons.
When a button is created, it connects signals to the controller to inform it of being pressed. The receiving slot in the Controller class is then responsible for turning off any other buttons.
Skeleton code: -
class ButtonController : public QGraphicsObject
{
public slots:
void ButtonPressed();
private:
QList<MyButton*> m_buttonList;
};
void ButtonController::ButtonPressed()
{
foreach(MyButton* pButton, m_buttonList)
{
if(pButton != sender())
{
pButton->Off();
}
}
}
In the constructor of MyButton, assuming the controller is the parent: -
MyButton::MyButton(ButtonController* parent)
: QGraphicsObject(parent);
{
connect(this, &MyButton::pressed(), parent, &ButtonController::ButtonPressed());
...
}
Alternatively, the controller may just hold a list of the buttons, in which case you can do this: -
MyButton::MyButton(QObject* parent, ButtonController* pButtonController)
: QGraphicsObject(parent);
{
connect(this, &MyButton::pressed(), pButtonController, &ButtonController::ButtonPressed());
...
}
In the case of not being able to change the constructor of the buttons, the controller may simply have an AddButton function, in which it creates the connection when the button is added under its control.
Subclass QGraphicsScene
Reimplement mousePressEvent and check is left mouse button pressed.
If so, then get position of mouse by pos() method and get current graphics object under arrow by itemAt() method.
Try to cast it into your needed object, if it was successfully, then change background and other.
Store your graphics objects in vector, in this case you can check every object and decide which object should be turned off.
Fully working example:
header:
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QPoint>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
public slots:
private:
QVector<QGraphicsEllipseItem * > vec;
};
#endif // GRAPHICSSCENE_H
cpp:
#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsItem>
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
//set circles in different positions.
vec.push_back(addEllipse(0,0,50,50,QPen(Qt::red),QBrush(Qt::blue)));
vec.push_back(addEllipse(0+100,0+100,50,50,QPen(Qt::red),QBrush(Qt::blue)));
vec.push_back(addEllipse(0+150,0+150,50,50,QPen(Qt::red),QBrush(Qt::blue)));
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
//qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
QGraphicsEllipseItem *ell = qgraphicsitem_cast<QGraphicsEllipseItem *>(item);
if(ell)
{
for(int i = 0; i < vec.size(); i++)
{
if(vec.at(i) != ell)
{
vec.at(i)->setBrush(QBrush(Qt::blue));//disable all other bettons
}
}
ell->setBrush(QBrush(Qt::black));//to chosen circle
qDebug() << "good";
}
else
qDebug() << "not ell" << mouseEvent->scenePos();
}
}
Usage:
GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setScene(scene);
With this case, your circles will be similar to radioButtons. If you want save state of all buttons you can use:
for(int i = 0; i < vec.size(); i++)
vec.at(i)->setData(0,false);
And get state with
if(!ell->data(0).toBool())
//do

javaScriptWindowObjectCleared signal is not invoked while html page loaded in qwebview

I am new to QT. I have been trying to see the bridge between javascript and Qt Class.
What I did:
1) I have a button and connected clicked signal to on_pushButton_clicked, also I have qwebview instance.
In on_pushButton_clicked:
...
QUrl url = QUrl::fromLocalFile("C:\\whoami\\sd\\index.html");
QObject::connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
this, SLOT(addJSObject()));
ui->webView->page()->mainFrame()->load(QUrl(url));
....
and in addJSObject,
void MainWindow::addJSObject()
{
qDebug () <<"Inside addJSObject";
ui->webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("mBridge"), m_bridge);
qDebug () <<"Nooo. I m not invoked..";
}
Problem:
It compiles without error, and html file is displayed in the qwebview, but addJSObject callback is not invoked.
Could someone help me in order to resolve this issue?.. I must have done some silly mistake. :(.
Make sure, that your MainWindow: 1) inherits QObject 2) has Q_OBJECT macro 3) has a slot addJSObject().
For example mainwindow.h:
class MainWindow : public QObject
{
Q_OBJECT
public:
MainWindow();
private slots:
void addJSObject();
};
If this is correct, you should be able to connect to addJSObject() without static QObject::connect(). Just use connect() when referring to this as signal target object.
One way to just check, that your signalling works is to try using QTimer timeout signal:
QTimer::singleShot(5000, this, SLOT(addJSObject()));

Qt - two signals and modal dialog window

I have a QDialog based class.
I have one QEditLine *editLine and QButton *button.
I use clicked() signal of button. And editingFinished() signal of editLine.
When I change the text in the editLine and press the button firstly editingFinished() signal is emitted. In the slot method I call QMessageBox::question().
After that I can't receive clicked() signal of my button.
I tried to use Qt::QueuedConnection for connect method, but it does not help.
How to solve my problem?
I think the issue is that the event loop for the message box is blocking the main event loop so your button's signal is not emitted. But how do you plan to click the button anyway if you have a modal dialog open?
Here is the code:
Window::Window(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
appPath = QApplication::applicationDirPath();
connect(pButton, SIGNAL(clicked()), this, SLOT(build()), Qt::QueuedConnection);
connect(pLineEdit, SIGNAL(editingFinished()), this, SLOT(pathChanged()), Qt::QueuedConnection);
}
void Window::pathChanged()
{
QString path = pLineEdit->text();
if(createPath(path))
updatePath(path);
}
bool Window::createPath(QString path)
{
if(!QDir(path).exists())
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, tr("Folder is not exist"), "Folder " + path + " is not exist. Do you want to create it?", QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes)
{
QDir dir;
dir.mkpath(path);
}
}
return true;
}
class Window : public QDialog, public Ui::GLConverterDialogUI
{
Q_OBJECT
public:
Window(QWidget *parent = 0);
~Window(void);
......
}
I have the same problem in another application. I use some library. I guess that this library use pressed() signal of QAbstractButton instead of clicked(). And when I call QFileDialog::getSaveFileName() after button is pressed it seems that mouseReleaseEvent() is also not called. So after closing of dialog button is still pressed and I have to send MouseButtonRealese event manually.
Maybe I should call dialog with some special parameters?

implement a progress dialog by QDialog

I'm using QT to implement some UI program.
In this program I need a progress dialog. I tried to use the build-in QProgressDialog, it works fine but in my case I need to confirm (with another dialog) when the "cancel button" is clicked.
In QProgressDialog once the cancel button is clicked, the progress dialog will be canceled, so, I tried to implement my own progress dialog (very simple, a dialog with progress bar). However, if I use my own progress dialog, there is some problems. It cannot be moved or clicked. Once I tried to move it and the dialog loss its focus, the progress bar won't update any more and it cannot gain the focus again. I tried to set different Modality, but either Qt::ApplicationModal or Qt::WindowModal has the same situation.
follows is my progress dialog class, if someone knows how to modify QProgressDialog to meet the confirm requirement or where is the problem in my code.
header:
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
void setRange(int minimum, int maximum);
void setValue(int value);
void setLabelText(QString labtext);
bool wasCanceled();
private:
Ui::Dialog *ui;
bool cancelStatus;
private slots:
void cancel();
};
Source:
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
cancelStatus = false;
ui->progressBar->setRange(0,1);
ui->progressBar->setValue(0);
//this->setWindowModality(Qt::WindowModal);
show();
}
Dialog::~Dialog(){
delete ui;
}
void Dialog::setRange(int minimum, int maximum){
ui->progressBar->setRange(minimum,maximum );
}
void Dialog::setValue(int value){
this->ui->progressBar->setValue(value);
}
void Dialog::setLabelText(QString labtext){
this->ui->label->setText(labtext);
}
void Dialog::cancel(){
// pop up the confirm dialog here
// cancelStatus = true if the confirm dialog is accepted, else do nothing .
}
bool Dialog::wasCanceled(){
return cancelStatus;
}
From the Qt Documentation: The signal QProgressDialog::canceled() is emitted when the cancel button is clicked and it is connected to the cancel() slot by default.
Did you try to connect the canceled signal to you own validation slot, and the cancel the dialog if the user confirm is choice?
Before, connecting your own slot, disconnect the canceled signal from the cancel slot using QObject::disconnect() : http://doc.qt.io/archives/qt-4.7/qobject.html#disconnect

QT EventTransition implementation

I am trying to build an QT State Maschine. I have some States, and for those States i need Transition that alter the Graphics on my gui.
The Problem i having and the only reason i am asking, i am Stuck and Point 1.
The compiler cant identifie the QTEventTransition. I have QT 4.6 wroking with QT Creator on Windows.
The compiler does not find Header #include < QtEventTransition >
This is what i did i never did this bevor but i think it should be correct, I have A Header File where i have my Transitions Declareted like this:
class validateBoatTransition : public QtEventTransition
{
public:
validateBoatTransition(Widget *widget,ServerSkeleton* server);
protected:
bool eventTest(QEvent *e);
void onTransition(QEvent *);
private:
Chart* ourChart;
Message current;
BarelySocket* myBarelySocket;
};
Than i have my Cpp File where i have this:
validateBoatTransition::validateBoatTransition(Widget *widget,ServerSkeleton* server)
{
}
void validateBoatTransition::onTransition(QEvent *e)
{
/*
My Logik should go here
*/
}
What i want is that if the Transition is activated by an Button (clicked) it should fire this transition!
I searched the net, but cant find an solution. Can i do that? I should i think.
Yours Thomas
Maybe you should take a look to signals/slot mechanism. I think this is what you need to achieve what you want.
Make your onTransition function a slot instead of an event handler and connect it to the signal clicked of the button.
class validateBoatTransition : public QtEventTransition
{
...
public slots:
void onTransition();
...
}
Somewhere in your code, connect the button to the slot:
QObject::connect(myButton, signal(clicked()), myValidateBoatTransition, slot(onTransition());
Each time the button will be clicked the execution will go through the onTransition function.
I think you're trying to use wrong classes/mechanisms to achieve your goals. If I understand you correctly, you have some GUI and after clicking some button you want to validate some stuff and if this validation is successful the state machine should change it's state. I'd write it this way:
Create some class to handle validation:
class BoatValidator : public QObject
{
Q_OBJECT
// boring stuff like constructor, etc.
public slots:
void validate()
{
if ( /*your validation logic goes here*/ ) {
emit boatTransition();
}
}
signals:
void boatTransition(); // emitted if validation is succesful
};
Then you connect your QPushButton::clicked() to BoatValidator::validate() and use BoatValidator::boatTransition() signal to drive the state machine:
QStateMachine machine;
QState *state1 = new QState(&machine);
QState *state2 = new QState(&machine);
// more state machine setup
// connect validator and button
QPushButton button;
BoatValidator validator;
connect(&button, SIGNAL(clicked()), &validator, SLOT(validate()));
// use validator to change states
state1->addTransition(&validator, SIGNAL(boatTransition()), state2);
Generally I'd use signal to drive state machine, unless some transitions are obviously event driven (for example some QEvent::Enter/QEvent::Leave on GUI widgets, etc.).
What i wanted to do is build a Qt State Machine. The Problem was that i could not trigger my own Transitions (let alone with my own Events). The answers given are good but would lead to a messy code. Why should i use a QT State Machine if i could not use the QT Transitions?
The First Problem above is solved, if you create a new Project. QT Creater is very annoying.
But here now my solution , may it help others.
First my State:
class ServerState : public QState
{
Q_OBJECT
public:
ServerState(QPushButton * pushButton);
~ServerState();
public slots:
void buttonWasClicked();
protected:
void onEntry(QEvent *e);
void onExit(QEvent *e);
private:
QPushButton * pushButton;
};
Normal, but you see i added an Slot. This slot enables me to connect a bottom signal or a Widget Mouse Press Signal to it !
Like this:
QStateMachine *machine = new QStateMachine(this);
ServerState *s1 = new ServerState(connectButton);
connect(connectButton, SIGNAL(clicked()), s1, SLOT(buttonWasClicked()));
machine->addState(s1);
s1->addTransition(connectTransition);
all i needed to to is now fire a declared Event like this one :
#define RegisterToServerEventIndex User+5
class ConnectToServerEvent : public QEvent
{
public:
ConnectToServerEvent() : QEvent(QEvent::Type(QEvent::ConnectToServerEventIndex))
{}
};
when the slot was called:
void ServerState::buttonWasClicked()
{
this->machine()->postEvent(new ConnectToServerEvent());
qDebug("ServerState::buttonWasClicked");
}
The QT State Machine would now call all the Transitions , link with this state:
ConnectToServerTransition::ConnectToServerTransition(QPushButton * pushButtonB,ServerSkeleton* serverSkeleton)
{
this->pushButtonB = pushButtonB;
this->pushButtonB->hide();
this->serverSkeleton = serverSkeleton;
qDebug("ConnectToServerTransition::ConnectToServerTransition");
}
bool ConnectToServerTransition::eventTest(QEvent *e)
{
return (e->type() == QEvent::ConnectToServerEventIndex);
}
void ConnectToServerTransition::onTransition(QEvent *e)
{
if (true == this->serverSkeleton->initalisieren())
{
this->pushButtonB->show();
}else{
qDebug("Conection to Server faild");
}
emit kill();
return;
}
Whats so great that i dare to post?
Well first you can link a Qt SM to a widget where a mouse press event , or somthing else, is called and process the raw data to a an level you need later in your program. All you then need to do is, to emit the singal:
void Widget::mousePressEvent(QMouseEvent *event){
Coordinates current;
current.line = 0;
current.row = A;
current.row = (Row) (event->x() / 30); // 30 = breite von einen Feld
current.line = event->y() / 30; // 30 = länge von einen Feld
emit this->clicked(current);
return;
}
Then this enhenced information (current) is passed to the slot at my state, where i chose to call the correct transition that does the work. You could link more transitions to it, if you need it.
But most importend you dont need to reprogramm the Transition, a think i realy disliked.
Thank you for your help , i could not done it alone.

Resources