qlistwidget添加自定义控件_PyQt5学习笔记(十一)高级容器控件

PyQt5中存在这样的一些控件,它们本身并没有作用,但是它们却可以当做一个主窗口中的小岛屿,在上面摆放(装载)各种布局和空间,将这些整合的布局和控件看做一个复合控件再加入主窗口,这类控件一般称为高级容器控件。
高级容器控件的存在使得更加复杂的控件层次关系得以实现。


选项卡控件(QTabWidget)

什么是选项卡控件?还是拿万能的pycharm做例子:

比如设置中的代码风格设置中的Python:

46db7b7fbb1f9ba6856855ccccb1061d.png

比如最常见的,我们的工作区上方可以在不同的程序文件中切换的标签一样的东西:

a31f57f87fe853faab1b776479e0f2a0.png

用红色框起来的都是选项卡控件,它可以使得我们在同一个主窗口中切换不同的页面。这就是很有需求的一个控件,因为我们之前学的所以控件顶多是重叠数据,但是需要在一个主窗口上显示多个大页面却无能为力。现在有了选项卡控件,这个需求就可以得到满足。

我们创建的类需继承自QTabWidget才能使用选项卡控件,继承后通过QWidget()即可在主窗口上方创建选项卡。

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class TabWidgetDemo(QTabWidget):
    def __init__(self, parent=None):
        super(TabWidgetDemo, self).__init__(parent)
​
        self.setWindowTitle("选项卡控件:QTabWidget")
        self.resize(500, 200)
        # 创建用于显示控件的窗口
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tab3 = QWidget()
​
        # 将三个tab加入主窗口,并且将名字设为如下
        self.addTab(self.tab1, "选项卡1")
        self.addTab(self.tab2, "选项卡2")
        self.addTab(self.tab3, "选项卡3")
​
        self.tab1UI()
        self.tab2UI()
        self.tab3UI()
​
    def tab1UI(self):
        layout = QFormLayout()
        layout.addRow("姓名", QLineEdit())
        layout.addRow("地址", QLineEdit())
​
        # 将第一个选项卡,即tab1的文本改为...
        self.setTabText(0, "联系方式")
​
        self.tab1.setLayout(layout)
​
    def tab2UI(self):
        layout = QFormLayout()
        sex = QHBoxLayout()
        sex.addWidget(QRadioButton('男'))
        sex.addWidget(QRadioButton('女'))
        layout.addRow("性别", sex)
        layout.addRow("生日", QLineEdit())
​
        # 将第二个选项卡,即tab2的文本改为...
        self.setTabText(1, "个人详细信息")
​
        self.tab2.setLayout(layout)
​
    def tab3UI(self):
        layout = QHBoxLayout()
        layout.addWidget(QLabel("科目"))
        layout.addWidget(QCheckBox("物理"))
        layout.addWidget(QCheckBox("高数"))
​
        # 将第三个选项卡,即tab3的文本改为...
        self.setTabText(2, "教育程度")
        self.tab3.setLayout(layout)
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = TabWidgetDemo()
    main.show()
    sys.exit(app.exec_())

运行结果:

7c4a167abd08feab4fc138d4769a5aa9.png

堆栈窗口控件(QStackWidget)

在一个主窗口显示多个页面的信息和控件,除了选项卡控件之外,还可以使用堆栈窗口控件(QStackWidget)来切换页面:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class StackedExample(QWidget):
    def __init__(self):
        super(StackedExample, self).__init__()
​
        self.setWindowTitle("选堆栈窗口控件:QStackedWidget")
        self.resize(500, 400)
​
        # 创建一个列表控件
        self.list = QListWidget()
        self.list.insertItem(0 ,"联系方式")
        self.list.insertItem(1, "个人信息")
        self.list.insertItem(2, "教育程度")
​
        # 创建三个QWidget类型的子页面
        self.stack1 = QWidget()
        self.stack2 = QWidget()
        self.stack3 = QWidget()
​
        # 创建一个堆栈窗口控件,并将三个子页面装载进入其中
        self.stack = QStackedWidget()
        self.stack.addWidget(self.stack1)
        self.stack.addWidget(self.stack2)
        self.stack.addWidget(self.stack3)
        
        # 调用封装好的、用来为子页面添加控件的函数
        self.tab1UI()
        self.tab2UI()
        self.tab3UI()
​
        layout = QHBoxLayout()
        layout.addWidget(self.list)
        layout.addWidget(self.stack)
        self.setLayout(layout)
​
        self.list.currentRowChanged.connect(self.display)
​
​
    def tab1UI(self):
        layout = QFormLayout()
        layout.addRow("姓名", QLineEdit())
        layout.addRow("地址", QLineEdit())
​
        self.stack1.setLayout(layout)
​
    def tab2UI(self):
        layout = QFormLayout()
        sex = QHBoxLayout()
        sex.addWidget(QRadioButton('男'))
        sex.addWidget(QRadioButton('女'))
        layout.addRow("性别", sex)
        layout.addRow("生日", QLineEdit())
​
        self.stack2.setLayout(layout)
​
    def tab3UI(self):
        layout = QHBoxLayout()
        layout.addWidget(QLabel("科目"))
        layout.addWidget(QCheckBox("物理"))
        layout.addWidget(QCheckBox("高数"))
​
        self.stack3.setLayout(layout)
​
    def display(self, index):
        # 根据index,堆栈窗口控件会切换到相应序号的页面
        self.stack.setCurrentIndex(index)
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = StackedExample()
    main.show()
    sys.exit(app.exec_())

运行结果:

9007f9a95a50247bee3f1148e26d054f.png
点击左侧的三个标签,右侧的显示的控件会发生相应的变化

可能第一次接触堆栈窗口控件的同学会对上述的代码的层次有一点混乱,那我们来整理一下吧。这个例子中,主窗口层面我们只放了两个控件:QListWidgetQStackWidget,这两个控件都是容器控件;然后我们的QListWidget占据左半侧的空间,存放了三段文本,而QStackWidget作为高级容器控件占据了右半侧的空间,存放了三个子页面self.stack1self.stack2self.stack3,而我们又在下面的函数中(tab1UItab2UItab3UI)实现了对子页面控件的添加;最终通过QStackWidget控件的setCurrentIndex方法在stack123中切换页面。


停靠控件(QDockWidget)

什么是停靠控件呢,相信经常使用WPS、VS等多功能编辑平台的同学不会太陌生:

0ad825089f9b2e0e40f63db3936f5628.png
红框框起来的是VS的停靠控件,中间有允许固定停靠的位置提示
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class DockDemo(QMainWindow):
    def __init__(self):
        super(DockDemo, self).__init__()
​
        self.setWindowTitle("停靠控件:QDockWidget")
        self.resize(500, 400)
​
        layout = QHBoxLayout()
        # 往主窗口添加一个停靠控件
        # 第二个参数的意思是,我们的这个停靠控件是直接依附在主窗口上创建的
        # 而不是依附于其他的控件或者布局
        self.items = QDockWidget("Dockable", self)
        self.listWidget = QListWidget()
        self.listWidget.addItem("item1")
        self.listWidget.addItem("item2")
        self.listWidget.addItem("item3")
​
        self.items.setWidget(self.listWidget)
​
        self.setCentralWidget(QLineEdit())
​
        # Qt.RightDockWidgetArea的意思是我们的停靠控件items,默认停靠区域为右侧
        self.addDockWidget(Qt.RightDockWidgetArea, self.items)
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = DockDemo()
    main.show()
    sys.exit(app.exec_())

运行结果:

f9369fe40ff92bc3ef2ee43537ba41f7.png
Dockable子窗口可以拖动

还可以让停靠控件一开始就为悬浮:

# 初始状态为悬浮状态
# 默认参数为False,即停靠
self.items.setFloating(True)

容纳多文档的窗口(QMdiArea&QMdiSubWindow)

在许多UI中都有创建新页面的功能,所谓的创建新窗口,许多都是创建一个依附于主窗口存在的子窗口(关闭主窗口,子窗口一并消失)。PyQt5提供了高级容器控件QMdiArea和可装载进入该容器控件的QMdiSubWindow子窗口控件来实现这种功能。

具体的步骤如下:

  • 通过QMdiArea创建一个无形的容器(其实能感觉到,因为主窗口因QMdiArea的加入而变成了深灰色)
  • 通过QMdiSubWindow创建子窗口,通过一系列方法可以向该子窗口里添加布局和方法。
  • 通过QMdiAreaaddSubWindow方法可以将我们创建的子窗口装载进入QMdiArea
  • 使用show()使子窗口在主窗口上显示出来。
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class MultiWindows(QMainWindow):
    # 用来记录已经创建的子窗口数,目的是为了新建的子窗口起名字
    count = 0
    def __init__(self):
        super(MultiWindows, self).__init__()
        self.initUI()
​
    def initUI(self):
        self.setWindowTitle("容纳多文档的窗口")
        self.resize(700, 500)
​
        self.mdi = QMdiArea()
        # 创建菜单栏
        bar = self.menuBar()
        # 菜单栏下新建一个标签"File",下辖三个功能子标签:
        # New:创建新子窗口
        # cascade:将所有子窗口重叠排列
        # Tiled:将所有子窗口平铺排列
        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
​
        file.triggered.connect(self.windowaction)
​
        self.setCentralWidget(self.mdi)
​
    def windowaction(self, q):
        if q.text() == "New":
            # 新建一个窗口,计数的变量+1
            MultiWindows.count += 1
​
            # 创建一个子窗口控件
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("子窗口" + str(MultiWindows.count))
​
            # 将子窗口装载进入容器中
            self.mdi.addSubWindow(sub)
​
            # 这一步千万不要忘了
            sub.show()
​
        elif q.text() == "cascade":
            self.mdi.cascadeSubWindows()
​
        elif q.text() == "Tiled":
            self.mdi.tileSubWindows()
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MultiWindows()
    main.show()
    sys.exit(app.exec_())

运行结果:

97ba466ed62e76c6c0380aeca5172c70.png
通过File->New创建了四个子窗口

79c73a27071ce87f3b7495afa759de56.png
通过File->cascade将四个子窗口重叠排列

a4c63e955b271442b5f67dc9ea8a0d95.png
通过File->Tiled将四个子窗口平铺排列

滚动条控件(QScrollBar)

滚动条控件不是高级容器控件,它在一定的场合下可以发挥和容器控件类似的功能:

  1. 通过滚动条值的变化控制其他控件状态的变化
  2. 通过滚动条值的变化控制控件位置的变化

下面就距离通过三个QScrollBar控件控制QLabel前景色(也就是文本文字的字体颜色)的RGB颜色的三个通道值。

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class ScrollBar(QWidget):
    def __init__(self):
        super(ScrollBar, self).__init__()
        self.initUI()
​
    def initUI(self):
        self.setWindowTitle("滚动条控件")
        self.resize(500, 400)
​
        hbox = QHBoxLayout()
        self.label = QLabel("拖动滚动条去改变文字颜色")
​
        hbox.addWidget(self.label)
​
        # 下面设置三个滚动条,分别控制QLabel中文字的RGB颜色通道的三个分量值
        self.scrollbar1 = QScrollBar()
        # 滚动条值最大设为255,因为这是RGB通道每个分量的最大值
        # 不设置滚动条值的最小值是因为默认最小值为0
        self.scrollbar1.setMaximum(255)
        self.scrollbar1.sliderMoved.connect(self.colorChanged)
​
        self.scrollbar2 = QScrollBar()
        self.scrollbar2.setMaximum(255)
        self.scrollbar2.sliderMoved.connect(self.colorChanged)
​
        self.scrollbar3 = QScrollBar()
        self.scrollbar3.setMaximum(255)
        self.scrollbar3.sliderMoved.connect(self.colorChanged)
​
        hbox.addWidget(self.scrollbar1)
        hbox.addWidget(self.scrollbar2)
        hbox.addWidget(self.scrollbar3)
​
        self.setLayout(hbox)
​
        # 获取label的纵坐标坐标
        self.y = self.label.pos().y()
​
    def colorChanged(self):
        print("R:{},G:{},B:{}".format(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value()))
​
        # 不用多说了吧,调整颜色都需要创建调色板对象
        palette = QPalette()
        c = QColor(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value())
        # 设置调色板的颜色参数:
        # 填充模式:填充前景色(文字颜色), 代表颜色的QColorDialog对象
        palette.setColor(QPalette.Foreground, c)
        self.label.setPalette(palette)
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = ScrollBar()
    main.show()
    sys.exit(app.exec_())

运行结果:

923dfc75b8589926c7e9818a83af400a.png

再实现通过QLabel的上下移动,为此,我们添加第四个滚动条,用来控制QLabel的上下移动:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
​
class ScrollBar(QWidget):
    def __init__(self):
        super(ScrollBar, self).__init__()
        self.initUI()
​
    def initUI(self):
        self.setWindowTitle("滚动条控件")
        self.resize(500, 400)
​
        hbox = QHBoxLayout()
        self.label = QLabel("拖动滚动条去改变文字颜色")
​
        hbox.addWidget(self.label)
​
        # 下面设置三个滚动条,分别控制QLabel中文字的RGB颜色通道的三个分量值
        self.scrollbar1 = QScrollBar()
        # 滚动条值最大设为255,因为这是RGB通道每个分量的最大值
        # 不设置滚动条值的最小值是因为默认最小值为0
        self.scrollbar1.setMaximum(255)
        self.scrollbar1.sliderMoved.connect(self.colorChanged)
​
        self.scrollbar2 = QScrollBar()
        self.scrollbar2.setMaximum(255)
        self.scrollbar2.sliderMoved.connect(self.colorChanged)
​
        self.scrollbar3 = QScrollBar()
        self.scrollbar3.setMaximum(255)
        self.scrollbar3.sliderMoved.connect(self.colorChanged)
​
        self.scrollbar4 = QScrollBar()
        self.scrollbar4.setMaximum(255)
        self.scrollbar4.sliderMoved.connect(self.posMoved)
​
        hbox.addWidget(self.scrollbar1)
        hbox.addWidget(self.scrollbar2)
        hbox.addWidget(self.scrollbar3)
        hbox.addWidget(self.scrollbar4)
​
        self.setLayout(hbox)
​
        # 获取label的纵坐标坐标
        self.y = self.label.pos().y()
​
    def colorChanged(self):
        print("R:{},G:{},B:{}".format(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value()))
​
        # 不用多说了吧,调整颜色都需要创建调色板对象
        palette = QPalette()
        c = QColor(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value())
        # 设置调色板的颜色参数:
        # 填充模式:填充前景色(文字颜色), 代表颜色的QColorDialog对象
        palette.setColor(QPalette.Foreground, c)
        self.label.setPalette(palette)
​
    def posMoved(self):
        self.label.move(self.label.x(), self.y + self.scrollbar4.value())
​
​
​
if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = ScrollBar()
    main.show()
    sys.exit(app.exec_())

运行结果:

1190d9a1e8a99f10a0ab29038f2f3bea.png
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值