Skip to content
  • 0 Votes
    9 Posts
    2k Views
    A

    @KenAppleby-0
    I have an extremely stupid proof of concept that sort of does what I describe in the initial message, it's extremely rough and should not be considered a good idea by anybody, but here goes:

    from PyQt6.QtWidgets import QWidget, QPushButton, QGridLayout, QSizePolicy, QApplication from PyQt6.QtGui import QColor, QPalette from PyQt6.QtCore import Qt class BorderWidget(QWidget): def __init__(self, widget_id, side, layout=None, row=None, column=None): super(BorderWidget, self).__init__() self.widget_id = widget_id self.side = side self.layout = layout self.row = row self.column = column pal = self.palette() pal.setColor(QPalette.ColorRole.Window, QColor('white')) self.setAutoFillBackground(True) self.setPalette(pal) self.pressed = False def mousePressEvent(self, event): super(BorderWidget, self).mousePressEvent(event) print(f"Clicked on {self.side} border of widget {self.widget_id}") print(f"self.press is {self.pressed}") self.pressed = True self.last_x = event.globalPosition().x() self.last_y = event.globalPosition().y() def mouseReleaseEvent(self, event): self.pressed = False def mouseMoveEvent(self, event): if self.pressed and self.layout is not None: dx = event.globalPosition().x() - self.last_x self.last_x = event.globalPosition().x() dy = event.globalPosition().y() - self.last_y self.last_y = event.globalPosition().y() if dx != 0: if self.side in ['right', 'left']: new_stretch = max(1, self.layout.columnStretch(self.column) - dx) self.layout.setColumnStretch(self.column, int(new_stretch)) elif self.side in ['bottom', 'top']: new_stretch = max(1, self.layout.rowStretch(self.row) - dy) self.layout.setRowStretch(self.row, int(new_stretch)) class DraggableWrapper(QWidget): def __init__(self, widget, widget_id, main_layout, row, column): super(DraggableWrapper, self).__init__() self.layout = QGridLayout(self) self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.border_top = BorderWidget(widget_id, 'top', main_layout, row, column) self.border_bottom = BorderWidget(widget_id, 'bottom', main_layout, row + 1, column) self.border_left = BorderWidget(widget_id, 'left', main_layout, row, column) self.border_right = BorderWidget(widget_id, 'right', main_layout, row, column + 1) self.border_top_left_horizontal = BorderWidget(widget_id, 'topleft', main_layout, column) self.border_top_right_horizontal = BorderWidget(widget_id, 'topright', main_layout, column) self.border_bottom_left_horizontal = BorderWidget(widget_id, 'bottomleft', main_layout, column) self.border_bottom_right_horizontal = BorderWidget(widget_id, 'bottomright', main_layout, column) self.layout.addWidget(widget, 1, 1) self.layout.addWidget(self.border_top, 0, 1) self.layout.addWidget(self.border_bottom, 2, 1) self.layout.addWidget(self.border_left, 0, 0, 3, 1) # cover the corners self.layout.addWidget(self.border_right, 0, 2, 3, 1) # cover the corners self.layout.addWidget(self.border_top_left_horizontal, 0, 0) self.layout.addWidget(self.border_top_right_horizontal, 0, 2) self.layout.addWidget(self.border_bottom_left_horizontal, 2, 0) self.layout.addWidget(self.border_bottom_right_horizontal, 2, 2) border_width = 10 self.border_top.setFixedHeight(border_width) self.border_bottom.setFixedHeight(border_width) self.border_left.setFixedWidth(border_width) self.border_right.setFixedWidth(border_width) # apply size restrictions to corner border widgets to form L-shaped corners self.border_top_left_horizontal.setFixedSize(border_width, border_width) self.border_top_right_horizontal.setFixedSize(border_width, border_width) self.border_bottom_left_horizontal.setFixedSize(border_width, border_width) self.border_bottom_right_horizontal.setFixedSize(border_width, border_width) # Apply size policies self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) class MainWindow(QWidget): def __init__(self): super().__init__() layout = QGridLayout(self) layout.setSpacing(0) default_stretch = 300 layout.setRowStretch(0, default_stretch) layout.setRowStretch(1, default_stretch) layout.setColumnStretch(0, default_stretch) layout.setColumnStretch(1, default_stretch) widget1 = QPushButton("Button 1") wrapper1 = DraggableWrapper(widget1, '1', layout, 0, 0) widget2 = QPushButton("Button 2") wrapper2 = DraggableWrapper(widget2, '2', layout, 0, 1) widget3 = QPushButton("Button 3") wrapper3 = DraggableWrapper(widget3, '3', layout, 1, 0) widget4 = QPushButton("Button 4") wrapper4 = DraggableWrapper(widget4, '4', layout, 1, 1) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(wrapper1, 0, 0) layout.addWidget(wrapper2, 0, 1) layout.addWidget(wrapper3, 1, 0) layout.addWidget(wrapper4, 1, 1) if __name__ == '__main__': app = QApplication([]) mainWin = MainWindow() mainWin.setMinimumSize(800, 800) mainWin.show() app.exec()
  • 0 Votes
    6 Posts
    2k Views
    ODБOïO

    @Kyeiv said in Place items in GridLayout leaving empty column:

    anchors.horizontalCenter: parent.horizontalCenter

    you can't use "anchors" inside an item that is direct child of a QML Layout, you should see a warning for that.

    This will put the text exactly in the center

    GridLayout{ anchors.fill : parent columns : 3 Item{ Layout.fillWidth:true Layout.columnSpan : 3 Text{ text : "Hello" anchors.centerIn:parent } Button{ anchors.right:parent.right anchors.verticalCenter:parent.verticalCenter } } }
  • 0 Votes
    13 Posts
    2k Views
    jeremy_kJ

    A ListView appears to be a better match than the more complicated GridLayout and Repeater.

    ListView { delegate: Item { width: ListView.view.width height: childrenRect.height Text { anchors.right: parent.horizontalCenter text: modelData.firstPart + ":" } Text { anchors.left: parent.horizontalCenter text: modelData.secondPart } } }
  • 1 Votes
    3 Posts
    497 Views
    S

    I'm also looking for a solution to the same issue.

    I think what @plaristote meant was, let's say I have a custom QML component with a Label and a Button in a RowLayout:

    Custom.qml

    import QtQuick 2.11 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.3 Item { id: root implicitWidth: rowLayout.implicitWidth implicitHeight: rowLayout.implicitHeight property string text: "" RowLayout { id: rowLayout anchors.fill: parent Label { text: root.text } Button { id: button Layout.fillWidth: true Layout.fillHeight: true text: "Press me" } } }

    I want to put 2 Custom.qml items on top of each other:

    main.qml

    import QtQuick 2.11 import QtQuick.Window 2.2 import QtQuick.Layouts 1.3 Window { visible: true width: 640 height: 480 ColumnLayout { Custom {text: "Short label"} Custom {text: "Very very long label"} } }

    The output is the following:

    qt_wrong.png

    Instead I'd like the children of my Custom.qml item to be aligned like this:

    qt_good.png

    I could align the elements by setting a fixed preferredWidth to the Label of my Custom.qml, but I'd like to know if a more flexible solution exists.

  • 0 Votes
    9 Posts
    866 Views
    J.HilkJ

    @Slash200

    Gibt es in QML eine View die das freie einfügen von Items in eine Zelle ermöglicht, ohne dass die vorherigen Zellen ein Item haben?

    Nein, nicht das ich es kennen würde. Da musst du dir was eigenes Schreiben, was sich die Postion von allem Items merkt und ach entsprechend neu positioniert, wenn sich die Fenstergröße ändert zum Beispiel.

    Übrigens, hab das Beispiel erweitert über den "Add" Knopf kann man jetzt eines der freien "Dummy"-Elemente ersetzen

    Hattest du dir das so gedacht?

  • 0 Votes
    9 Posts
    2k Views
    SGaistS

    Great !

    The please mark the thread as solved using the "Topic Tools" button or the three doted menu beside the answer you deem correct so that other forum users may know a solution has been found :-)

  • 0 Votes
    2 Posts
    316 Views
    A

    I fixed it - so this is for anyone else having a similar issue. I'm not sure why this happened but in a RowLayout, I had a button that used Layout.prefferedWidth + Layout.prefferedHeight. relative to its parent - and this caused the error. Deleting the lines worked, but when I was checking with just 1 of them, I got a 'binding loop' error for the prefferedWidth - I'm guessing multiple of these caused it to crash.

  • 0 Votes
    4 Posts
    507 Views
    JKSHJ

    @Dexter99 said in Pyqt5 help on button and grid layouts.:

    The show is okay but now I want to add it in a grid layout.

    Please show us what you've tried.

  • 0 Votes
    8 Posts
    2k Views
    U

    Hi! With GridView you can set verticalLayoutDirection: GridView.BottomToTop and it populates items from bottom to up, works fine.

    However with GridLayout there seems to be no such property. One hack to achieve this behaviour with GridLayout would be to rotate the GridLayout component by 180 degrees and counter rotate its children accordingly. You can also use LayoutMirroring property to control left-to-right right-to-left behavior. Depending on what you are trying to achieve this might be a workaround for you.

    Here's example code, (click on window to switch between top-to-bottom and bottom-to-top):

    import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Layouts Window { width: 640 height: 480 visible: true title: qsTr("Hello World") GridLayout { LayoutMirroring.enabled: grid.rotation == 180 id: grid columns: 3 anchors.fill: parent rotation: 0 Text { text: "Three"; font.bold: true; rotation: grid.rotation } Text { text: "words"; color: "red"; rotation: grid.rotation } Text { text: "in"; font.underline: true; rotation: grid.rotation } Text { text: "a"; font.pixelSize: 20; rotation: grid.rotation } Text { text: "row"; font.strikeout: true; rotation: grid.rotation } } MouseArea { anchors.fill: parent onClicked: { if (grid.rotation == 0) grid.rotation = 180 else grid.rotation = 0 } } }

    Regards,
    Ulrich

  • 0 Votes
    4 Posts
    10k Views
    L

    First of all I am glad that you found a solution you're happy with.
    Nevertheless, I still recommend to use GridView. On the one hand, it probably reduces your amount of code, on the other hand, and most importantly, it's much more readable to you and every other developer, who might want to help you or needs some Inspiration, because he has the same problems as you have.

    To your question:

    On of the key features of Qml is property binding. So let's say you have

    import QtQuick.Controls 2.3 ApplicationWindow { id: root width: 600; height: 600 visible: true Rectangle { width: parent.width/2; height: parent.height/2 color: "blue" } MouseArea { anchors.fill: parent onClicked: { root.width -= 10; root.height += 10; } } }

    If you click the applicationWindow its width will be decreased by 10 and its height increased by 10. At the same time the rectangle's width will be decreased by 5 and its height increased by 5. That's because its size depends on the size of the applicationWindow and will be changed automatically.

    Same applies to your case. If the model changes its size, your ListView should notice this and update the list.

    Just in case you don't know (or if it's working in your case, didn't know how your model looks like) you can do:
    model: yourModelName.length
    or if it's a List of Arrays/Vectors
    model: yourModelName[index].length

    Index should be available through the outer ListView if I did understand you correctly.

    ListView { model: yourModel.length delegate: ListView { model: yourModel[index].length } }

    Probably there is no need to write an "getLengthOfDataVector" function, if you intended to do it like this. But maybe I missed something as I don't know how you model looks like exactly.

  • 0 Votes
    15 Posts
    6k Views
    MrKozmonM

    Checkout the answer I have given here:
    https://forum.qt.io/topic/105191/why-isn-t-a-qcombobox-positioned-correctly-in-a-layout

  • 0 Votes
    1 Posts
    593 Views
    No one has replied
  • 0 Votes
    2 Posts
    1k Views
    SGaistS

    Hi,

    There's one thing that's wrong, you should not put a layout on a QScrollArea but a widget. So the first thing to do is put your grid layout on a widget and then set that widget on the QScrollArea.

    IIRC the grid layout (as QVBoxLayout) will use by default the available space to layout the widget evenly

  • 0 Votes
    14 Posts
    4k Views
    Ni.SumiN

    @gabor53

    Please it as Solved .

  • 0 Votes
    2 Posts
    1k Views
    SGaistS

    Hi,

    You should put that QGridLayout inside a widget that you set on the QScrollArea. See QScrollArea::setWidget

  • 0 Votes
    15 Posts
    5k Views
    mrjjM

    @kshegunov
    I agree . must been something like that as now the effect
    is 100% as your experience. Even in designer.
    Sorry for the confusion.

  • 0 Votes
    6 Posts
    6k Views
    raven-worxR

    @IL
    here ya go

  • 0 Votes
    3 Posts
    3k Views
    R

    Hi @p3c0 ,

    thank you tor you trick!!

    I tried, and it works!!!

  • 0 Votes
    4 Posts
    2k Views
    SGaistS

    Shouldn't the legend be part of the plot ?