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)
Related
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.
I have a MainWindow in qt with a Tab Widget attached, containing a tab called "tab_upload".
On this tab i got a label with the text "Genres" (it's a library application) with a "plus" button attached. I want to be able to get a new QLineEdit every time I click this button , positioned inline with the other ones. To get the right coordonates is easy but I'm not able to properly set the geometry of the new QLineEdit. It doesn't matter what I type in the setGeometry function, the QLineEdit will always appear in the center.
And also, if I press the button a second time I get an error saying
QWidget::setLayout: Attempting to set QLayout "" on QWidget "tab_upload", which already has a layout.
if(nr_genres < 4)
{
QLineEdit *newgen = new QLineEdit(ui->tab_upload);
int x = 5 + nr_genres * 90;
newgen->setGeometry(x,187,90,25);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(newgen);
ui->tab_upload->setLayout(layout);
}
Layouts are designed to have control over the positioning of widgets:
All QWidget subclasses can use layouts to manage their children. The QWidget::setLayout() function applies a layout to a widget. When a layout is set on a widget in this way, it takes charge of the following tasks:
Positioning of child widgets.
Sensible default sizes for windows.
Sensible minimum sizes for windows.
Resize handling.
Automatic updates when contents change:
Font size, text or other contents of
child widgets.
Hiding or showing a child widget.
Removal of child widgets.
You should read this documentation for information about adding widgets to layouts:
All the widgets will initially be allocated an amount of space in accordance with their QWidget::sizePolicy() and QWidget::sizeHint().
If any of the widgets have stretch factors set, with a value greater than zero, then they are allocated space in proportion to their stretch factor (explained below).
If any of the widgets have stretch factors set to zero they will only get more space if no other widgets want the space. Of these, space is allocated to widgets with an Expanding size policy first.
Any widgets that are allocated less space than their minimum size (or minimum size hint if no minimum size is specified) are allocated this minimum size they require. (Widgets don't have to have a minimum size or minimum size hint in which case the stretch factor is their determining factor.)
Any widgets that are allocated more space than their maximum size are allocated the maximum size space they require. (Widgets do not have to have a maximum size in which case the stretch factor is their determining factor.)
I think that the easiest way to manage widgets in layouts is to use the Design mode in Qt Creator, and specify a minimumSize and/or maximumSize for each widget, along with a sizePolicy. This way, you can see what happens and experiment with different values.
With regards to the error you're receiving, it is mentioned in the documentation for setLayout():
If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.
QWidget::setLayout: Attempting to set QLayout "" on QWidget
"tab_upload", which already has a layout.
You set new layout on widget that already contains layout from previous click on "plus" button. This problem can be solve by next way:
QLineEdit *newgen = new QLineEdit(ui->tab_upload);
QVBoxLayout *layout = static_cast<QVBoxLayout*>(ui->tab_upload->layout());
if(!layout) {
layout = new QVBoxLayout(ui->tab_upload);
ui->tab_upload->setLayout(layout);
}
layout->addWidget(newgen);
But you cannot directly set geometry for your QLineEdit because geometry was set by layout. If I understand the problem, this code must help you. It creates new QLineEdit after each click on "plus" button and append QLineEdit to existing layout.
In Qt, how can I have a widget which automatically sizes itself according to the size of it's children?
For example, if I have a QGroupBox which contains a QHBoxLayout which contains some QPushButtons, I would like the QGroupBox to automatically calculate it's size so that it is no bigger and no smaller than necessary to fit all of the QPushButtons.
Ideally I would like to be able to do this in Qt Designer so that I can create a .ui file which already knows how to size the QGroupBox, however I am also opening to deriving from a class inside a .ui file and doing the resizing manually.
I have tried placing the QGroupBox inside it's own layout (with and without a spacer) but this just resizes the QGroupBox to the smallest possible size so that none of the children are visible.
There are two things to pay attention to:
Set the size policies appropriately on the children in the groupbox. You literally need to think what the buttons can do - most likely, you do not want the buttons to either grow or shrink, so setting both of their size policies to Fixed is the right thing to do. You could, possibly, let the buttons expand horizontally, so the horizontal policy of MinimumExpanding is an option.
Set the size constraint on the layout in the groupbox to act according to your objective:
ui->groupbox->layout()->setConstraint(QLayout::SetMinAndMaxSize);
Of course, the groupbox will be inside of some layout in its parent window, but that doesn't matter.
You'll probably have the most luck by sub classing QGroupBox and overriding sizeHint or other sizing functions to loop through children and calculate the minimum bounding rectangle. Depending on how dynamic the group box is, managing connections to new widgets might be a small challenge.
I have an instance of QDialog, populated by widgets using code generated by uic. The dialog contains a few labels laid out vertically, and I am popping the dialog from time to time to show some text in these labels. The text can be multi-line and its length is not pre-determined. I set the vertical size policy to fixed, so the user can't drag it (doesn't make sense), but I also want the dialog to change its size before being shown to accomodate for the current size of the labels.
To this end, I was calling QWidget::adjustSize() on the QDialog before displaying it, but it doesn't work as expected. When the dialog is shown, it seems to retain the (wrong) size from the previous displaying, but when I click the mouse in the (disabled) vertical resize mode, the dialog suddenly "snaps" to the (correct) adjusted size.
Is there any way to make my dialog appear correctly?
EDIT: I tied rubenvb's advice, and ended up with this:
QSizePolicy free(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
QSizePolicy fixed(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
dialog->setSizePolicy(free);
dialog->adjustSize();
dialog->setSizePolicy(fixed);
dialog->show();
Unfortunately, that didn't seem to change anything.
This isn't the answer you're hoping for, and it may not apply to what you're trying to do, however, the only way that I was able to adjust the dimensions of a QWidget at run-time was by handling the object's resizeEvent(..) method. This allowed me to calc the size of items based upon the font being used, number of lines, available space, etc., and then adjust their size accordingly before passing the 'event' on to the base resizeEvent(..) method.
My approach used a single QWidget container within a window, below a header, above a footer status area, and to the right of a column of menu buttons. The widget container, inside the resizeEvent() call, would look at the objects it was going to display, calculate the font heights being used, and then resize some items according to their dimensions (because of how the style sheet selected fonts and colors, etc) and then adjust the sub-widget dimensions before allowing the container widget to get the resizeEvent() message.
So I wasn't so interested in setting a window size, but I think the container QWidget might work the same way? I was more interested in setting the dimensions to some asthetically pleasing size, depending upon the dimensions of the display.
Hope you find that helpful.
Do everything in the right order:
Dialog is not shown. Dialog is resizeable.
Calculate new size, set new size.
Set dialog to not-resizeable.
Show Dialog.
Hide dialog, go to step one.
I want to place some widgets in a parent widget in some random places, like one button at Point (10,10) and another at (15,40), etc. How to achieve this?. QGridLayout is pushing everything into row column style. But I want to put the widgets whereever I want,Can anybody help me?
If you really want to set absolute positions, I would ignore using a layout altogether. You can manually set the positions of elements by using the move() function or the setGeometry() function.
QWidget *parent = new QWidget();
parent->resize(400, 400);
QPushButton *buttonA = new QPushButton(parent);
buttonA->setText("First Button");
buttonA->move(10, 10);
QPushButton *buttonB = new QPushButton(parent);
buttonB->setText("Second Button");
buttonB->move(15, 40);
Side note: I would avoid setting absolute positions of elements in Qt. Why? Well, Qt tries to be a platform-independent GUI library. On different platforms, a lot of display things can change (i.e. font size of text in push buttons) so the size of your actual push buttons can vary to accommodate large or smaller font sizes. This can throw off your meticulously spaced push buttons is you use absolute positions as in the example above.
If you use layouts, overlapping buttons or buttons falling off the edge of your window can be avoided.
You can see my answer for overlay button in QT: Qt Widget Overlays. This may help you to achieve what you want.