Forcing QDialog to stay open - c++

How should I best go about forcing a QDialog to stay open when the dialog's accept() slot is called? I was thinking of reimplementing that function to get the dialog's exec to return without hiding the dialog, but was wondering if there were any better ways to accomplish this.

Rather than use a QDialog, I would accomplish the effect with a QDockWidget.
Remove the feature that allows the dock to be moved (QDockWidget::DockWidgetMovable)
Set the dock widget to floating (setFloating(true))
Connect items on the dock widget to the appropriate signals and slots on the main window
References
Dock Widgets Example
QDockWidget Documentation

You need to make your QDialog modeless, by calling show instead of exec, and using a custom signal instead of accept, because accept closes the window. And you connect that signal to a slot in the main window with the code you had after the exec call.
And in case that wasn't already the case, you should keep a reference/pointer to your QDialog somewhere (as a member in your main window class, or a static variable within the function that opens it) to be able to avoid creating multiple instances of the dialog, and you need to make sure you only connect the signals/slots once.

Related

QWidget event when overlaid dialog closed?

I have a complex widget on the screen which is visible. By pushing a button a dialog appears but parts of the original widget is still visible. When closing the dialog I would like to refresh some data of my particular widget ... but this widget does not know anything about that dialog. Is there any event I can check for this purpose ? Or any other way to get to know when the dialogs closed ?
First I used
virtual void QWidget::showEvent( QShowEvent* event );
but it is not called when the parts of the widget is already visible.
EDIT
I'm sorry but I wasn't precise enough. When I wrote complex, I meant that I have a main window, which has a child widget which also has child widget and so on (for about file level). That lowest level child widget initiates the opening of the dialog. The other widget which needs the closing event of this dialog is also an embedded widget but somewhere else in the application. When I wrote sending the signal through many classes I meant this. In this case if want to notify my final widget I have to connect the closing signal from my source widget to several intermediate widgets which does not even interested in that signal. I also didn't want to (and can't) connect these signal/slot in the main window because of the mentioned structure. In this is there any advice ?
send the signal through many objects just for this purpose
There's no such thing as sending a signal "through" objects unless you insist on manually threading it through a bunch of them. So this doesn't make much sense unless you explain why you want to "thread" the signal through many objects ("threading" as in a string through a needle, not as in a processing thread).
A signal-slot connection has two endpoints. All you need is:
A signal at the dialog.
A slot at the supercomplex widget.
A connection set up outside of both of them. To make life simple, both the widget and the dialog could be instantiated in main(), and a connection set up before anything even appears on the screen.
The dialog signal you're looking for is simply QDialog::finished, if you have a properly designed dialog. Otherwise, use an EventSignaler of some sort to convert a QEvent::close to a signal.
The slot in the supercomplex widget should be e.g.:
Q_SLOT void refreshSomething();
Its signature/name shouldn't refer to the fact that some dialog was closed: that's coupling the API too much to the external detail of some dialog being there. The slot should get the dialog to update/refresh what you need. The reasons for invoking it are irrelevant to the widget.
Inside the widget, the slot's implementation should most likely simply call update() on one or more subwidgets, perhaps with a relevant region - if you wish to, you can have the region as an optional slot parameter.
See this question about how to forward signals or slots inside of a complex composite class that contains many objects. It's supposed to be very simple; if it's not you'll have to edit the question to indicate why it's complex for you.
At the simplest, with the most decoupled code - where the dialog knows nothing about the widget, and vice versa - as it should be, you can have:
class Dialog : public QDialog { ... };
class Widget : public QMainWindow {
Q_OBJECT
Q_SIGNAL void showDialog();
Q_SLOT void refreshSomething();
...
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
...
Widget widget;
Dialog dialog;
QObject::connect(&widget, &Widget::showDialog, &dialog, &QWidget::show);
QObject::connect(&dialog, &QDialog::finished, &widget, &Widget::refreshSomething);
widget.show();
return app.exec();
}

QComboBox Qt Creator signals slots never fire

I have a very simple Qt window that contains combo box, and I try to create signal slots for this combo box with Qt Creator. I tried activated, currentIndexChanged, currentTextChanged, nothing works.
What may be the reason?
Other signals (button click, menu item click) on the same window fire normally. Operating system is Windows 7.
When you create slots in Qt Designer, on a Form, like a QMainWindow Form, if you right click and Go to slot..., it uses naming conventions to automagically connect the ui form elements to slots based on their name.
After you create those slots, you go and change the object name to something else.
Like instead of comboBox1, you change it to myComboBox, it will break the automagically connected ui form elements, because the name is different.
http://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connections
Widgets and Dialogs with Auto-Connect
Although it is easy to implement a custom slot in the dialog and
connect it in the constructor, we could instead use QMetaObject's
auto-connection facilities to connect the OK button's clicked() signal
to a slot in our subclass. uic automatically generates code in the
dialog's setupUi() function to do this, so we only need to declare and
implement a slot with a name that follows a standard convention:
void on_<object name>_<signal name>(<signal parameters>);
That is the most likely reason why your combobox started to not connect.
If it wasn't that you can see the output of every explicit connect call when they fail based on naming:
QObject::connect(ui->comboBox, SIGNAL(misspelled_signal()), this, SLOT(non_existent_slot()));
And you will get very useful output in your Application Output tab at runtime to help diagnosis the errors.
Hope that helpls.

Qt 5 - How to send data back from child dialog in real time

I have a settings dialog that has some settings that require another dialog to fully configure. My window shows a preview of the data as it's being tweaked by these settings. Upon clicking on the configuration button I launch another modal dialog with some knobs to twist to fine tune the particular setting.
I wish to send the result of the twisting of the knobs on the child dialog back to the parent dialog so that it can show the new preview data as the knobs on the child are being played with. The way I imagine it is I have a "refresh preview" function in the parent that is called after modification of it's data preview member variables. The question is, how do I do this? How can I access getters/setters from the parent dialog as a modal child dialog? If I do access them will the preview change or will it be blocked because of the modality of the child?
Thank you!
In Qt world, it is generally encouraged to exploit the Signal/Slot mechanism. In short, classes can send signals when something changes within that class. And slots can receive such signals provided we notified the receiving classes appropriately.
Let us look at how we can do it for our present case.
In our settings dialog constructor, we include this code (assumption is that you display the "another" dialog when a button is pressed):
Dialog *dialog = new Dialog();
connect(dialog->dial(), &QDial::valueChanged, this, &QSettingsDialog::changeTemp);
Code walkthrough:
Our QDialog has been constructed with a QDial object, dial. We access that member pointer with dialog->dial().
We tie the signal that emits the value changed on the dial to the slot called changeTemp that receives the value changed and sets the display widget on the settings dialog (parent) accordingly.
The changeTemp method might be like so:
void QSettingsDialog::changeTemp(int val)
{
lineEdit->setText(QString::number(val));
}
Notes:
You need to declare the Q_OBJECT macro on all classes that need to implement Signals and slot. In this case, both the settings dialog and the child dialog.
The above signal/slot signature is the new Qt5 signature. If you are on a version below 5.0, the signature is different. Refer to the docs.

Is there a way to determine if a top level Qt window has been moved?

I am trying to determine when the main window of my application has been moved. The main window is a standard QMainWindow and we've installed an eventFilter on the QApplication to look for moveEvents for the QMainWindow, but none are being triggered. For a variety of reasons, subclassing the QMainWindow isn't really an option.
Any thoughts on this, aside from starting a QTimer tto constantly check the position, would greatly be appreciated.
I guess it's better to install the event filter at the top-level window, instead of the application. However, if you still do not get QMoveEvents and you're working on Windows, you probably can override winEventFilter() and wait for WM_MOVE. Similar functionality might be available for Linux and Mac.
I usually do not recommend to break the platform-independence, but sometimes it might make sense.
Subclassing is really the best solution :-/
In the class that implements your top level windows you just overload this function:
virtual void moveEvent ( QMoveEvent * event )
From the documentation:
This event handler can be
reimplemented in a subclass to receive
widget move events which are passed in
the event parameter. When the widget
receives this event, it is already at
the new position.
The old position is accessible through
QMoveEvent::oldPos().
This should allow you to detect if your main window has moved. Why can't you subclass? Are you using an instance of QMainWindow directly? The usual use case is to subclass it anyway.

How do I create a custom slot in qt4 designer?

Whenever I use the signal/slot editor dialog box, I have to choose from the existing list of slots. So the question is how do I create a custom named slot?
right click on the main window and select "change signals and slots" and add a new slot.
It will appear in your signal slot editor.
This does seem to be possible in the version of Qt Designer 4.5.2, but it can't be done from the Signal/Slot Editor dock-widget in the main window.
This is what worked for me
Switch to Edit Signals/Slots mode (F4)
Drag and drop from the widget which is to emit the signal, to the widget which is to receive the signal.
A Configure Connection dialog appears, showing the signals for the emitting widget, and the slots for the receiving widget. Click Edit... below the slots column on the right.
A Signals/Slots of ReceivingWidget dialog appears. In here its is possible to click the plus icon beneath slots to add a new slot of any name.
You can then go back and connect to your new slot in the Configure Connection dialog, or indeed in the Signal/Slot Editor dockwidget back in the main window.
Caveat: I'm using PyQt, and I've only tried to use slots added in this way from Python, not from C++, so your mileage may vary...
Unfortunately this is not possible in Qt4.
In Qt3 you could create custom slots which where then implemented in the ui.h file. However, Qt4 does not use this file so custom slots are not supported.
There is some discussion of this issue over on QtForum
I am able to do it by:
In MainWindow.h, add the line:
public slots:
void example();
in the MainWindow class.
In MainWindow.cpp
void MainWindow::example() {
<code>
}
This doesn't seem to be possible in a simple way.
The designer only allows you to promote existing widgets to your own custom widgets. yet it doesn't allow you to connect the signals and slots of the class of promoted widgets.
The way this is possible is creating a plugin for the designer as is described here and in the pages that follow it.
The normal course of action is to promote a widget to your own class and then to connect it manually in your own code. this process is described here
It is not possible to do it, because it means you would add a slot to an existing Qt class like QPushButton which is not really the way to go.
You should create your own QWidget eventually by subclassing an existing one. Then integrating it into Qt Designer as a plugin as suggested. Having your own class allows you to add/modifiy the signals/slots available as you want.
Don't forget about the slot auto-connection features. There are a few drawbacks, like having to rename your function if you rename your widget, but we use those a lot at my company.
You can use the magic slot format of
void on_objectName_signal() {
// slot code here, where objectname is the Qt Designer object name
// and the signal is the emission
}
The connection to this method is established by the method connectSlotsByName and whenever the signal is emitted, this slot is invoked.
Maybe it'll help.
By default you have to choose from the existing list of slots. But you can add slot by right-clicking at you object in the list at right side of designer and choose "slot/signals" and add your custom slot/signal. After that, you can choose it in signal/slot editor.
click the widget by right button
promote the widget into a class you defined
click the widget by right button again
you will see that signal and slot is editable