1.问题解释
我正在尝试使用Qt的QSplitter()
小部件。我在PyQt5中构建了一个非常简单的示例项目,其中在左侧显示了QSplitter()
并在右侧封装了QScrollArea()
的内容:
我已经给了QFrame()
和QScrollArea()
相等的拉伸因子,但是QFrame()
并没有平等地对待它们。 QSplitter()
总是获得最多的空间。我不知道为什么。
最小的,可重现的示例
只需将下面的代码复制粘贴到.py脚本中并运行它。我已经在Windows 10机器上运行带有PyQt5的Python 3.7。
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Scroller(QScrollArea):
'''
The Scroller(), will be first widget in the Splitter().
'''
def __init__(self):
super().__init__()
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
self.setStyleSheet("""
QScrollArea {
background-color:#fce94f;
border-color:#c4a000;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
""")
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 1. FRAME
self.__frm = QFrame()
self.__frm.setStyleSheet("QFrame { background: #ff25292d; border: none; }")
self.__frm.setMinimumHeight(100)
# 2. LAYOUT
self.__lyt = QVBoxLayout()
self.__frm.setLayout(self.__lyt)
# 3. SELF
self.setWidget(self.__frm)
self.setWidgetResizable(True)
return
class Frame(QFrame):
'''
The Frame(), will be second widget in the Splitter()
'''
def __init__(self):
super().__init__()
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
# 1. FRAME
self.setStyleSheet("""
QFrame {
background-color:#fcaf3e;
border-color:#ce5c00;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
""")
self.__lyt = QVBoxLayout()
self.__lyt.setAlignment(Qt.AlignTop)
self.__lyt.setSpacing(0)
self.__lyt.setContentsMargins(10, 10, 10, 10)
self.setLayout(self.__lyt)
return
class Splitter(QSplitter):
'''
The Splitter().
'''
def __init__(self, widg1, widg2):
super().__init__()
self.setOrientation(Qt.Horizontal)
self.addWidget(widg1)
self.addWidget(widg2)
self.setStretchFactor(0, 5)
self.setStretchFactor(1, 5)
return
def createHandle(self):
return QSplitterHandle(self.orientation(), self)
class CustomMainWindow(QMainWindow):
'''
CustomMainWindow(), a QMainWindow() to start the whole setup.
'''
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 600, 300)
self.setWindowTitle("QSPLITTER TEST")
# 1. OUTER FRAME
self.__frm = QFrame()
self.__frm.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.__frm.setStyleSheet("""
QFrame {
background-color: #eeeeec;
border-color: #2e3436;
}
""")
self.__lyt = QVBoxLayout()
self.__frm.setLayout(self.__lyt)
self.setCentralWidget(self.__frm)
self.show()
# 2. WIDGETS TO BE PUT IN SPLITTER
self.__widg1 = Scroller()
self.__widg2 = Frame()
# 3. SPLITTER
self.__splitter = Splitter(self.__widg1, self.__widg2)
self.__lyt.addWidget(self.__splitter)
return
if __name__== '__main__':
app = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Plastique'))
myGUI = CustomMainWindow()
sys.exit(app.exec_())
最佳答案
QSplitter不仅将拉伸因子作为参考,还考虑了sizeHint()。如果添加以下内容:
# ...
# 3. SPLITTER
self.__splitter = Splitter(self.__widg1, self.__widg2)
self.__lyt.addWidget(self.__splitter)
print(self.__widg1.sizeHint(), self.__widg2.sizeHint())
return
您得到以下信息:
PyQt5.QtCore.QSize(38, 22) PyQt5.QtCore.QSize(20, 20)
我们看到QScrollArea在sizeHint()中的宽度比QFrame大,这解释了为什么观察到的行为。
解决方案是建立相同的sizeHint()宽度,即不依赖于它包含的内容。
class Scroller(QScrollArea):
# ...
def sizeHint(self):
s = super().sizeHint()
s.setWidth(20) # same width
return s
class Frame(QFrame):
# ...
def sizeHint(self):
s = super().sizeHint()
s.setWidth(20) # same width
return s
# ...
输出:
关于python - QSplitter()不会平等对待QScrollArea()和QFrame(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56324313/