PyQt5多线程及布局

 
 
 
 
 
 
 
 

多线程


 

PyQt5 中常用的多线程方法主要是:QTimer、QThread 两种

 
 
 
 

QTimer

方法含义
timer.start(n)每 n 毫秒调用一次
QTimer.singleShot(n, app.quit)过 n 毫秒调用一次,且仅调用一次。

app.quit 可以替换成其他需要执行的事件

 

定时刷新时间

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class ShowTime(QWidget):
    def __init__(self):
        super(ShowTime, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("动态显示当前时间")

        self.label = QLabel("显示当前时间")
        self.startBtn = QPushButton("开始")
        self.endBtn = QPushButton("结束")
        layout = QGridLayout()

        self.timer = QTimer()
        self.timer.timeout.connect(self.showTimer)

        layout.addWidget(self.label, 0, 0, 1, 2)
        layout.addWidget(self.startBtn, 1, 0)
        layout.addWidget(self.endBtn, 1, 1)

        self.startBtn.clicked.connect(self.startTimer)
        self.endBtn.clicked.connect(self.endTimer)

        self.setLayout(layout)

    def showTimer(self):
        print("show")
        time = QDateTime.currentDateTime()

        timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd")
        self.label.setText(timeDisplay)

    def startTimer(self):
        # 让定时器以每 1 秒( 1000 毫秒)为周期进行循环调用其身上绑定的槽
        self.timer.start(1000)
        self.startBtn.setEnabled(False)
        self.endBtn.setEnabled(True)

    def endTimer(self):
        self.timer.stop()
        self.startBtn.setEnabled(True)
        self.endBtn.setEnabled(False)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = ShowTime()
    main.show()
    sys.exit(app.exec_())

 

定时关闭窗口

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class ShowTime(QWidget):
    def __init__(self):
        super(ShowTime, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("动态显示当前时间")

        QTimer.singleShot(5000, app.quit)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = ShowTime()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

QThread

如果使用单线程进行计算、刷新页面上某些值时(如更新 lcdNumber)。当事件仅执行一次时,没有问题,但是当事件是持续运行的循环事件,即使内部有 time.sleep() 之类的代码,其GUI也不会更新,而是期望等退出循环后再进行渲染,此期间程序的GUI将会未响应,但是程序依旧在后台运行

 

计数器及自动关闭

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

# 全局计数器
sec = 0


# 继承 QThread 并在其基础上实现新功能
class WorkThread(QThread):
    # 创建自定义信号
    # 每隔一秒发送一次信号
    timer = pyqtSignal()
    # 技术结束后发送一次信号
    end = pyqtSignal()

    def run(self):
        while True:
            # 睡眠一秒
            self.sleep(1)
            # 计数器到 5 时,关闭窗口
            if sec == 5:
                # 发送 end 信号,触发槽函数
                self.end.emit()

                # 结束该信号的持续监听
                break

            # 每隔一秒发送一次 timer 信号
            self.timer.emit()


class Counter(QWidget):
    def __init__(self):
        super(Counter, self).__init__()
        self.setWindowTitle("使用 QThread 编写计数器")
        self.resize(300, 120)

        layout = QVBoxLayout()
        # 类似 led 的显示屏
        self.lcdNumber = QLCDNumber()
        layout.addWidget(self.lcdNumber)

        button = QPushButton("开始计数")
        layout.addWidget(button)

        # 实例化继承了 Thread 的自定义子类,以开辟新线程进行某些工作
        self.workThread = WorkThread()
        # 持续发送 timer 信号
        self.workThread.timer.connect(self.countTime)
        # 到达 sec==5 触发 end 信号
        self.workThread.end.connect(self.end)

        button.clicked.connect(self.work)

        self.setLayout(layout)

    def countTime(self):
        global sec
        sec += 1
        self.lcdNumber.display(sec)

    def end(self):
        QMessageBox.information(self, "消息", "计数结束", QMessageBox.Ok)

    def work(self):
        # 开启新线程,并发送自定义信号
        self.workThread.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Counter()
    main.show()
    sys.exit(app.exec_())

 
 
 
 
 
 
 
 

布局


 

绝对布局

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class AbsoluteLayout(QWidget):
    def __init__(self):
        super(AbsoluteLayout, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("绝对布局")

        self.label1 = QLabel("欢迎", self)
        self.label1.move(15, 20)

        self.label2 = QLabel("学习", self)
        self.label2.move(35, 40)

        self.label3 = QLabel("PyQT5", self)
        self.label3.move(55, 80)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = AbsoluteLayout()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

水平盒布局

在这里插入图片描述

import sys, math
from PyQt5.QtWidgets import *


class HBoxLayout(QWidget):
    def __init__(self):
        super(HBoxLayout, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("水平盒布局")

        layout = QHBoxLayout()
        layout.addWidget(QPushButton("按钮1"))
        layout.addWidget(QPushButton("按钮2"))
        layout.addWidget(QPushButton("按钮3"))
        layout.addWidget(QPushButton("按钮4"))
        layout.addWidget(QPushButton("按钮5"))
        layout.addWidget(QPushButton("按钮6"))

        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = HBoxLayout()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

垂直盒布局

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class HBoxLayout(QWidget):
    def __init__(self):
        super(HBoxLayout, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("水平盒布局")

        layout = QVBoxLayout()
        layout.addWidget(QPushButton("按钮1"))
        layout.addWidget(QPushButton("按钮2"))
        layout.addWidget(QPushButton("按钮3"))
        layout.addWidget(QPushButton("按钮4"))
        layout.addWidget(QPushButton("按钮5"))
        layout.addWidget(QPushButton("按钮6"))
        layout.setSpacing(40)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = HBoxLayout()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

设置控件对齐方式

通过调整 addWidget() 的参数来控制控件的位置

  • stretch —— 设置伸缩量,即控件占用空间的比例
  • alignment —— 对齐方式

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class HBoxLayout(QWidget):
    def __init__(self):
        super(HBoxLayout, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("水平盒布局")

        layout = QHBoxLayout()
        layout.addWidget(QPushButton("按钮1"), 1, Qt.AlignLeft | Qt.AlignTop)
        layout.addWidget(QPushButton("按钮2"), 1, Qt.AlignLeft | Qt.AlignTop)
        layout.addWidget(QPushButton("按钮3"), 1, Qt.AlignLeft | Qt.AlignTop)
        layout.addWidget(QPushButton("按钮4"), 1, Qt.AlignLeft | Qt.AlignBottom)
        layout.addWidget(QPushButton("按钮5"), 1, Qt.AlignLeft | Qt.AlignBottom)
        layout.addWidget(QPushButton("按钮6"), 1, Qt.AlignLeft | Qt.AlignBottom)
        layout.setSpacing(40)
        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = HBoxLayout()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

让按钮永远在窗口某位置

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *


class FixBtn(QWidget):
    def __init__(self):
        super(FixBtn, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("垂直盒布局")

        okBtn = QPushButton("确定")
        canBtn = QPushButton("取消")

        layout = QHBoxLayout()
        # 关键在这里,添加一个伸缩量,该伸缩量后方的控件都被挤到右侧了
        layout.addStretch(1)
        layout.addWidget(okBtn)
        layout.addWidget(canBtn)

        layout1 = QVBoxLayout()
        btn1 = QPushButton("按钮1")
        btn2 = QPushButton("按钮2")
        btn3 = QPushButton("按钮3")

        # 添加一个为 0 的伸缩量,在遇到第二个伸缩量前的控件,全部向顶部(如果是水平就是左侧)排列
        layout1.addStretch(0)
        layout1.addWidget(btn1)
        layout1.addWidget(btn2)
        layout1.addWidget(btn3)
        # 添加一个伸缩量,让其下方的值全部靠底排列
        layout1.addStretch(1)
        layout1.addLayout(layout)

        self.setLayout(layout1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = FixBtn()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

栅格布局实现计算器

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *


class Cacl(QWidget):
    def __init__(self):
        super(Cacl, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("计算器")

        layout = QGridLayout()
        self.setLayout(layout)

        names = [
            "Cls", "Back", "", "Close",
            "7", "8", "9", "/",
            "6", "5", "4", "*",
            "3", "2", "1", "-",
            "0", "=", "+", "+",
        ]

        # 生成网格坐标
        position = [(i, j) for i in range(5) for j in range(4)]

        # 绑定网格坐标和文本
        for posi, name in zip(position, names):
            # 不生成按钮
            if name == "":
                continue

            btn = QPushButton(name)
            layout.addWidget(btn, *posi)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Cacl()
    main.show()
    sys.exit(app.exec_())

 
 
 
 

栅格单元格跨列

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *


class GridForm(QWidget):
    def __init__(self):
        super(GridForm, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("计算器")

        layout = QGridLayout()
        self.setLayout(layout)

        tLabel = QLabel("标题")
        aLabel = QLabel("作者")
        cLabel = QLabel("内容")

        tLineEdit = QLineEdit()
        aLineEdit = QLineEdit()
        cLineEdit = QTextEdit()

        layout.addWidget(tLabel, 1, 0)
        layout.addWidget(aLabel, 2, 0)
        layout.addWidget(cLabel, 3, 0)
        layout.addWidget(tLineEdit, 1, 1)
        layout.addWidget(aLineEdit, 2, 1)
        layout.addWidget(cLineEdit, 3, 1, 5, 1)

        layout.setSpacing(10)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = GridForm()
    main.show()
    sys.exit(app.exec_())

 
 
 
 
 
 
 
 

表单布局

在这里插入图片描述

import sys
from PyQt5.QtWidgets import *


class FormForm(QWidget):
    def __init__(self):
        super(FormForm, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("计算器")

        layout = QFormLayout()
        self.setLayout(layout)

        tLabel = QLabel("标题")
        aLabel = QLabel("作者")
        cLabel = QLabel("内容")

        tLineEdit = QLineEdit()
        aLineEdit = QLineEdit()
        cLineEdit = QTextEdit()

        layout.addRow(tLabel, tLineEdit)
        layout.addRow(aLabel, aLineEdit)
        layout.addRow(cLabel, cLineEdit)

        layout.setSpacing(10)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = FormForm()
    main.show()
    sys.exit(app.exec_())

 
 
 
 
 
 
 
 

拖动控件边界

在这里插入图片描述
在这里插入图片描述

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class Splitter(QWidget):
    def __init__(self):
        super(Splitter, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("拖动控件边界")

        layout_hbox = QHBoxLayout()

        topleft = QFrame()
        topleft.setFrameShape(QFrame.StyledPanel)

        bottom = QFrame()
        bottom.setFrameShape(QFrame.StyledPanel)

        textedit = QTextEdit()
        
        # 拖动控件,将需要被拖动边界的两个控件放入到 splitter 内
        splitter1 = QSplitter(Qt.Horizontal)
        splitter1.addWidget(topleft)
        splitter1.addWidget(textedit)
        # 设置左右两侧的尺寸
        splitter1.setSizes([100, 200])
        
        # 形成上下分割的布局
        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter1)
        splitter2.addWidget(bottom)

        layout_hbox.addWidget(splitter2)
        self.setLayout(layout_hbox)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Splitter()
    main.show()
    sys.exit(app.exec_())

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值