Modifying the QDockWidget default snap locations? - c++

I am trying to model a UI from a wxWidgets application to QT. However, in the original application they have Dock Widgets that can snap in place and move around except for occupying the main window.
Every box appears to be a dock widget except for the main window. And if I want to move the Datasets window (top left) to the right of the Output Adjustment window I can:
So now my goal was to try and get the UI in QT to at least accomplish the dock widgets on the left side of the main widget. Which in my case, I was able to at least get the width and the height with some trouble to show up the same. However, I cannot create a QDockWidget like the Output Adjustment and have it snap next to the others. And the other problem comes when I try to move a dock widget it will not snap to the right or the left of the other widgets.
This is where I have my problems. I cannot snap it to either side of the dock widgets. Is this something that will need to be hard coded? I know I have seen other examples online that look awfully similar to this layout. However they are all hard coded. And it would be a lot more simple if I could just use the creator to add the sliders and toolbars as time goes on. And if it is not something I have to hard code, how do I modify the locations on where my widgets can snap? I tried to make a grid layout, however the widgets do not go into the grid.

By enabling dock nesting in your main window you can achieve a more flexible placement of the dock widgets, including positioning the dock widgets side-by-side. In Qt Designer, select the main window and in the Property Editor panel mark the dockNestingEnabled check box (present in the QMainWindow section). Alternatively, you can achieve the same result by calling the method QMainWindow::setDockNestingEnabled in your code.
If you want your application to start with dock widgets arranged side-by-side as in your reference application, you have to resort on the method QMainWindow::splitDockWidget. For example, you can create an initial arrangement in Qt Designer such as the one depicted below.
Next, you can rearrange the dock widgets in the main window constructor code,
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// Changes the dock widgets arrangement.
splitDockWidget(ui->dock1, ui->dock3, Qt::Orientation::Horizontal);
splitDockWidget(ui->dock1, ui->dock2, Qt::Orientation::Vertical);
}
which would produce the result below.

Related

Is there a way to attach or anchor two QWidgets together?

I'm getting started with Qt and decided to build a full-screen text editor. I want to have a button (button with arrow in screenshot) attached to a QDockWidget which opens and closes it so the button is always visible to the right side of the screen and stay anchored to it when dock is visible or resized.
My current app is a simple fullscreen textEdit set to centeralwidget in Mainwindow.
I haven't found a way to do this yet with layouts or existing addAnchor() functions so any help or direction is appreciated.
You can achieve what you want by using a container for your text edit and the button. A QWidget instance can be used as an "invisible"*** container for other widgets.
So in Qt Designer you add a widget as a central widget of the main-window, inside this widget you add the text edit and the button, then you set a vertical layout for this container widget.
Don't forget to restrict the docking widget to only dock to the right side, you can do that with: dock->setAllowedAreas(Qt::DockWidgetArea::RightDockWidgetArea); //assuming dock is the pointer to your QDockWidget.
In case you want the dockWidget to be able to dock to any side and the button to follow, you can do that too, but it get a little bit more complicated. Basically you need to connect a slot to dockLocationChanged of your dockWidget and based on where it's docked you need to set-up a new layout for the container widget to be vertical or horizontal and the order of the textEdit and the button based on the side the dock happened.
LE:*** you will most likely need to set the margins you want, since both the widget and it's layout can have them and the actual content might have higher spacing than you want.

How to resize QPlainTextEdit widget when displayed

I have a QT GUI application, it has a vertical layout all the controls expand to fill the layout. If I add a QTextBox to the layout it has a fixed size (too big), I can change this in the designer or in code (in the MainWindow constructor)
m_textEdit->setMaximumHeight(3 * RowHeight);
but then it seems it is fixed permanently. I want to make it bigger when it has focus.
I have tried css
m_textEdit->setStyleSheet("QPlainTextEdit:focus{max-height: 400px}");
I have tried the resize function which is called in an action
m_textEdit->resize(m_textEdit->width(), 3 * RowHeight);
also doesn't resize once displayed.
I also thought that maybe I could put it in a splitter layout which would then be resizeable, but then the controls didn't expand with the window size.
Any ideas anyone?
You can change the widget size dynamically depending on the focus. When it's enterred, make the size bigger. When it's left, make the size smaller.
There are multiple ways to do this. In my opinion, the cleaner and easier way is by installing an event filter to your widget.
In this event filter, you will handle the QEvent::FocusIn and QEvent::FocusOut to change the size of your widget.
The CSS change is not the way to go in your case, neither is the resize.
The more convenient way is by changing the width/height using minimum, fixed, maximum).
It's up to you to decide which strategy, if you want to set the size using QWidget::setFixedXXX, or some QWidget::setMaximumXXX, QWidget::setMinimumXXX method. I like the Fixed one, but it really depends on your application style, and your layout context.
Official doc on event filter : (http://doc.qt.io/qt-5/qobject.html#installEventFilter).
The way I did this in the end is to add a QLabel and a QTextEdit to the form, then I right click on form and layout->'break layout' (why, I don't know!), then I select both widgets and add them to a vertical splitter layout (by right clicking form and layout->'vertical splitter'). Then I right click on form and add a vertical layout which then sets the all important layout to the MainWidget and lets the controls scale with the window size (the red warning icon disappears from the mainwidget). To get the vertical proportions I want at startup I have to also add the following code
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QList<int> sizes;
sizes << 1000 << 1;
ui->splitter->setStretchFactor(0,1000);
ui->splitter->setStretchFactor(1,1);
}
I also have to set the size policy to expanding on the widgets (not sure this is required)

Qt/C++ Technique To Show Inline Dialog

I have QtCreator 5.5 for the Mac, using C++, and I'm new at this. I have a MainForm window. I want to show a dialog inside that but draw it separately in its own UI designer. Then, at runtime, my code will pull that other UI and show it inside that window.
Imagine for instance a main application window. You click a button and you need to see a confirmation dialog. Normally you could do that with a separate window. Instead, I want it to be inline at runtime, to show it like a widget on the main window.
Sure, I could draw my dialog on top my existing window in a widget, but that defeats the point where I want to be able to adjust it in its own designer window, and just load it as necessary in the main window when I need it.
What's the technique in QtCreator and C++ to do this?
Open QtCreator. This task can only be done through there.
Assuming you have a regular Qt Widget Application, you need to just add a QWidget control on the MainWindow's centralWidget in the UI Designer.
Next, click Edit in the UI Designer and then rightclick Forms. Choose Add New...
In the dialog that opens up, choose Qt > Qt Designer Form Class, and click Choose...
Select Widget and then go with the defaults on the rest. This creates a widget called Form, and the form.h and form.cpp will also be added to your project.
Now find the form.ui and open it in Qt Designer. Add a Stacked Widget Control on the QWidget form. Size it to the same size as the parent widget. Next, stick a Label Control on the Stacked Widget Control's first page. This label will be temporary just to prove that this works. You'll set it to the text of "Testing". Now close the designer.
Flipping back to your UI File of your Main Window, find that QWidget you added and rightclick it. Choose Promote... and a dialog box appears. In that dialog, set Promoted Class Name to Form and then set Header File to form.h. Leave everything else on defaults and click Add and then Promote.
You may be expecting to see an immediate change in your Main Window in that QWidget that you added previously. However, that's not how this works unfortunately. You only see the change at runtime. So, now you should Run your application in Qt Creator. You'll see when it runs that your widget now contains the contents of that form.ui component you created.
Now, here's where it gets interesting. You can now draw all your inline modal dialogs on that form.ui, just putting them on different pages of your Stacked Widget control. You can also set the properties of your widget so that the background of the QWidget container is opaque and dark (creating a background dimmer) and then, at runtime, resize the QWidget to the size of your Main Window. When you need to switch to a different dialog, you can use setCurrentWidget() or setCurrentIndex() on that StackedWidget item like so:
QStackedWidget *w = ui->widget->findChild<QStackedWidget *>("stackedWidget");
w->setCurrentIndex(1);
In that example, I had a QWidget control on my MainWindow named simply widget. I then found the control on it called stackedWidget. Once I had it, I used the setCurrentIndex(x) method on it to change the page of that widget to show the one I needed. Remember that this is a zero-based index. So, (1) would be page 2.
QMainWindow::setCentralWidget
Inside your QMainWindow constructor add:
MyDialogClass myDialog = new MyDialogClass();
setCentralWidget(myDialog);

How to set Focus on a specific widget

I'm trying to implement GUI with various widgets for OpenGL project. I have a main widget for drawing the scene. The OpenGL widget is associated with Key and Mouse events, therefore the focus should always be on it. I've noticed if I click on say a push button, then the focus is moved to this button which means the focus is no longer associated with OpenGL widget. Clicking the widget by the mouse is not changing the focus. One of the solution is to turn off the focus for all widgets except the OpenGL widget in the GUI as follows
ui->processButton->setFocusPolicy(Qt::NoFocus);
ui->quitButton->setFocusPolicy(Qt::NoFocus);
ui->clearButton->setFocusPolicy(Qt::NoFocus);
ui->textEdit->setFocusPolicy(Qt::NoFocus);
ui->groupBox->setFocusPolicy(Qt::NoFocus);
if I have many widgets, then this solution is annoying especially if I add widgets later on. My question is is there a solution to set the focus on a specific widget?
Your solution is fine, you just shouldn't be enumerating widgets manually:
// C++11
for (auto widget : findChildren<QWidget*>())
if (! qobject_cast<QOpenGlWidget*>(widget)) widget->setFocusPolicy(Qt::NoFocus);
// C++98
foreach (QWidget * widget, findChildren<QWidget*>())
if (! qobject_cast<QOpenGlWidget*>(widget)) widget->setFocusPolicy(Qt::NoFocus);

How can I insert QDockWidget as tab

I have a lot of widgets in my application and I know I can drag them during runtime and place over another widget in order to merge them (both widgets are on same place and there are tabs under them which I can use to switch them).
How can I insert QDockWidget like this programmatically from start?
For example I want to add 2 QDockWidgets to bottom that are tabbed so that they are in same area and I can tab-switch them
If you want to layout two or more dock widgets as tabbed windows, you can either drag one dock widget over the other (as you properly described), or do that programaticaly using QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second) function. As the function description says:
Moves second dock widget on top of first dock widget, creating a
tabbed docked area in the main window.