I am attempting to do a HTML style grid layout in Qt using this example here: https://gist.github.com/Cysu/7461066. It nearly does what I want, however when I put it into a scroll area it seems to collapse down to a minimum size and not want to expand to the full size of the scroll area. I did see that in the documentation you need to set the sizeConstraint in the layout to SetMinAndMaxSize, however this did not seem to fix it.
How can I get the layout to occupy the maximum size inside of the scroll area?
Here's a basic example, importing the class from the link above:
class App(QtWidgets.QDialog):
def __init__():
super().__init__()
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
grid = QtWidgets.QWidget()
grid_layout = FlowLayout()
grid_layout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize)
grid.setLayout(grid_layout)
scroll_area = QtWidgets.QScrollArea()
scroll_area.setWidget(grid)
layout.addWidget(scroll_area)
# layout.addWidget(grid) # adding the widget the the parent layout works just fine...
for i in range(25):
grid_layout.addWidget(QtWidgets.QLabel(f"Label {i}"))
Related
I am trying to have a QTreeView fit into a horizontal layout perfectly.
My layout setup looks like this:
I want the horizontal width of Vertical Layout 1 to be defined by the required widths of the QTreeView Column Headers. In other words the Vertical Layout 1 should stretch horizontally to make sure its width always exactly matches the width required by QTreeView column headers. Therefore the layout stretch factors of the topmost horizontal layout are set to (0,1) so that the Vertical Layout 1 does not stretch and Vertical Layout 2 does.
This is what it looks like in action:
The good news is that when QTreeView items are expanded, the headers also expand and in turn the Vertical Layout 1 stretches accordingly.
The problem is however highlighted on this picture:
For some reason there is redundant unused space within QTreeView itself, which has constant width in both collapsed and expanded states.
All the headers within the QTreeView are set to Resize to Contents, the Size policy of the QTreeView is set to 'AdjustToContents' and last header section stretch is set to False, which I think is correct:
self.accountsTree.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
self.accountsTree.header().setStretchLastSection(False)
self.accountsTree.header().setSectionResizeMode(
AccountTreeColumns.COLUMN_NAME,
QHeaderView.ResizeMode.ResizeToContents,
)
self.accountsTree.header().setSectionResizeMode(
AccountTreeColumns.COLUMN_BALANCE,
QHeaderView.ResizeMode.ResizeToContents,
)
self.accountsTree.header().setSectionResizeMode(
AccountTreeColumns.COLUMN_BALANCE_BASE,
QHeaderView.ResizeMode.ResizeToContents,
)
self.accountsTree.header().setSectionResizeMode(
AccountTreeColumns.COLUMN_SHOW,
QHeaderView.ResizeMode.ResizeToContents,
)
I am using PyQt 6.4 and Qt Designer.
I tried playing around with stretch factors, layout constraints and different header section resize modes, but everything I tried only led to worse results. I don't understand where the extra space comes from, other than that the setup works exactly how I want it to. I must be missing some setting somewhere but I can't seem to figure it out.
Thanks for any tips
I am working on a GUI that at one point should display a long horizontal ROI of a camera feed. For that I am writing a widget consisting of an ImageView that is using a ViewBox and an ImageItem and then add that widget to a constrained space on a layout of the GUI. My problem is that the image from the camera is not visible upon opening the window but 'hidden' outside of the field of view of the widget (a little bit down). Upon resizing the window, it appears centered.
This is how it looks after resizing before that it is where the arrow indicates
This is a minimal version of the display widget in question:
class CameraViewerWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.viewport = GraphicsLayoutWidget()
self.view = self.viewport.addViewBox(lockAspect=False, enableMenu=True)
self.img = pg.ImageItem()
self.view.addItem(self.img)
self.imv = pg.ImageView(view=self.view, imageItem=self.img)
layout = self.layout()
layout.addWidget(self.imv)
def update_image(self, image, auto_range=True, auto_histogram_range=False):
self.imv.setImage(image, autoRange=auto_range, autoHistogramRange=auto_histogram_range)
It is then added to the GUI via addWidget() and update_image() is called repeatedly using a QTimer.
Obviously the auto_range argument does not help here. I also tried to use the setLimits() and setRange() methods of the ViewBox but that also did not change the situation. I am suspecting that as I add this Widget to a contrained size on the layout of the main GUI (maximumSize = 100) the ImageView does not know how much space it has but I am not sure how to test that and a bit confused by the different coordinate systems used here. Did anyone encounter similar issues or is able to see my error here?
I am a GWT programmer trying to get to grips with using PlayN with Tripleplays gui library.
Having a little bit of trouble working out how to get a border layout filling up all the space of its container. (presumably with the middle space expanding to fill the available size)
BorderLayout border = new BorderLayout(3);
Group mainLayout = new Group(border);
mainLayout.setConstraint(AxisLayout.stretched());
Button Center= new Button("test");
Center.setConstraint(BorderLayout.CENTER);
mainLayout.add(Top);
mainLayout.add(Bottom);
mainLayout.add(Left);
mainLayout.add(Center);
Top Bottom and Left are similarly specified to BorderLayout.Left, top etc.
the whole thing is then added to the root screen with
_root.setConstraint(AxisLayout.stretched());
_root.add(0, mainLayout);
(_root itself just has a AxisLayout.vertical() ...which I am assuming makes it act somewhat like a gwt vertical panel)
At the moment the vertical space seems to be filled, but not the horizontal.
Any ideas where I am going wrong?
I would suggest to set
border.setConstraint(AxisLayout.stretched());
before adding border to mainLayout. This will tell mainLayout to strech this child widget.
I am having some trouble making a new QT widget fill all the available space.
I want to add a widget (a QGLWidget) to the verticle layout (mVisual) and have the layout resize so that mVisual occupies the maximal amount of area.
My layout looks as follows:
The code I have is
ui.setupUi(this);
mWidget = new glStream();
//mWidget->setMinimumHeight(480);
//mWidget->setMinimumWidth(480);
ui.mVisual->addWidget(mWidget);
The problem is that if I don't manually set the width or height I can't even see my widget when I add it!
The only thing I can think of is to perform some sort or arithmetic like parentSize-lytControlsSize, but this feels dirty and like MFC.
How can I layout my widgets so that one layout (mVisual) is minimal, while the other is maximal?
if you put your widget in a Layout, widget fill all available space in their parent area, and if you want to fill without margins, set Layout margins to 0.
I have a QScrollArea Widget, which starts empty;
It has a vertical layout, with a QGridLayout, and a vertical spacer to keep it at the top, and prevent it from stretching over the whole scroll area;
Elsewhere in the program, there is a QTextEdit, which when changed, has its contents scanned for "species" elements, and then they are added to the QGridLayout. Any species elements which have been removed are removed too. This bit works;
I have turned the vertical scrollbar on all the time, so that when it appears it does not sit on top of the other stuff in there. Note that the scroll bar is larger than the scroll box already though, despite not needing to be.
This is the problem. The scroll area seems to be preset, and i cannot change it. If i add more rows to the QGridLayout, the scroll area doesn't increase in size.
Instead, it stays the same size, and squeezes the QGridLayout, making it look ugly (at first);
And then after adding even more it becomes unusable;
Note that again, the scroll bar is still the same size as in previous images. The first two images are from Qt Designer, the subsequent 3 are from the program running.
If I resize the window so that the QScrollArea grows, then I see this:
Indicating that there's some layout inside the scroll area that is not resizing properly.
My question is; what do I need to do to make the scrollable area of the widget resize dynamically as I add and remove from the QGridLayout?
If you're coming here from Google and not having luck with the accepted answer, that's because you're missing the other secret invocation: QScrollArea::setWidget. You must create and explicitly identify a single widget which is to be scrolled. It's not enough to just add the item as a child! Adding multiple items directly to the ScrollArea will also not work.
This script demonstrates a simple working example of QScrollArea:
from PySide.QtGui import *
app = QApplication([])
scroll = QScrollArea()
scroll.setWidgetResizable(True) # CRITICAL
inner = QFrame(scroll)
inner.setLayout(QVBoxLayout())
scroll.setWidget(inner) # CRITICAL
for i in range(40):
b = QPushButton(inner)
b.setText(str(i))
inner.layout().addWidget(b)
scroll.show()
app.exec_()
The documentation provide an answer :
widgetResizable : bool
This property holds whether the scroll area should resize the view widget.
If this property is set to false (the default), the scroll area honors the size of its widget.
Set it to true.
Why don't you use a QListView for your rows, it will manage all the issues for you? Just make sure that after you add it you click on the Class (top right window of designer) and assign a layout or it wont expand properly.
I use a QLIstWidget inside a QScrollArea to make a scrollable image list
Try this for adding other objects to the list, this is how I add an image to the list.
QImage& qim = myclass.getQTImage();
QImage iconImage = copyImageToSquareRegion(qim, ui->display_image->palette().color(QWidget::backgroundRole()));
QListWidgetItem* pItem = new QListWidgetItem(QIcon(QPixmap::fromImage(iconImage)), NULL);
pItem->setData(Qt::UserRole, "thumb" + QString::number(ui->ImageThumbList->count())); // probably not necessary for you
QString strTooltip = "a tooltip"
pItem->setToolTip(strTooltip);
ui->ImageThumbList->addItem(pItem);
Update on Artfunkel's answer:
Here's a PySide6 demo that uses a "Populate" button to run the for loop adding items to the scroll area. Each button will also delete itself when clicked.
from PySide6.QtWidgets import *
app = QApplication([])
scroll = QScrollArea()
scroll.setWidgetResizable(True) # CRITICAL
inner = QFrame(scroll)
inner.setLayout(QVBoxLayout())
scroll.setWidget(inner) # CRITICAL
def on_remove_widget(button):
button.deleteLater()
def populate():
for i in range(40):
b = QPushButton(inner)
b.setText(str(i))
b.clicked.connect(b.deleteLater)
inner.layout().addWidget(b)
b = QPushButton(inner)
b.setText("Populate")
b.clicked.connect(populate)
inner.layout().addWidget(b)
scroll.show()
app.exec()