I set a QMainWindow with two layouts, called A and B, in a Pyqt4 app written in Python 3.5
They usually display as shown in this schema:
But at some point, something in Layout B makes wider. Therefore Layout B makes wider too, overlapping Layout A, which remain partially hidden:
Could anybody please give me a hand to find a solution to this behaviour?
I would like to lock Layout A and B widths somehow to avoid this issue.
Without seeing your code, I suspect you add both layouts directly to your main window, without putting them into a main layout that would control their resizing. This way you're creating unnecessary problems, as you need to manage the layout's position and size manually. Read more in the Qt docs.
To solve this, you just add a QHBoxLayout to the main window, then the child layouts to that using addLayout() with an appropriate stretch factor. Here's an example in C++ (untested) to illustrate the necessary steps:
QHBoxLayout* mainLayout = new QHBoxLayout();
QGridLayout* childLayout0 = new QGridLayout();
QGridLayout* childLayout1 = new QGridLayout();
//Add widgets to the child layouts
mainLayout->addLayout(childLayout0, 2);
mainLayout->addLayout(childLayout1, 1);
mainWindow->setLayout(mainLayout);
Related
I want to have a small QFormLayout that grows to fill its parent widget.
I created a new .ui file using the QWidget template in Qt Designer. I put a QFormLayout inside that 'window', then put some controls inside that QFormLayout.
This all works reasonably well, but the QFormLayout always stays at the size I set in Qt Designer. I would like the QFormLayout to fill its parent widget and grow/shrink with it.
How can I accomplish that?
In Designer, activate the centralWidget and assign a layout, e.g. horizontal or vertical layout.
Then your QFormLayout will automatically resize.
Always make sure, that all widgets have a layout! Otherwise, automatic resizing will break with that widget!
See also
Controls insist on being too large, and won't resize, in QtDesigner
I found it was impossible to assign a layout to the centralwidget until I had added at least one child beneath it. Then I could highlight the tiny icon with the red 'disabled' mark and then click on a layout in the Designer toolbar at top.
The accepted answer (its image) is wrong, at least now in QT5. Instead you should assign a layout to the root object/widget (pointing to the aforementioned image, it should be the MainWindow instead of centralWidget). Also note that you must have at least one QObject created beneath it for this to work. Do this and your ui will become responsive to window resizing.
You need to change the default layout type of top level QWidget object from Break layout type to other layout types (Vertical Layout, Horizontal Layout, Grid Layout, Form Layout).
For example:
To something like this:
I have a simple QSplitter with a few widgets thrown in:
...
actions_splitter = QSplitter(
Qt.Horizontal,
frameShape=QFrame.StyledPanel,
frameShadow=QFrame.Plain
)
actions_splitter.addWidget(self.systems)
actions_splitter.addWidget(self.events)
actions_splitter.addWidget(self.compass_widget)
actions_splitter.setChildrenCollapsible(False)
...
The resulting splitters function perfectly fine, in that I can hover my mouse over their position, see the cursor change, and drag them around and change the sizes of the neighboring widgets.
The problem is that the handles themselves, the QSplitterHandles, absolutely refuse to have any visual modifications stick to them.
I have tried style sheets:
handle = actions_splitter.handle(0)
handle.setStyleSheet("{background-color: red}")
I have tried adding layouts with widgets to them:
handle = actions_splitter.handle(0)
layout = QHBoxLayout()
widget = QPushButton("HANDLE")
layout.addWidget(widget)
handle.setLayout(layout)
And absolutely nothing is doing anything to change how these handles appear. The only "visual" thing I can change is their width, and that's via QSplitter.setHandleWidth().
Someone please point out the painfully, stupidly obvious thing I'm missing here so I can get on with my life.
Premise
QSplitterHandle is one of the few very specific widgets that don't seem to follow generic QWidget "rules"; the reason is pretty simple: its aim is normally limited to the usage it's intended for, which is being a QSplitter child.
Then, you have to consider that, while pretty "liberal", the stylesheet syntax follows basic but important rules, it depends on the underlying QStyle in use and its behavior might change whenever a child widget is very dependant on its parent, as in this case.
First of all, there's a conceptual problem in your approach: the stylesheet syntax is wrong, as you're trying to use a selector-like syntax (using {braces}) without specifying a selector. With a syntax like that, the stylesheet won't be applied anyway, even with much more "standard" widgets.
But that's not enough. The QSplitter handle() documentation explains an important point (emphasis mine):
Returns the handle to the left of (or above) the item in the splitter's layout at the given index, or nullptr if there is no such item. The handle at index 0 is always hidden.
Even if your syntax were correct, it wouldn't have worked anyway since you tried to apply the stylesheet to the first (hidden) handle.
So, theoretically, the correct syntax should've been the following:
self.splitter.handle(1).setStyleSheet("background-color: red;")
even better:
self.splitter.handle(1).setStyleSheet(
"QSplitterHandle {background-color: red;}")
or, for all handles:
self.splitter.setStyleSheet(
"QSplitterHandle {background-color: red;}")
On the other hand, since QSplitterHandle is a very peculiar widget, its color properties are applied in different ways according to the currently applied QStyle, even when a correct syntax is used. Remember that stylesheets are overrides to the current QStyle, which means that the QStyles states the painting rules, and applies the eventual stylesheet according to those rules.
For instance, while the "windows" style uses the background color rule of the stylesheet to draw the actual background of the handle, the fusion style uses the background color to draw the "dots" of the splitter only.
As with other complex widgets (like QComboBox or QAbstractItemView), you need to use specific selectors for sub-controls, as clearly explained in the QSplitter stylesheet documentation; using the selector you ensure that the color rule is applied to the handle as a whole, no matter the style in use:
self.splitter.setStyleSheet("QSplitter::handle {background-color: red}")
I'm using PySide2 to write a gui (witout QtDesigner).
The mainwindow contains plots and some other widgets. Through a menu option I want to open a side panel widget. The way I want it to work is that the whole window simply grows to contain that new widget without changing the size of anything else in the main window. How can this be done?
Currently the widget is just added to the central layout with addWidget, I've also tried making it a QDockWidget but it is still resized (and anyway I would like to avoid the extra fluff that comes with having a DockWidget).
So I have
---------
|content|
---------
which should turn into
-------------
|new|content|
-------------
but currently I get
---------
|new|cnt|
---------
It's hard to do well on the "client" side of Qt; this would really belong within Qt itself. I have implemented a slightly more general variant of this a couple of years ago, and just to make it work well across Windows, Mac and KDE, the code ballooned to over a thousand lines to cover all the icky corner cases, with another thousand for the test harness. It was surprisingly hard to implement the tests - especially on X11, where there was no way around using native X APIs to verify intended behavior. I got rid of that monstrosity soon later - the effort was unnecessary.
You can have the side panel as a separate top-level frameless widget that moves itself so that its top-right corner is aligned with the top-left corner of the content window, and resizes itself vertically to match the vertical size of the content window. You can of course make it slightly shorter (vertically) while still center-aligning it vertically with the content window.
You'd want to capture the resize events of the content window to do this: the side panel should install itself as an event filter for the content window.
You'll want the side panel to be a Qt child of the content window, but you also need to make it a top-level window, i.e. set the Qt::Window flag on it, so that it becomes top-level and not a sub-widget of the content window.
I've got a GUI in PyQt that does the following:
The main window is a grid layout (2 columns and 3 rows). This is the scheme (soory I can't post images yet):
Now, when resizing the Main Window I'd like the QTableView widgets to be resized. However, it happens otherwise:
And the tables stay almost fixed in size (but every size-fixing property is set not to fix anything), they just expand for about 50 pĂxels. I've tried changing the main layout to a horizontal layout and then putting vertical layouts there but no change. I'm designing the GUI with the QtDesigner as I have no clue on how to doing it by hand-writing the code, and I need to export it to python.
What's the property determining which layout gets expanded and which one not?
I fixed it! As there were some LineEdits on the left side, they had to expand too. Setting its expanding policy to "fixed" or setting a maximum fixed it.
Thanks everybody for the help and dont worry, i'm going to learn to handwrite Qt GUIs soon.
I am using QTDesigner to design an application (I am trying my hand at a dual pane file manager). I can't figure out how to have the 2 widgets side by side so that they both resize when I resize the application
A layout, as JRazor mentioned, is a good solution if you want your Tree Views to have always same size. If not, use a QSplitter
From the Qt documentation:
A splitter lets the user control the size of child widgets by dragging
the boundary between them.
QSplitter *splitter = new QSplitter(parent);
QListView *listview = new QListView;
QTreeView *treeview = new QTreeView;
splitter->addWidget(listview);
splitter->addWidget(treeview);
EDIT
Sorry I didn't notice that you are actually looking for a python solution. I have provided a C++ example code, but I believe that it's not that big difference doing it with python.
Use layout:
layout = QHBoxLayout(self)
layout.addWidget(left_tree)
layout.addWidget(right_tree)
If you want use QtDesigner: http://doc.qt.io/qt-4.8/designer-layouts.html