Python PyQt5 教程
PyQt5教程 :http://code.py40.com/face
教程翻译自:http://zetcode.com/gui/pyqt5/
PyQt5 的 核心API 以及 扩展应用(CSDN 学院收费视频):https://edu.csdn.net/course/play/9870/222942
pyqt5 - 对文本样式进行操作:https://www.cnblogs.com/XJT2018/p/9835262.html
setStyleSheet 用法:https://www.cnblogs.com/aheng123/p/5630761.html
Pyqt5 —— setStyleSheet 用法:https://blog.csdn.net/weixin_42066185/article/details/82225197
颜色代码查询,RGB 查询:http://tool.chinaz.com/tools/selectcolor.aspx
RGB颜色值转换成十六进制颜色码:https://www.sioe.cn/yingyong/yanse-rgb-16/
【第一节】PyQt5简介:http://code.py40.com/1948.html
【第二节】PyQt5基本功能:http://code.py40.com/1961.html
【第三节】PyQt5布局管理:http://code.py40.com/1995.html
【第四节】PyQt5菜单和工具栏:http://code.py40.com/1984.html
【第五节】PyQt5事件和信号:http://code.py40.com/2004.html
【第六节】PyQt5 对话框:http://code.py40.com/2009.html
【第七节】PyQt5控件:http://code.py40.com/2018.html
【第八节】PyQt5控件(II):http://code.py40.com/2026.html
【第九节】PyQt 拖拽:http://code.py40.com/2035.html
【第十节】PyQt5绘图:http://code.py40.com/2042.html
【第十一节】PyQt5自定义控件:http://code.py40.com/2049.html
【第十二节】PyQt5俄罗斯方块:http://code.py40.com/2052.html
PyQt5 说明
pyqt5是一套Python绑定Digia QT5应用的框架。它可用于Python 2和3。本教程使用Python 3。Qt库是最强大的GUI库之一。pyqt5的官方网站http://www.riverbankcomputing.co.uk/news。
pyqt5 做为 Python 的一个模块,它有 620 多个类和 6000 个函数和方法。这是一个跨平台的工具包,它可以运行在所有主要的操作系统,包括 UNIX,Windows,Mac OS。pyqt5 是双重许可。开发者可以在 GPL 和 商业许可 之间进行选择。
pyqt5 的类别分为几个模块,包括以下:
- QtCore
- QtGui
- QtWidgets
- QtMultimedia
- QtBluetooth
- QtNetwork
- QtPositioning
- Enginio
- QtWebSockets
- QtWebKit
- QtWebKitWidgets
- QtXml
- QtSvg
- QtSql
- QtTest
说明:
QtCore | 包含了核心的非 GUI 功能。 此模块用于处理时间、文件和目录、各种数据类型、流、URL、MIME类型、线程或进程。 |
QtGui | 包含类窗口系统集成、事件处理、二维图形、基本成像、字体和文本。 |
QtWidgets | 模块包含创造经典桌面风格的用户界面提供了一套UI元素的类。 |
QtMultimedia | 包含的类来处理多媒体内容和 API 来访问相机和收音机的功能。 |
QtBluetooth | 模块包含类的扫描设备和连接并与他们互动。描述模块包含了网络编程的类。 这些类便于 TCP 和 IP 和 UDP 客户端和服务器的编码,使网络编程更容易和更便携。 |
QtNetwork | 网络模块 |
QtPositioning | 包含类的利用各种可能的来源,确定位置,包括卫星、Wi-Fi、或一个文本文件。 |
Enginio | 模块实现了客户端库访问 Qt 云服务托管的应用程序运行时。 |
QtWebSockets | 模块包含实现 WebSocket 协议类。 |
QtWebKit | 包含一个基于 Webkit2 图书馆 Web 浏览器 实现类。 |
QtWebKitWidgets | 包含的类的基础 webkit1 ,用于 qtwidgets 应用 Web 浏览器的实现。 |
QtXml | 包含与 XML 文件的类。这个模块为 SAX 和 DOM API 提供了实现。 |
QtSvg | 模块提供了显示 SVG 文件内容的类。可伸缩矢量图形(SVG)是一种描述二维图形和图形应用的语言。 |
QtSql | 模块提供操作数据库的类。 |
QtTest | 包含的功能,使 pyqt5 应用程序的单元测试 |
pyqt5 不向后兼容 pyqt4。pyqt5 有几个显著的变化。将旧代码调整到新库并不困难。有几个大的改变如下:
- Python模块已经重组。一些模块已经删除(qtscript),有的被分割成子模块(QtGui,QtWebKit)。
- 新的模块作了详细的介绍,包括qtbluetooth,qtpositioning,或enginio。
- pyqt5只支持新型的信号和槽handlig。电话signal()或slot()不再支持。
- pyqt5不支持Qt的API被标记为过时或陈旧的任何部分在QT V5.0。
【第 1 节】 到 【第 4 节】演示代码
( 可以 把 __init__ 函数中的 注释逐个取消,然后运行程序看执行效果 ):
-
# -*- coding: utf-8 -*-
-
# @Author :
-
# @File : main.py
-
# @Software: PyCharm
-
# @description : XXX
-
-
-
import sys
-
-
# QMainWindow 类提供了一个主要的应用程序窗口。
-
# 你用它可以让应用程序添加状态栏,工具栏和菜单栏。
-
from PyQt5.QtWidgets
import QWidget, QMainWindow
-
-
from PyQt5.QtWidgets
import QApplication
-
from PyQt5.QtWidgets
import QDesktopWidget, QMessageBox, QLabel, QPushButton, QAction
-
from PyQt5.QtWidgets
import QAction, qApp
-
from PyQt5.QtWidgets
import QLineEdit, QTextEdit
-
from PyQt5.QtWidgets
import QHBoxLayout
# horizontal 水平布局
-
from PyQt5.QtWidgets
import QVBoxLayout
# vertical 垂直布局
-
from PyQt5.QtWidgets
import QGridLayout
# Grid 网格布局
-
-
from PyQt5.QtGui
import QIcon
-
-
-
# 如果不想一个一个 导入,可以 import *
-
# from PyQt5.QtWidgets import *
-
-
-
class MyForm1(QWidget):
-
def __init__(self):
-
super(MyForm1, self).__init__()
-
# self._init_ui_1()
-
# self._init_ui_2()
-
# self._init_ui_3()
-
# self._init_ui_4()
-
self._init_ui_5()
-
pass
-
-
def center(self):
-
"""
-
控制窗口显示在屏幕中心的方法
-
:return:
-
"""
-
# 获得窗口
-
qr = self.frameGeometry()
-
# 获得屏幕中心点
-
cp = QDesktopWidget().availableGeometry().center()
-
# 显示到屏幕中心
-
qr.moveCenter(cp)
-
self.move(qr.topLeft())
-
-
def _init_ui_1(self):
-
"""
-
重置大小,中心显示
-
:return:
-
"""
-
self.resize(
1000,
600)
-
self.center()
-
self.show()
-
-
def _init_ui_2(self):
-
"""
-
使用 绝对位置 布局元素位置
-
:return:
-
"""
-
lbl1 = QLabel(
'Zetcode', self)
-
lbl1.move(
15,
10)
-
-
lbl2 = QLabel(
'tutorials', self)
-
lbl2.move(
35,
40)
-
-
lbl3 = QLabel(
'for programmers', self)
-
lbl3.move(
55,
70)
-
-
self.setGeometry(
300,
300,
250,
150)
-
self.setWindowTitle(
'Absolute')
-
self.show()
-
-
def _init_ui_3(self):
-
"""
-
使用布局 来 布局 元素位置
-
:return:
-
"""
-
btn_ok = QPushButton(
"OK")
-
btn_cancel = QPushButton(
"Cancel")
-
-
hbox = QHBoxLayout()
-
hbox.addStretch(
1)
-
hbox.addWidget(btn_ok)
-
hbox.addWidget(btn_cancel)
-
-
vbox = QVBoxLayout()
-
vbox.addStretch(
1)
-
vbox.addLayout(hbox)
-
-
self.setLayout(vbox)
-
-
self.setGeometry(
300,
300,
300,
150)
-
self.setWindowTitle(
'Buttons')
-
self.show()
-
-
def _init_ui_4(self):
-
"""
-
使用 网格布局 来 布局 元素位置
-
:return:
-
"""
-
grid = QGridLayout()
-
self.setLayout(grid)
-
-
names = [
-
'Cls',
'Bck',
'',
'Close',
-
'7',
'8',
'9',
'/',
-
'4',
'5',
'6',
'*',
-
'1',
'2',
'3',
'-',
-
'0',
'.',
'=',
'+'
-
]
-
-
positions = [(i, j)
for i
in range(
5)
for j
in range(
4)]
-
-
for position, name
in zip(positions, names):
-
-
if name ==
'':
-
continue
-
button = QPushButton(name)
-
grid.addWidget(button, *position)
-
-
self.move(
300,
150)
-
self.setWindowTitle(
'Calculator')
-
self.show()
-
-
def _init_ui_5(self):
-
"""
-
网格布局 跨越 多行 或者 多列
-
:return:
-
"""
-
title = QLabel(
'Title')
-
author = QLabel(
'Author')
-
review = QLabel(
'Review')
-
-
titleEdit = QLineEdit()
-
authorEdit = QLineEdit()
-
reviewEdit = QTextEdit()
-
-
grid = QGridLayout()
-
grid.setSpacing(
10)
-
-
grid.addWidget(title,
1,
0)
-
grid.addWidget(titleEdit,
1,
1)
-
-
grid.addWidget(author,
2,
0)
-
grid.addWidget(authorEdit,
2,
1)
-
-
grid.addWidget(review,
3,
0)
-
grid.addWidget(reviewEdit,
3,
1,
5,
1)
-
-
self.setLayout(grid)
-
-
self.setGeometry(
300,
300,
350,
300)
-
self.setWindowTitle(
'Review')
-
self.show()
-
-
def closeEvent(self, event):
-
"""
-
重写关闭窗口事件
-
:param event:
-
:return:
-
"""
-
reply = QMessageBox.question(
-
self,
'Message',
'Are you sure close window ?',
-
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
-
)
-
if reply == QMessageBox.Yes:
-
event.accept()
-
else:
-
event.ignore()
-
pass
-
-
-
class MyForm2(QMainWindow):
-
"""
-
QMainWindow 类提供了一个主要的应用程序窗口。
-
你用它可以让应用程序添加状态栏,工具栏和菜单栏。
-
"""
-
-
def __init__(self):
-
super(MyForm2, self).__init__()
-
# self._init_ui_6()
-
# self._init_ui_7()
-
# self._init_ui_8()
-
self._init_ui_9()
-
-
def _init_ui_6(self):
-
"""
-
状态栏
-
:return:
-
"""
-
self.statusBar().showMessage(
'Ready')
-
self.setGeometry(
800,
300,
250,
150)
-
self.setWindowTitle(
'Statusbar')
-
self.show()
-
-
def _init_ui_7(self):
-
"""
-
菜单栏
-
:return:
-
"""
-
# QAction可以操作菜单栏,工具栏,或自定义键盘快捷键。
-
-
# 创建一个事件和一个特定的图标和一个“退出”的标签。
-
exitAction = QAction(QIcon(
'exit.png'),
'&Exit', self)
-
exitAction.setShortcut(
'Ctrl+Q')
# 定义该操作的快捷键。
-
-
# 创建一个鼠标指针悬停在该菜单项上时的提示。
-
exitAction.setStatusTip(
'Exit application')
-
-
# # 第三行创建一个鼠标指针悬停在该菜单项上时的提示。
-
exitAction.triggered.connect(qApp.quit)
-
-
self.statusBar()
-
-
# 创建一个菜单栏
-
menubar = self.menuBar()
-
# 添加菜单
-
fileMenu = menubar.addMenu(
'&File')
-
# 添加事件
-
fileMenu.addAction(exitAction)
-
-
self.setGeometry(
800,
300,
300,
200)
-
self.setWindowTitle(
'Menubar')
-
self.show()
-
-
def _init_ui_8(self):
-
"""
-
工具栏
-
:return:
-
"""
-
exitAction = QAction(QIcon(
'exit24.png'),
'Exit', self)
-
exitAction.setShortcut(
'Ctrl+Q')
-
exitAction.triggered.connect(qApp.quit)
-
-
self.toolbar = self.addToolBar(
'Exit')
-
self.toolbar.addAction(exitAction)
-
-
self.setGeometry(
800,
300,
300,
200)
-
self.setWindowTitle(
'Toolbar')
-
self.show()
-
-
def _init_ui_9(self):
-
# 创建一个菜单条,工具栏和状态栏的小窗口
-
textEdit = QTextEdit()
-
self.setCentralWidget(textEdit)
-
-
exitAction = QAction(QIcon(
'exit24.png'),
'Exit', self)
-
exitAction.setShortcut(
'Ctrl+Q')
-
exitAction.setStatusTip(
'Exit application')
-
exitAction.triggered.connect(self.close)
-
-
self.statusBar()
-
-
menubar = self.menuBar()
-
fileMenu = menubar.addMenu(
'&File')
-
fileMenu.addAction(exitAction)
-
-
toolbar = self.addToolBar(
'Exit')
-
toolbar.addAction(exitAction)
-
-
self.setGeometry(
800,
300,
350,
250)
-
self.setWindowTitle(
'Main window')
-
self.show()
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
form_1 = MyForm1()
-
form_2 = MyForm2()
-
sys.exit(app.exec_())
-
pass
-
点击产生一个新窗口:
-
import sys
-
from PyQt5.QtWidgets
import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton
-
-
-
class Form1(QWidget):
-
-
def __init__(self):
-
super(Form1, self).__init__()
-
self.setWindowTitle(
'From_1')
-
self.resize(
600,
300)
-
self._init_ui()
-
self.show()
-
-
def close_window(self):
-
"""
-
点击按钮 将 窗体1 关掉
-
:return:
-
"""
-
self.close()
-
-
def _init_ui(self):
-
v_box = QVBoxLayout()
-
self.btn_1 = QPushButton(
'btn_1: close Form_2')
-
self.btn_2 = QPushButton(
'btn_2: show Form_2')
-
v_box.addWidget(self.btn_1)
-
v_box.addWidget(self.btn_2)
-
self.setLayout(v_box)
-
-
-
class Form2(QWidget):
-
-
def __init__(self):
-
super(Form2, self).__init__()
-
self.setWindowTitle(
'From_2')
-
self.resize(
800,
400)
-
self._init_ui()
-
-
def display(self):
-
"""
-
显示窗体
-
:return:
-
"""
-
self.show()
-
-
def _init_ui(self):
-
h_box = QHBoxLayout()
-
btn_3 = QPushButton(
'btn_3')
-
btn_4 = QPushButton(
'btn_4')
-
h_box.addWidget(btn_3)
-
h_box.addWidget(btn_4)
-
self.setLayout(h_box)
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
w1 = Form1()
-
w2 = Form2()
-
w1.show()
-
w1.btn_1.clicked.connect(w1.close_window)
-
w1.btn_2.clicked.connect(w2.display)
-
app.exec_()
布局示例:
PyQt入门(五)— 布局:https://blog.csdn.net/qq_34710142/article/details/80875625
-
from PyQt5
import QtWidgets
-
-
-
class MyWindow(QtWidgets.QWidget):
-
-
def __init__(self):
-
super().__init__()
-
self.setWindowTitle(
'嵌套布局示例')
-
-
# 开始:
-
wlayout = QtWidgets.QHBoxLayout()
# 全局布局(1个):水平
-
-
hlayout = QtWidgets.QHBoxLayout()
# 局部布局(4个):水平、竖直、网格、表单
-
vlayout = QtWidgets.QVBoxLayout()
-
glayout = QtWidgets.QGridLayout()
-
flayout = QtWidgets.QFormLayout()
-
-
hlayout.addWidget(QtWidgets.QPushButton(str(
1)))
# 局部布局添加部件(例如:按钮)
-
hlayout.addWidget(QtWidgets.QPushButton(str(
2)))
-
vlayout.addWidget(QtWidgets.QPushButton(str(
3)))
-
vlayout.addWidget(QtWidgets.QPushButton(str(
4)))
-
glayout.addWidget(QtWidgets.QPushButton(str(
5)),
0,
0)
-
glayout.addWidget(QtWidgets.QPushButton(str(
6)),
0,
1)
-
glayout.addWidget(QtWidgets.QPushButton(str(
7)),
1,
0)
-
glayout.addWidget(QtWidgets.QPushButton(str(
8)),
1,
1)
-
flayout.addWidget(QtWidgets.QPushButton(str(
9)))
-
flayout.addWidget(QtWidgets.QPushButton(str(
10)))
-
flayout.addWidget(QtWidgets.QPushButton(str(
11)))
-
flayout.addWidget(QtWidgets.QPushButton(str(
12)))
-
-
hwg = QtWidgets.QWidget()
# 准备四个部件
-
vwg = QtWidgets.QWidget()
-
gwg = QtWidgets.QWidget()
-
fwg = QtWidgets.QWidget()
-
-
hwg.setLayout(hlayout)
# 四个部件设置局部布局
-
vwg.setLayout(vlayout)
-
gwg.setLayout(glayout)
-
fwg.setLayout(flayout)
-
-
wlayout.addWidget(hwg)
# 四个部件加至全局布局
-
wlayout.addWidget(vwg)
-
wlayout.addWidget(gwg)
-
wlayout.addWidget(fwg)
-
-
self.setLayout(wlayout)
# 窗体本尊设置全局布局
-
-
-
if __name__ ==
"__main__":
-
import sys
-
-
app = QtWidgets.QApplication(sys.argv)
-
win = MyWindow()
-
win.show()
-
sys.exit(app.exec_())
效果:
布局 时 需要注意点
继承 QMainWindow 时布局界面 和 继承 QWidget 时 布局界面 是不一样的
1. 继承 QMainWindow 时 的界面布局
如何给QMainWindow正确地设置布局( C++ 示例 步骤)
- 第一步:创建一个QWidget实例,并将这个实例设置为 centralWidget:
QWidget *widget = new QWidget();
this->setCentralWidget(widget); - 第二部:创建一个主布局mainLayout,并把所需要的所有控件都往里面放(工具栏、菜单栏、状态栏除外):
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(...);
mainLayout->addLayout(...);
... - 第三步:将 widget 的布局设置为 mainLayout:
centralWidget()->setLayout(mainLayout);
//centralWidget()返回的是第一步创建的那个QWidget实例
继承 QMainWindow 时,需要设置 中心部件(即 主界面),如下面代码需要添加三行代码:
-
main_widget = QWidget()
# 界面 实例
-
self.setCentralWidget(main_widget)
# 设置 为 中心界面
-
......
-
......
-
self.centralWidget().setLayout(v_box)
# 设置中心界面的布局
根据 C++ 示例 步骤改成 python ,完整示例代码如下:
-
import sys
-
-
# QMainWindow 类提供了一个主要的应用程序窗口。
-
# 你用它可以让应用程序添加状态栏,工具栏和菜单栏。
-
from PyQt5.QtWidgets
import QWidget, QMainWindow
-
-
from PyQt5.QtWidgets
import (
-
QApplication, QDesktopWidget, QHBoxLayout, QVBoxLayout,
-
QPushButton, QListView,
-
)
-
-
-
class LayoutDemoByQMainWindow(QMainWindow):
-
-
def __init__(self):
-
super(LayoutDemoByQMainWindow, self).__init__()
-
self.resize(
1000,
600)
# 重置大小
-
self._center_display()
# 中心显示
-
self.vertical_layout()
-
self.show()
-
-
def _center_display(self):
-
"""
-
控制窗口显示在屏幕中心的方法
-
:return:
-
"""
-
# 获得窗口
-
qr = self.frameGeometry()
-
# 获得屏幕中心点
-
cp = QDesktopWidget().availableGeometry().center()
-
# 显示到屏幕中心
-
qr.moveCenter(cp)
-
self.move(qr.topLeft())
-
-
def vertical_layout(self):
-
"""
-
垂直布局
-
:return:
-
"""
-
###################################
-
main_widget = QWidget()
-
self.setCentralWidget(main_widget)
-
###################################
-
-
h_box_1 = QHBoxLayout()
-
h_box_2 = QHBoxLayout()
-
h_box_3 = QHBoxLayout()
-
-
btn_ok = QPushButton(
'Ok', self)
-
btn_cancel = QPushButton(
'Cancel', self)
-
btn_exit = QPushButton(
'Exit', self)
-
btn_ok.resize(
10,
10)
-
btn_cancel.resize(
10,
10)
-
btn_exit.resize(
40,
10)
-
-
# h_box_1.addStretch(1)
-
h_box_1.addWidget(btn_ok)
-
h_box_1.addWidget(btn_cancel)
-
h_box_1.addWidget(btn_exit)
-
-
list_view = QListView(self)
-
h_box_2.addWidget(list_view)
-
-
btn_1 = QPushButton(
'btn_1', self)
-
btn_2 = QPushButton(
'btn_2', self)
-
btn_3 = QPushButton(
'btn_3', self)
-
h_box_3.addStretch(
1)
-
h_box_3.addWidget(btn_1)
-
h_box_3.addWidget(btn_2)
-
h_box_3.addWidget(btn_3)
-
-
v_box = QVBoxLayout()
-
v_box.addLayout(h_box_1)
-
v_box.addLayout(h_box_2)
-
v_box.addLayout(h_box_3)
-
-
###################################
-
self.centralWidget().setLayout(v_box)
-
###################################
-
pass
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
# form_1 = LayoutDemoByQWidget()
-
form = LayoutDemoByQMainWindow()
-
sys.exit(app.exec_())
-
pass
示例代码 2:
-
from PyQt5.QtWidgets
import QApplication, QMainWindow, QTextEdit, QWidget, QVBoxLayout, QFrame
-
from PyQt5.Qt
import QSize
-
import sys
-
-
-
class Example(QMainWindow):
-
-
def __init__(self):
-
super(Example, self).__init__()
-
-
self._init_ui()
-
-
def _init_ui(self):
-
# 控件随窗口改变而改变
-
# 可以通过继承 QMainWindow 来实现
-
self.resize(
400,
400)
-
# 建立顶层控件
-
self.centeralwidget = QWidget()
-
self.v_box = QVBoxLayout(self.centeralwidget)
-
edit = QTextEdit()
-
self.v_box.addWidget(edit)
-
# 通过设置中心控件,将子控件填充布局
-
# 如果有多个控件最好在加一层widget这样最好布局,控制
-
self.setCentralWidget(self.centeralwidget)
-
self.show()
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
ex = Example()
-
sys.exit(app.exec_())
示例代码 3:
-
from PyQt5
import QtWidgets
-
import sys
-
-
-
# 主窗口类
-
class MainWidget(QtWidgets.QMainWindow):
-
def __init__(self):
-
super().__init__()
-
self.resize(
500,
300)
-
self.setWindowTitle(
"")
# 设置窗口标题
-
main_widget = QtWidgets.QWidget()
# 实例化一个widget部件
-
main_layout = QtWidgets.QGridLayout()
# 实例化一个网格布局层
-
main_widget.setLayout(main_layout)
# 设置主widget部件的布局为网格布局
-
self.setCentralWidget(main_widget)
# 设置窗口默认部件为主widget
-
-
-
if __name__ ==
'__main__':
-
app = QtWidgets.QApplication(sys.argv)
-
gui = MainWidget()
-
gui.show()
-
sys.exit(app.exec_())
2. 继承 QWidget 时 的界面布局
继承 Qwidget 时,不需要设置中心部件,直接布局就行。最后把 Qwidget 的布局设置成 你自己的布局即可。
self.setLayout(v_box)
完成示例代码:
-
import sys
-
-
# QMainWindow 类提供了一个主要的应用程序窗口。
-
# 你用它可以让应用程序添加状态栏,工具栏和菜单栏。
-
from PyQt5.QtWidgets
import QWidget
-
-
from PyQt5.QtWidgets
import (
-
QApplication, QDesktopWidget, QHBoxLayout, QVBoxLayout,
-
QPushButton, QListView,
-
)
-
-
-
class LayoutDemoByQWidget(QWidget):
-
-
def __init__(self):
-
super(LayoutDemoByQWidget, self).__init__()
-
self.resize(
1000,
600)
# 重置大小
-
self._center_display()
# 中心显示
-
self.vertical_layout()
-
self.show()
-
-
def _center_display(self):
-
"""
-
控制窗口显示在屏幕中心的方法
-
:return:
-
"""
-
# 获得窗口
-
qr = self.frameGeometry()
-
# 获得屏幕中心点
-
cp = QDesktopWidget().availableGeometry().center()
-
# 显示到屏幕中心
-
qr.moveCenter(cp)
-
self.move(qr.topLeft())
-
-
def vertical_layout(self):
-
"""
-
垂直布局
-
:return:
-
"""
-
h_box_1 = QHBoxLayout()
-
h_box_2 = QHBoxLayout()
-
h_box_3 = QHBoxLayout()
-
-
btn_ok = QPushButton(
'Ok', self)
-
btn_cancel = QPushButton(
'Cancel', self)
-
btn_exit = QPushButton(
'Exit', self)
-
btn_ok.resize(
10,
10)
-
btn_cancel.resize(
10,
10)
-
btn_exit.resize(
40,
10)
-
-
# h_box_1.addStretch(1)
-
h_box_1.addWidget(btn_ok)
-
h_box_1.addWidget(btn_cancel)
-
h_box_1.addWidget(btn_exit)
-
-
list_view = QListView(self)
-
h_box_2.addWidget(list_view)
-
-
btn_1 = QPushButton(
'btn_1', self)
-
btn_2 = QPushButton(
'btn_2', self)
-
btn_3 = QPushButton(
'btn_3', self)
-
h_box_3.addStretch(
1)
-
h_box_3.addWidget(btn_1)
-
h_box_3.addWidget(btn_2)
-
h_box_3.addWidget(btn_3)
-
-
v_box = QVBoxLayout()
-
# v_box.addStretch(1)
-
v_box.addLayout(h_box_1)
-
v_box.addLayout(h_box_2)
-
v_box.addLayout(h_box_3)
-
-
# 把 默认布局 设置成 v_box
-
self.setLayout(v_box)
-
pass
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
form = LayoutDemoByQWidget()
-
sys.exit(app.exec_())
-
pass
一篇文章让你读懂PyQt5布局管理,绝对干货
From:https://cloud.tencent.com/developer/article/1437295
python爬虫实战之路:https://cloud.tencent.com/developer/column/4821
pyqt5 - 布局控件 :https://www.cnblogs.com/liming19680104/p/10356142.html
Python 图形开发:PyQt 三种界面布局解析:http://www.codebelief.com/article/2017/04/python-gui-development-pyqt-three-kinds-of-layout/
Qt 之水平/垂直布局(QBoxLayout、QHBoxLayout、QVBoxLayout):https://blog.csdn.net/liang19890820/article/details/51537246
PyQt5 布局大全:https://blog.csdn.net/jeekmary/article/details/80208601
PyQt5之布局管理:https://www.cnblogs.com/laizhenghong2012/p/10040798.html
窗体的四个角布局:http://www.bubuko.com/infodetail-2838999.html
继承图:
在布局中添加控件用addWidght(),添加布局用addLayout()
PyQt5 的界面布局主要有两种方法:绝对定位和局部类。在PyQt5中有四种布局方式:水平布局、垂直布局、网格布局、表单布局。还有两种布局方法:addLayout和addWidget,其中addLayout用于在布局中插入子布局,addWidget用于在布局中插入控件。
- 垂直布局:控件默认按照从上到下的顺序进行纵向添加。
- 水平布局:控件默认按照从左到右的顺序进行横向添加。
- 栅格布局:将窗口分为若干行(row)和列(column)。
- 表单布局:控件以两列的形式布局在窗口中,左边为标签,右边为输入控件。
使用布局管理器
- 绝对布局 这个就不详细说明了,使用 QWidget 的 move、setGeometry 等方法,直接设置其在窗口中的位置。
- 盒子布局(QHBoxLayout 水平布局、QVBoxLayout 垂直布局) 方法:
- stretch(伸缩量),只适用于QBoxLayout布局方式,控件和窗口会随着伸缩量的变大而增加
- alignment,指定对齐方式
- addLayout(self, QLayout, stretch=0) 在窗口的右边添加布局,使用stretch(伸缩量)进行伸缩,默认为0
- addWidget(self, QWidget, stretch, Qt.Alignment) 在布局中添加控件。
- QGridLayout 栅格布局(网格布局) 方法:
- addLayout(QLayout, row, column, Qt.Alignment) 在栅格布局的行(row)、列(column)位置添加新的布局,并设置对齐方式
- addLayout(QLayout, row, column, rowSpan, columnSpan, Qt.Alignment) 在栅格布局中新的布局,从行(row)、列(column)开始,占据rowSpan行、columnSpan列
- addWidget(QWidget, row, column, Qt.Alignment) 在栅格布局的行(row)、列(column)中添加窗口控件,
- addWidget(QWidget, fromRow, fromColumn, rowSpan, columnSpan, Qt.Alignment) 在栅格布局中添加窗口控件,从行(row)、列(column)开始,占据rowSpan行、columnSpan列
- setRowStretch(row, stretch) 在行(row)处添加伸缩量
- setColumnStretch(column, stretch) 在列(column)处添加伸缩量
- QFormLayout 表单布局 方法:
- addRow(QWidget, QWidget)
- addRow(QWidget, QLayout)
- addRow(str, QWidget)
- addRow(str, QLayout) 以上在表单布局最后添加一行数据,设置表单的标签和控件
- addRow(QWidget)
- addRow(QLayout) QWidget和QLayout添加在最后一行,并占据两列宽度
- insertRow(row, QWidget, QWidget)
- insertRow(row, QWidget, QLayout)
- insertRow(row, str, QWidget)
- insertRow(row, str, QLayout) 在指定行添加标签和控件
- insertRow(row, QWidget)
- insertRow(row, QLayout) 在指定行添加控件,并占据两列宽度
盒布局名字虽然听起来怪怪的,但是却非常形象,主要借助两个函数QHBoxLayout(水平方向)和QVBoxLayout(竖直方向),建立一个个水平方向或者是竖直方向的“盒子”,盒子本身整齐排列,同时把盒子内部的组件也整齐排列,这样整体来看就显得会很整齐。就像小时候写作业一样,放置内容之前之间先给你把区域划好了。
示例代码:
-
import sys
-
from PyQt5.QtWidgets
import (QWidget, QPushButton,
-
QHBoxLayout, QVBoxLayout, QApplication,QMainWindow)
-
-
class Example(QWidget):
-
-
def __init__(self):
-
super().__init__()
-
self.initUI()
-
-
-
def initUI(self):
-
# 添加5个按钮
-
Button1 = QPushButton(
"按钮1")
-
Button2 = QPushButton(
"按钮2")
-
Button3 = QPushButton(
"按钮3")
-
Button4 = QPushButton(
"按钮4")
-
Button5 = QPushButton(
"按钮5")
-
-
#添加一个竖直盒子,两个水平盒子
-
hbox1 = QHBoxLayout()
-
hbox2 = QHBoxLayout()
-
# hbox = QHBoxLayout()
-
vbox = QVBoxLayout()
-
-
-
#把按钮放在盒子里
-
vbox.addWidget(Button1)
-
vbox.addWidget(Button2)
-
vbox.addWidget(Button3)
-
hbox2.addWidget(Button4)
-
hbox2.addWidget(Button5)
-
-
#把竖直盒子和水平盒子嵌套在水平盒子中
-
hbox1.addLayout(vbox)
-
hbox1.addLayout(hbox2)
-
-
self.setLayout(hbox1)
-
self.setGeometry(
400,
400,
600,
300)
-
self.setWindowTitle(
'盒布局示例')
-
self.show()
-
-
-
if __name__ ==
'__main__':
-
-
app = QApplication(sys.argv)
-
ex = Example()
-
sys.exit(app.exec_())
效果如下:
在盒布局里,还有一个特别有用的函数:布局.addStretch(int)
。这个函数很形象,就是在布局之内添加一个弹簧,使组件之间有空隙。int值代表“弹簧”的长度。
在QT Designer中,你可以看到这个组件就是一个弹簧样子的。
需要注意的是:弹簧控件是按照这个弹簧的比例分的,比如:
-
hbox.addStretch(
1)
#hbox是一个水平“盒子”
-
hbox.addWidget(Button1)
-
hbox.addStretch(
1)
-
hbox.addWidget(Button2)
-
hbox.addStretch(
1)
就是把hbox
这个盒子剩余空间等分成三份,如果把中间的弹簧改成2,那么就是把这个盒子剩余空间等分成4分,中间的空间占两份。对比如下:
布局对齐方式:
参数 | 描述 |
---|---|
QtCore.Qt.AlignLeft | 水平方向居左对齐 |
QtCore.Qt.AlignRight | 水平方向居右对齐 |
QtCore.Qt.AlignCenter | 水平方向居中对齐 |
QtCore.Qt.AlignJustify | 水平方向两端对齐 |
QtCore.Qt.AlignTop | 垂直方向靠上对齐 |
QtCore.Qt.AlignBottom | 垂直方向靠下对齐 |
QtCore.Qt.AlignVCenter | 垂直方向居中对齐 |
间距
-
addSpacing(self, int)
# 设置各控件的上下间距,通过该方法可以增加额外的控件
-
addStretch(self, int)
# 分配布局大小比例
-
insertStretch(index, stretch =
0)
# 在指定控件间隔处添加布局比例
-
insertSpacing(index, size)
#在指定控件间隔处设置间隔大小
addStretch 是按照比例来调整界面布局,在页面布局中使用广泛,所以我们要使用一定的篇幅来进行代码测试。
使用 addStretch,我们可以实现各种对齐方式,而且更加灵活。
-
import sys
-
from PyQt5.QtWidgets
import QApplication, QWidget, QPushButton, QHBoxLayout
-
-
-
class Example(QWidget):
-
def __init__(self):
-
super().__init__()
-
self.initUI()
-
-
def initUI(self):
-
layout = QHBoxLayout()
-
layout.addWidget(QPushButton(str(
1)))
-
layout.addWidget(QPushButton(str(
2)))
-
-
self.setLayout(layout)
-
self.setGeometry(
300,
300,
400,
100)
-
self.setWindowTitle(
"Buttons")
-
-
-
if __name__ ==
"__main__":
-
app = QApplication(sys.argv)
-
ex = Example()
-
ex.show()
-
sys.exit(app.exec_())
-
默认是所有控件撑满整个布局文件。运行结果截图:
按比例布局:
-
layout.addWidget(btn)
-
layout.addWidget(tableWidget)
-
layout.addLayout(h_layout)
-
-
layout.setStretchFactor(btn,
1)
-
layout.setStretchFactor(tableWidget,
2)
-
layout.setStretchFactor(h_layout,
2)
调用 setStretchFactor 函数后,三个控件的比例分别为:1:2:2
- 水平居左对齐 ~ QtCore.Qt.AlignLeft
-
def initUI(self):
-
layout = QHBoxLayout()
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
-
layout.addStretch(
1)
# 新增这一行。把 剩余空间分成一份,最后添加这一份的间隔
-
......
在两个控件后增加这一行,相当于水平布局中存在:按钮1 ,按钮2, stretch。此时 addStretch 的参数只要大于0,则表示占满整个布局最后一部分,前面的控件显示为正常大小,不要拉伸。
- 水平居右对齐 ~ QtCore.Qt.AlignRight
-
def initUI(self):
-
layout = QHBoxLayout()
-
-
layout.addStretch(
1)
# 新增这一行在控件前面
-
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
......
这一行加入到布局中所有控件之前,相当于水平布局中存在:stretch-按钮1-按钮2,表示占满整个布局的最开始部分,后面的控件显示为正常大小,不要拉伸。
- 水平居中对齐 ~ QtCore.Qt.AlignCenter
-
def initUI(self):
-
layout = QHBoxLayout()
-
-
layout.addStretch(
1)
# 前面增加一行
-
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
-
layout.addStretch(
1)
#后面增加一行
-
......
stretch,按钮1,按钮2,stretch,表示左右两边充满,控件占据中间位置
注意:当一个布局中出现多个addStretch时,后面的参数就有意义了,其表示整个布局的大小减去控件总大小进行n等份分配。
例如:
-
def initUI(self):
-
layout = QHBoxLayout()
-
layout.addStretch(
1)
# 注意1
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
layout.addStretch(
3)
# 注意2
表示除去控件1、控件2 的宽度,剩余部分四等份,前面占据一份,最后面占据三份
- 水平两端对齐 ~ QtCore.Qt.AlignJustify
-
def initUI(self):
-
layout = QHBoxLayout()
-
layout.addWidget(QPushButton(str(
1))
-
layout.addStretch(
1)
# 添加行
-
layout.addWidget(QPushButton(str(
2))
- 垂直顶部对齐 ~ QtCore.Qt.AlignTop
-
def initUI(self):
-
layout = QVBoxLayout()
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
layout.addStretch(
1)
# 添加行
- 垂直底部对齐 ~ QtCore.Qt.AlignBottom
-
def initUI(self):
-
layout = QVBoxLayout()
-
layout.addStretch(
1)
# 添加行
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
- 垂直居中对齐 ~ QtCore.Qt.AlignVCenter
-
def initUI(self):
-
layout = QVBoxLayout()
-
layout.addStretch(
1)
# 添加行
-
layout.addWidget(QPushButton(str(
1))
-
layout.addWidget(QPushButton(str(
2))
-
layout.addStretch(
1)
# 添加行
- 垂直两端对齐
-
def initUI(self):
-
layout = QVBoxLayout()
-
layout.addWidget(QPushButton(str(
1))
-
layout.addStretch(
1)
# 添加行
-
layout.addWidget(QPushButton(str(
2))
如果要进行组合布局,例如左上角、右下角等,如下:
-
def initUI(self):
-
layout1 = QHBoxLayout()
-
layout1.addWidget(QPushButton(str(
1))
-
layout1.addWidget(QPushButton(str(
2))
-
layout1.addStretch(
1)
# 水平居左
-
-
layout2 = QVBoxLayout()
-
layout2.addLayout(layout1)
-
layout2.addStretch(
1)
# 垂直顶部对齐
-
-
self.setLayout(layout2)
-
......
addSpacing
addSpacing是设置控件之间的间距。就按照图1的布局及代码进行演示。
-
def initUI(self):
-
layout = QHBoxLayout()
-
layout.addWidget(QPushButton(str(
1))
-
layout.addSpacing(
100)
-
layout.addWidget(QPushButton(str(
2))
间距设置可以放置在任何地方,对于调整控件位置十分有效。相当于在控件之间添加了一个空的控件。详细的用法与addStrech类似,参考以上使用即可。
QSplitter
控件大小占比不固定,可以通过拖拽两个控件的边界改变控件占比大小
-
import sys
-
from PyQt5.QtWidgets
import (QWidget, QHBoxLayout, QFrame,
-
QSplitter, QTextEdit, QApplication)
-
from PyQt5.QtCore
import Qt
-
-
-
class SplitterExample(QWidget):
-
def __init__(self):
-
super(SplitterExample, self).__init__()
-
self.initUI()
-
-
def initUI(self):
-
# 初始化控件
-
topleft = QFrame()
-
topleft.setFrameShape(QFrame.StyledPanel)
-
bottom = QFrame()
-
bottom.setFrameShape(QFrame.StyledPanel)
-
textedit = QTextEdit()
-
-
# 设置第一个Splitter的布局方向
-
splitter1 = QSplitter(Qt.Horizontal)
-
# 为第一个Splitter添加控件,并设置两个控件所占空间大小
-
splitter1.addWidget(topleft)
-
splitter1.addWidget(textedit)
-
splitter1.setSizes([
100,
200])
-
-
# 设置第二个Splitter的布局方向,将第一个Splitter嵌套在第二个里
-
splitter2 = QSplitter(Qt.Vertical)
-
splitter2.addWidget(splitter1)
-
splitter2.addWidget(bottom)
-
-
# 设置全局布局
-
hbox = QHBoxLayout(self)
-
hbox.addWidget(splitter2)
-
self.setLayout(hbox)
-
-
self.setWindowTitle(
'QSplitter 例子')
-
self.setGeometry(
300,
300,
300,
200)
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
demo = SplitterExample()
-
demo.show()
-
sys.exit(app.exec_())
【第 5 节】PyQt5 事件 和 信号 演示代码
( 可以 把 __init__ 函数中的 注释逐个取消,然后运行程序看执行效果 ):
-
# -*- coding: utf-8 -*-
-
# @Author :
-
# @File : main.py
-
# @Software: PyCharm
-
# @description : XXX
-
-
-
import sys
-
from PyQt5.QtCore
import Qt
-
from PyQt5.QtWidgets
import (
-
QWidget, QMainWindow, QLCDNumber, QSlider, QVBoxLayout, QApplication, QPushButton
-
)
-
-
from PyQt5.QtCore
import pyqtSignal, QObject
-
-
-
class Communicate(QObject):
-
"""
-
创建了一个名为closeApp的信号。
-
这个信号会在按下鼠标时触发,它连接着QMainWindow的close()插槽。
-
"""
-
closeApp = pyqtSignal()
-
-
-
# class MyForm(QWidget):
-
class MyForm(QMainWindow):
-
-
def __init__(self):
-
super(MyForm, self).__init__()
-
# self._init_ui_1()
-
# self._init_ui_2()
-
# self._init_ui_3()
-
self._init_ui_4()
-
-
def _init_ui_1(self):
-
"""
-
展示了一个QtGui.QLCDNumber和QtGui.QSlider。lcd的值会随着滑块的拖动而改变。
-
:return:
-
"""
-
lcd = QLCDNumber(self)
-
sld = QSlider(Qt.Horizontal, self)
-
-
vbox = QVBoxLayout()
-
vbox.addWidget(lcd)
-
vbox.addWidget(sld)
-
-
self.setLayout(vbox)
-
-
##########################################################
-
# 这里我们将滚动条的 valueChanged信号连接到lcd的display插槽。
-
# sender是发出信号的对象。
-
# receiver是接收信号的对象。
-
# slot(插槽)是对信号做出反应的方法。
-
sld.valueChanged.connect(lcd.display)
-
##########################################################
-
-
self.setGeometry(
300,
300,
500,
300)
-
self.setWindowTitle(
'Signal & slot')
-
self.show()
-
-
def _init_ui_2(self):
-
self.setGeometry(
300,
300,
500,
300)
-
self.setWindowTitle(
'Event handler')
-
self.show()
-
-
def keyPressEvent(self, e):
-
"""
-
重写 keyPressEvent 事件
-
:param e:
-
:return:
-
"""
-
if e.key() == Qt.Key_Escape:
-
self.close()
-
-
def _init_ui_3(self):
-
btn1 = QPushButton(
"Button 1", self)
-
btn1.move(
30,
50)
-
-
btn2 = QPushButton(
"Button 2", self)
-
btn2.move(
150,
50)
-
-
# 按钮的点击信号 连接到 槽(槽就是一个函数)buttonClicked
-
# 两个按钮连接到了同一个插槽。
-
btn1.clicked.connect(self.buttonClicked)
-
btn2.clicked.connect(self.buttonClicked)
-
-
self.statusBar()
-
-
self.setGeometry(
300,
300,
500,
300)
-
self.setWindowTitle(
'Event sender')
-
self.show()
-
-
def buttonClicked(self):
-
# 通过调用sender()方法来判断当前按下的是哪个按钮
-
sender = self.sender()
-
-
# 通过调用sender()方法来判断信号源, 并将其名称显示在窗体的状态栏中。
-
self.statusBar().showMessage(sender.text() +
' was pressed')
-
-
def _init_ui_4(self):
-
"""
-
通过QObject创建的对象可以发出信号。
-
这个示例演示了如何发出自定义信号
-
:return:
-
"""
-
# 信号closeApp 是 Communicate的类属性,它由 pyqtSignal()创建。
-
self.c = Communicate()
-
-
# 自定义closeApp信号连接到QMainWindow的close槽
-
# 当在窗体上点击鼠标时会触发closeApp信号,使程序退出。
-
self.c.closeApp.connect(self.close)
-
-
self.setGeometry(
1000,
300,
500,
300)
-
self.setWindowTitle(
'Emit signal')
-
self.show()
-
-
def mousePressEvent(self, event):
-
self.c.closeApp.emit()
-
-
-
if __name__ ==
'__main__':
-
app = QApplication(sys.argv)
-
form = MyForm()
-
sys.exit(app.exec_())
-
pass
-
【第 6 节】对话框 演示代码
演示代码:
-
import sys
-
from PyQt5.QtWidgets
import (
-
QWidget, QMainWindow, QPushButton, QLineEdit, QInputDialog, QApplication, QFrame, QColorDialog,
-
QVBoxLayout, QSizePolicy, QLabel, QFontDialog, QTextEdit, QAction, QFileDialog
-
)
-
from PyQt5.QtGui
import QColor
-
from PyQt5.QtGui
import QIcon
-
-
-
# class MyForm(QWidget):
-