问题
I'm using PySide/PyQt, but this is a general Qt question.
Is there a way to set up a QFormLayout so that labels are centered vertically without having to explicitly create the QLabel's and set their vertical size policy to expanding first? When the widget in column 2 is taller than my label, I want my label to be centered vertically with the widget, rather than aligned with it's top...
Here's an example script that demonstrates the problem. I've colored the labels red to better demonstrate their size behavior.
from PySide import QtCore, QtGui
app = QtGui.QApplication([])
widget = QtGui.QWidget()
widget.setStyleSheet("QLabel { background-color : red}")
layout = QtGui.QFormLayout()
layout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
layout.setLabelAlignment(QtCore.Qt.AlignCenter)
editor1 = QtGui.QLineEdit()
editor1.setFixedSize(300, 100)
editor2 = QtGui.QLineEdit()
editor2.setFixedSize(300, 100)
layout.addRow('Input', editor1)
layout.addRow('Longer Named Input', editor2)
widget.setLayout(layout)
widget.show()
app.exec_()
Here's the outcome:
Here's an example that demonstrates the desired result by explicitly creating QLabel's and giving them an expanding size policy:
from PySide import QtCore, QtGui
app = QtGui.QApplication([])
widget = QtGui.QWidget()
widget.setStyleSheet("QLabel { background-color : red}")
layout = QtGui.QFormLayout()
layout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
layout.setLabelAlignment(QtCore.Qt.AlignCenter)
editor1 = QtGui.QLineEdit()
editor1.setFixedSize(300, 100)
editor2 = QtGui.QLineEdit()
editor2.setFixedSize(300, 100)
label1 = QtGui.QLabel('Input')
expand = QtGui.QSizePolicy.Expanding
label1.setSizePolicy(expand, expand)
label2 = QtGui.QLabel('Longer Named Input')
label2.setSizePolicy(expand, expand)
layout.addRow(label1, editor1)
layout.addRow(label2, editor2)
widget.setLayout(layout)
widget.show()
app.exec_()
And here's that outcome...
I've tried QFormLayout.setLabelAlignment()
which doesn't appear to help. The docs even mention that setLabelAlignment only does the horizontal alignment of the labels (and even then doesn't appear to do centered, just left or right).
As an aside, this lead me to also try to set the horizontal alignment to centered, but that proved even harder since the labels don't expand horizontally to fill the space (small labels don't expand to match the biggest label). The only way I could get horizontally centered labels was to explicitly find the width of the biggest label, after showing the widget, then set all other labels to have the same width...
labels = [layout.itemAt(i*2).widget() for i in range(layout.rowCount())]
max_width = max(label.width() for label in labels)
for w in labels:
w.setFixedWidth(max_width)
w.setAlignment(QtCore.Qt.AlignCenter)
Which results in this:
Is there anything I'm missing at the QFormLayout level that will center the labels? Do I have to make QLabels and set to expanding or turn on expanding after the fact (like below)? Thanks for any ideas!
expand = QtGui.QSizePolicy.Expanding
labels = [layout.itemAt(i*2).widget() for i in range(layout.rowCount())]
for w in labels:
w.setSizePolicy(expand, expand)
回答1:
I don't think there is an elegant solution to your problem. From QFormLayout's source code:
void QFormLayoutPrivate::arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect)
{
// [...]
if (label) {
int height = layouts.at(label->vLayoutIndex).size;
if ((label->expandingDirections() & Qt::Vertical) == 0) {
/*
If the field on the right-hand side is tall,
we want the label to be top-aligned, but not too
much. So we introduce a 7 / 4 factor so that it
gets some extra pixels at the top.
*/
height = qMin(height,
qMin(label->sizeHint.height() * 7 / 4,
label->maxSize.height()));
}
[1] QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
int x = leftOffset + rect.x() + label->layoutPos;
[2] if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
[ ] x += label->layoutWidth - sz.width();
[ ] QPoint p(x, layouts.at(label->vLayoutIndex).pos);
// ### expansion & sizepolicy stuff
label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
}
// [...]
}
What do we see here?
- [1] Labels do not stretch horizontally
- [2] Labels can only be aligned left (by default) or right
So you have to either somehow manually synchronize labels' widths (e.g. set fixed one) or abandon QFormLayout
and use QGridLayout
instead.
回答2:
"[2] Labels can only be aligned left (by default) or right" - I don't believe this is true.
Your code doesn't run for me, so I can't test your exact code. However, this method works for other widgets: notice the use of |
to separate the various positional commands.
label2.setAlignment(PyQt5.QtCore.Qt.AlignLeft|PyQt5.QtCore.Qt.AlignVCenter)
I get this is a few years old, so you've probably come up with another way, but this method works well for me.
来源:https://stackoverflow.com/questions/34644808/set-vertical-alignment-of-qformlayout-qlabel