【发布时间】:2020-07-20 15:20:22
【问题描述】:
基本上,我想在 QtDesigner 的窗口中添加一些 QSlider,然后将它们“替换”为一个包含滑块的类,并在其下方包含一个文本框(行编辑)。
编辑:我为什么要这样做:当我使用 QtDesigner 时,我可以放置滑块,并对布局进行近似可视化,因为它将在最终应用程序中:
这就是为什么我想使用 QtDesigner 开始 - 获得最终布局的近似可视化,因为它将在应用程序中。而且由于我想用某种基于滑块的小部件替换这些滑块,因此首先将滑块放在视图中对我来说更有帮助。
但是,如果我必须将 QWidget 作为替换滑块所在位置的起点,那么 QtDesigner 视图如下所示:
换句话说,以前显示滑块的空间现在是空的 - 所以现在我不再预览最终的 GUI 布局,这有点违背了我使用 QtDesigner 的目的(我可能会好好努力,尝试完全在代码中绘制 GUI,没有任何视觉反馈,可能需要花费所有时间)。
到目前为止,我设法做到了这一点 - 我在 test2.py 中实现了一个名为“VertSlider”的 QSlider 子类,然后在 test2.ui 中将 QtDesigner 中的 QSlider 提升为此类:
有趣的是,它有点效果 - 如果您努力观察右侧两个滑块的中心,您可以在滑块的中心看到线条编辑的轮廓。
但显然我不希望这样 - 我希望在底部进行行编辑,它应该根据需要从原始滑块外观(如 QtDesigner 中指定)中占用尽可能多的垂直空间,然后实际的滑块应该填满其余的垂直空间(如屏幕截图左侧所示)。
我想,部分问题是,QSlider 似乎没有.layout() - 默认情况下返回“无”;我试图强迫一个,但这显然不起作用。
通过Qt widget stacking child layouts on top of each other 找到documentation 的这句话:
如果这个小部件上已经安装了一个布局管理器,QWidget 不会让你安装另一个。您必须先删除现有的布局管理器(由 layout() 返回),然后才能使用新布局调用 setLayout()。
显然,QSlider 没有默认布局管理器 .... 从 Is it possible to add text on top of a scrollbar? 和 Qt add a widget inside another widget? 判断 - 在这种情况下,我必须要么“子类 ... 并覆盖 paintEvent( )" 或 "使用代理样式/drawComplexControl()";根据https://www.learnpyqt.com/courses/custom-widgets/creating-your-own-custom-widgets/ 中的术语,这将是一个“自定义绘制的小部件”,但我真的希望我可以“只是”做一个“复合”小部件:只是以某种方式从 QtDesigner 中基于 QSlider 的规范 -> 到一个 QSLider+QLineEdit 小部件,无需处理自定义绘画。
当然,原则上我可以将 QWidget 子类化,然后使用 layout.addWidget 的方法会起作用 - 但我不能使用该子类来“提升”作为 QtDesigner 中的 QSlider 放置的内容。
那么,创建一个 QSlider 子类最简单的方法是什么,它只需在滑块底部添加一个行编辑文本框,它可以用作在 QtDesigner 中提升 QSlider 的类?
test2.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>436</width>
<height>354</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Want this:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item alignment="Qt::AlignHCenter">
<widget class="QSlider" name="verticalSlider">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>... by promoting these QSliders in QtDesigner:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="VertSlider" name="verticalSlider_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="VertSlider" name="verticalSlider_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>436</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>VertSlider</class>
<extends>QSlider</extends>
<header>test2</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
test2.py
import sys
from PyQt5 import QtCore, QtWidgets, QtGui, uic
from PyQt5.QtCore import pyqtSlot
class VertSlider(QtWidgets.QSlider):
def __init__(self, *args, **kwargs):
QtWidgets.QSlider.__init__(self, *args, **kwargs)
print(self.layout()) # None
# so, trying to force a layout here, so I could add a line edit - but it doesn't quite work:
self.layout = QtWidgets.QVBoxLayout(self)
self.label = QtWidgets.QLineEdit(self)
self.label.setText("aa")
self.label.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
self.layout.addWidget(self.label)
self.setLayout(self.layout)
print(self.layout, self.layout.count(), self.label.width(), self.label.height(), self.label.x(), self.label.y()) # <PyQt5.QtWidgets.QVBoxLayout object at 0x0000000006681790> 1 100 30 0 0
class MyMainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
uic.loadUi('test2.ui', self)
self.show()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MyMainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
【问题讨论】:
-
@eyllanesc 答案是正确的。关键是使用 QWidget 作为 QSlider 和 QLineEdit 子小部件的容器。您可以在 Qt Designer 中使用它的子小部件绘制 QWidget,然后将其提升为您的自定义小部件。
-
感谢@bfris - 我终于设法在 QtDesigner 中使用了“在 Qt Designer 中使用它的子小部件绘制 QWidget”方法,它允许在 QtDesigner 中进行不错的预览,并使用@eyllanesc 答案 - 在下面发布了一个单独的答案。
标签: python pyqt5 qt-designer