How to connect two dialogs? - c++

If i click on one dialog button on the other dialog will show some text, it doesnt have to be text basicly connection between two dialogs. Something that will help me about my problem.

If you have two QWidget (or inherited) objects represented as dialogs, then you should use an QObject::connect method. Learn about signals and slots in Qt. It looks like:
class DialogA : public QWidget {
Q_OBJECT
...
public slots:
void ShowSomeText(); // called when receive a signal
...
};
class DialogB : public QWidget {
Q_OBJECT
...
void SendTextSignal(); // sends a signal
...
};
// somwhere in code
DialogA da;
DialogB db;
connect(db, SIGNAL(SendTextSignal()), da, SLOT(ShowSomeText()));

Related

QT5 Slot not called in subclass

I have a superclass BackgroundWorkerWithWaitDialog that manages a WaitDialog that implements a progress bar box with an "abort" button. It is used as a QObject in a QThread.
My intention is to derive any background task from BackgroundWorker and implement only the execute() command, polling for an aborted flag to stop it.
BackgroundWorkerWithWaitDialog is derived from BackgroundWorker that is a QObject, all classes are Q_OBJECT and the worker classes are able to update the gui using signals and slots. This communication (Worker to Gui Object) is working correctly.
The problem is that though WaitDialog responds to the pushbutton click, the aborted() signal is emitted from the WaitDialog but isn't received by the BackGroundWorker. (Gui -> Worker)
class WaitDialog : public QDialog
{
Q_OBJECT
public:
explicit WaitDialog(QWidget *parent = 0);
~WaitDialog();
public slots:
void setText(QString text);
void setProgress(bool shown, int max);
void enableAbort(bool enable);
void setProgression (int level);
signals:
void aborted();
private slots:
void on_cmdAbort_clicked();
private:
Ui::WaitDialog *ui;
};
void WaitDialog::on_cmdAbort_clicked()
{
qDebug() << "ABORT";
emit aborted();
}
...
/// BackgroundWorker is QObject-derived.
class BackgroundWorkerWithWaitDialog : public BackgroundWorker
{
Q_OBJECT
public:
explicit BackgroundWorkerWithWaitDialog(MainWindow *main, WaitDialog *dialog);
...
public slots:
virtual void abortIssued();
....
BackgroundWorkerWithWaitDialog::BackgroundWorkerWithWaitDialog(MainWindow *main, WaitDialog *dialog)
: BackgroundWorker(main),
mWaitDialog(dialog),
mAborted(false)
{
connect (this, SIGNAL(progress(int)), mWaitDialog, SLOT(setProgression(int)));
connect (this, SIGNAL(messageChanged(QString)), mWaitDialog, SLOT(setText(QString)));
connect (this, SIGNAL(progressBarVisibilityChanged(bool,int)), mWaitDialog, SLOT(setProgress(bool,int)));
connect (this, SIGNAL(abortButtonVisibilityChanged(bool)), mWaitDialog, SLOT(enableAbort(bool)));
connect (mWaitDialog, SIGNAL(aborted()), this, SLOT(abortIssued()));
}
void BackgroundWorkerWithWaitDialog::abortIssued()
{
// THIS IS NEVER EXECUTED
mAborted = true;
}
Is there something I am missing? I temporarily fixed this with a listener pattern, but frankly I don't like this hybrid fix.
Why isn't the abortIssued slot not called ?
Thanks in advance.
So to summarize:
BackgroundWorkerWithWaitDialog (BWWWD) derives from BackgroundWorker that inherits from QObject
BackgroundWorkerWithWaitDialog receive in the constructor a WaitDialog (WD) that is derived from QDialog
BWWWD in the constructor connect()s the waitDialog aborted() signal with the abortIssued() slot
WD emits the signal but abortIssued isn't called
BWWWD is executed in a separate QThread
It would worth saying that BWWWD class is derived by other SpecificWorker classes that implements specific functions that make use of the aborted() function to interrupt the processing.
Your question states:
i have a superclass BackgroundWorker that manages a WaitDialog that implements a progress bar box with an "abort" button.
In the BackgroundWorkerWithWaitDialog constructor you do not pass dialog to BackgroundWorker's constructor, nor do you use a BackgroundWorker member variable when you are setting up your connections.
Either your questions opening statement is wrong, or you are connecting to a dialog that is never used.

No matching signal for QAction, no "go to slot" menu entry

I have problem with actually running QActions created with QtCreator. To run e.g. actionSystemSettings, I've added slot to MainWindows so it looks like this:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_menuWork_actionSystemSettings();
private:
Ui::MainWindow *ui;
};
And this:
void MainWindow::on_menuWork_actionSystemSettings() {
qDebug() << "Yay!";
}
It prompts:
QMetaObject::connectSlotsByName: No matching signal for
on_menuWork_actionSystemSettings()
I guess it's some dumb mistake and I just forgot about something but reading documentation gives me nothing. I have no "go to slot" menu entry which should auto-create some template... at least Visual Studio for C# did that.
When you're defining slots the correct way is:
on_<widget_name>_<signal>
for instance if you have to name your slot
private slots:
on_actionSystemSettings_triggered();
See QtAutoConnect
According to the documentation for QMetaObject::connectSlotsByName():
Searches recursively for all child objects of the given object, and
connects matching signals from them to slots of object that follow the
following form:
void on_object-name_signal-name(signal-parameters);
So, I think your slot should have the following signature:
void MainWindow::on_actionSystemSettings_triggered()
{
//
}

mainwindow.ui and dialog.ui to set/read communication date

I have two windows: mainwindow.ui and dialog.ui. In the mainwindow.cpp I initialise some objects on the heap of another class for Ethernet-communication and use functions of these objects to read date from the bus and show the values in the mainwindow.ui. In dialog.ui I would like to set the values on the bus, but the problem is to access the communication-functions and objects in mainwindow.cpp.
I wanted to define dialog.cpp as friend class, but I make something wrong. Here is some code:
mainwindow.h
class MainWindow : public QMainWindow
{protected: DateReg *myPosReg;...}
mainwindow.cpp
...
myPosReg = new DateReg(DateValue->AddReg());
...
myPosReg->GetValue(a,b,c);
myPosReg->setValue(a,b,c);
...
Can I somehow access setValue() function in dialog.cpp? Should I allways use dialog.cpp for the dialog.ui or there is some possibility work with dialog.ui-date in mainwindow.cpp? To set the values in dialog.ui I use QDoubleSpinBox.
In the mainwindow.ui I call dialog.ui.
Excuse me for my English.
As far as I understand, you have two classes: MainWindow and Dialog. As MainWindow::myPosReg is protected, you can only access it in Dialog, if Dialog derives from MainWindow or if it is a friend.
The following design should work:
class MainWindow : public QMainWindow
{
[...]
protected:
DateReg *myPosReg;
friend class Dialog;
};
class Dialog
{
[...]
MainWindow* myMainWindow;
void someFunction()
{
myMainWindow->myPosReg->setValue([...]);
}
};
As an alternative, I would suggest a more Qt-ish way by using signals and slots. When the spin-boxes in Dialog change, emit a signal to which MainWindow listens.
We start with the dialog:
class Dialog : public QDialog
{
[...]
Dialog()
{
[...init ui...]
connect(ui->spinBoxA, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
connect(ui->spinBoxB, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
connect(ui->spinBoxC, SIGNAL(valueChanged(int)),
this, SLOT(onSpinBoxValueChanged()));
}
signals:
void valuesChanged(int a, int b, int c);
private slots:
void onSpinBoxValueChanged()
{
emit valuesChanged(ui->spinBoxA->value(), ui->spinBoxB->value(),
ui->spinBoxC->value());
}
};
So the dialog has an internal slot onSpinBoxValueChanged(), which is called when
one of the spinboxes changes its value. The sole purpose of this slot is to emit
another signal valuesChanged to which we'll connect the main window (i.e. the
dialog's internal slot combines three values into one signal).
The main window could be the following:
class MainWindow : public QMainWindow
{
[...]
DateReg *myPosReg;
public slots:
void setValues(int a, int b, int c)
{
myPosReg->setValues(a, b, c);
}
};
And the code, which connects both
int main()
{
[...]
MainWindow* mainWindow = new MainWindow;
Dialog* dialog = new Dialog;
connect(dialog, SIGNAL(valuesChanged(int,int,int)),
mainWindow, SLOT(setValues(int,int,int)));
}
When the user changes the value in a spinbox, the following chain-reaction happens:
QSpinBox::valueChanged(int) -> Dialog::onSpinBoxValueChanged()
-> Dialog::valuesChanged() -> MainWindow::setValues() -> DateReg::setValues()
The advantage is that you decouple MainWindow and Dialog: Dialog just signals that the values have changed but does not care what happens with them and MainWindow changes its myPosReg but does not care, where the values are coming from.

Qt: why does connect() work only in the main window class?

Here's a simple code that creates a button and assigns a onclick handler:
auto btn = new QPushButton("CLICK ME");
connect(btn, SIGNAL(clicked()), this, SLOT(btn_Click()));
private slots:
void btn_Click() {
alert("clicked!");
}
It works as it should if called in the main window class. However when I try to do this in a child window, clicking the button does nothing. The child window is shown like this:
auto settingsWindow = new SettingsWindow();
settingsWindow->show();
I guess it's somehow connected with the receiver object which is now a different window. But how can I make it work?
In order to be able to declare signals/slots in your own class you should include Q_OBJECT directive in your class:
class SettingsWindow {
Q_OBJECT
...
};
You should add a MACRO in class SettingsWindow to enable singal receiving.
Add "Q_OBJECT" like the following.
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget();
....

Using QMDIArea with Qt 4.4.

I'm using the QMdiArea in Qt 4.4.
If a new project is created, I add a number of sub windows to a QMdiArea. I'd like to disallow the user to close a sub window during runtime. The sub windows should only be closed if the whole application is closed or if a new project is created.
How can I do this?
You need to define your own subWindow. create a subclass of QMdiSubWindow and override the closeEvent(QCloseEvent *closeEvent). you can control it by argument. for example:
void ChildWindow::closeEvent(QCloseEvent *closeEvent)
{
if(/*condition C*/)
closeEvent->accept();
else
closeEvent->ignore(); // you can do something else, like
// writing a string in status bar ...
}
then subclass the QMdiArea and override QMdiArea::closeAllSubWindows () like this:
class MainWindowArea : public QMdiArea
{
Q_OBJECT
public:
explicit MainWindowArea(QWidget *parent = 0);
signals:
void closeAllSubWindows();
public slots:
};
// Implementation:
MainWindowArea::closeAllSubWindows()
{
// set close condition (new project is creating, C = true)
foreach(QMdiSubWindow* sub,this->subWindowList())
{
(qobject_cast<ChildWindow*>(sub))->close();
}
}
you may also need to override close slot of your mdi area.
You'd do this the same as for a top-level window: process and ignore the QCloseEvent it sent. QMdiArea::closeActiveSubWindow/QMdiArea::closeAllSubWindows just call QWidget::close, which sends a closeEvent and confirms that it was accepted before proceeding.
You can process this event by subclassing QMdiSubWindow and reimplementing QWidget::closeEvent, or by using an event filter to intercept it..