Issue
How to find the number of rows and columns in QGridlayout ?, In my code, I have Buttons arranged in QGridLayout. Now I need to find out the total number of columns and the total number of rows.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Widget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QGridlayout")
self.btn1 = QPushButton("Button_1")
self.btn2 = QPushButton("Button_2")
self.btn3 = QPushButton("Button_3")
self.btn4 = QPushButton("Button_4")
self.btn4.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.MinimumExpanding)
self.btn5 = QPushButton("Button_5")
self.btn6 = QPushButton("Button_6")
self.btn7 = QPushButton("Button_7")
self.btn8 = QPushButton("Button_8")
self.btn9 = QPushButton("Button_9")
self.gl = QGridLayout()
self.gl.addWidget(self.btn1,1,0,1,1,Qt.AlignCenter)
self.gl.addWidget(self.btn2,0,1,1,1)
self.gl.addWidget(self.btn3,0,2,1,1)
self.gl.addWidget(self.btn4,0,3,2,1)
self.gl.addWidget(self.btn5,1,0,1,2)
self.gl.addWidget(self.btn6,2,0,1,3)
self.gl.addWidget(self.btn7,3,0,1,4)
self.gl.addWidget(self.btn8,1,2,1,1)
self.gl.setRowStretch(4,1)
self.gl.setColumnStretch(2,1)
self.gl.setSpacing(1)
self.setLayout(self.gl)
print(self.gl.count())
# print(self.gl.rowcount())
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Solution
For basic usage, rowCount()
and columnCount()
will suffice, as already said in other answers.
Be aware, though, that the above will only be reliable for the following conditions:
- layout items (widgets, nested layouts, spacers) are always added continuously: for instance, grid layout allows adding an item at row 0 and another at row 10, even if they only occupy one row and no other item occupies the inner rows and even if no row spanning occurs in the middle;
- removal of items will never clear the row or column count, even if there is no item at or after the "last" row or column;
rowCount()
andcolumnCount()
will always return a number equal or greater than1
, even if the layout is empty;- considering the above, dynamic insertion of new items between existing ones can become quite messy;
To explain the above, consider the following example:
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
app = QApplication([])
window = QWidget()
layout = QGridLayout(window)
def addRow():
row = layout.rowCount()
label = QLabel(str(row))
label.setStyleSheet('border: 1px solid black;')
label.setMinimumSize(100, 30)
label.setAlignment(Qt.AlignCenter)
layout.addWidget(label)
def removeRow():
item = layout.itemAt(layout.count() - 1)
widget = item.widget()
if widget:
widget.deleteLater()
layout.removeItem(item)
for r in range(4):
addRow()
window.show()
QTimer.singleShot(1000, removeRow)
QTimer.singleShot(2000, addRow)
QTimer.singleShot(3000, removeRow)
QTimer.singleShot(4000, addRow)
app.exec()
The steps are the following:
- create the first 4 labels; note that the label text shows the
rowCount()
before adding it to the layout: the text of the first label is "1", even if, at that moment, the layout is empty; the second label shows again "1", since the layout now does have an item at row 1; - remove the last label ("3") and the layout item corresponding to it; the layout now theoretically has only 3 rows; the layout item removal is actually pointless for this, since it won't change the result (I only added it for explanation purposes);
- add another label; the new label displays "4", not "3";
- remove the "4" label; the layout theoretically has only 3 rows again;
- add a further label, which displays "5";
While counter-intuitive, this behavior is done just for performance, simplicity and consistency reasons: the row/column count is static, and always based on the greatest row/column index (plus possible spanning if greater than 1). While adding/removing items within the same function call, the grid size must be consistent (and as fast as possible). Also, the computation of layout managers is possibly quite important for performance, as each layout has to query its own child items, ask about their size hints and policies and then make complex computations to set their geometries, and all this becomes recursive for nested layouts.
If you want a more dynamic approach you can still implement it, for example with this simple (but costly) function:
def gridLayoutRealRowCount(layout):
rows = 0
for i in range(layout.count()):
row, _, span, _ = layout.getItemPosition(i)
rows = max(1, row + span)
return rows
Now you can replace the row = layout.rowCount()
used before with the above function:
def addRow():
row = gridLayoutRealRowCount(layout)
# ...
And you'll get a more consistent result: the labels will always show "0", "1", "2" (and eventually "3"), even after removing the last item.
You can also make a "shim" (or "pseudo-polyfill") if you create a monkey patch after the very first Qt import; assuming all your Qt imports are consistent, you can use it from anywhere:
def gridLayoutRealRowCount(layout):
rows = 0
for i in range(layout.count()):
row, _, span, _ = layout.getItemPosition(i)
rows = max(1, row + span)
return rows
def gridLayoutRealColumnCount(layout):
columns = 0
for i in range(layout.count()):
_, column, _, span = layout.getItemPosition(i)
columns = max(1, columns + span)
return columns
QGridLayout.getRowCount = gridLayoutRealRowCount
QGridLayout.getColumnCount = gridLayoutRealColumnCount
Which allows the following:
def addRow():
row = layout.getRowCount()
# ...
If you require high performance and you're not interested on a "rigid" grid layout, you should consider other options, like a QFormLayout or a nested vertical+horizontal layout.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.