pyqt5学习笔记1: 常用组件的使用
目录
- 1 快速启动一个窗口
- 2 窗口基本设置
- 3 QTabWidget(页签)
- 4 QTreeWidget(树)
- 5 QTableWidget(表格)
- 6 QDockWidget(可拖动窗口)
- 7 自定义可折叠Widget
- 8 QMessageBox(消息框)
- 9. 特殊对话框(打开文件, 保存文件, 选择颜色)
- 10. 给Widget加滚动条
- 11 QProgressBar(进度条)
- 12 QSlider和QSpinBox
- 13 QComboBox
- 14 QRadioButton(单选框)
- 15 QCheckBox(复选框)
1 快速启动一个窗口
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
app = QtWidgets.QApplication(sys.argv) # 例化Widget前必须先例化一个app。
win = QtWidgets.QWidget() # 例化Widget
win.show() # 显示Widget
sys.exit(app.exec_()) # 当app退出时,退出当前python程序
2 窗口基本设置
窗口位置、大小、图标、标题、布局
效果图:
------------------------------------
| <> 一个窗口样例 - 口 X|
------------------------------------
| ---------------------------- |
| 姓名 | 输入条 | |
| ---------------------------- |
| |
| |
| ---- ---- |
| |取消| |提交| |
| ---- ---- |
-------------------------------------
代码
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
class CDemo(QtWidgets.QWidget):
def __init__(self):
super().__init__() # 要先调用QWidget(父类)的初始化函数.
#窗口中的几个部件
self.o_label = QtWidgets.QLabel('姓名')
self.o_line_edit = QtWidgets.QLineEdit('输入条')
self.o_btn_0 = QtWidgets.QPushButton('取消')
self.o_btn_1 = QtWidgets.QPushButton('提交')
# 窗口位置与大小,参数:x位置,y位置, x宽度, y高度
self.setGeometry(200, 200, 400, 200) #self.resize(400, 300)
# 窗口图标,显示在窗口标题拦最左边.
self.setWindowIcon(QtGui.QIcon('collapse_on.png'))
# 窗口标题,显示在窗口标题拦.
self.setWindowTitle('一个窗口样例')
# 设置窗口内组件摆放
self.setLayout(self.__gen_layout())
def __gen_layout(self):
# 子layout,水平放置标签和输入框,标签使用默认宽度,输入框拉伸占满其余宽度。
_o_layout_0 = QtWidgets.QHBoxLayout()
_o_layout_0.addWidget(self.o_label) # 添加Widget
_o_layout_0.addWidget(self.o_line_edit)
# 子layout,水平放置两个按钮, 靠右对齐.
_o_layout_1 = QtWidgets.QHBoxLayout()
_o_layout_1.addStretch(1) # stretch 占满左侧空间, 1是个比例,不代表绝对值.
_o_layout_1.addWidget(self.o_btn_0)
_o_layout_1.addWidget(self.o_btn_1)
_o_layout_1.addSpacing(10) # 最右侧空出10px的空白.
# 主layout, 垂直放置子layout.
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_0) # 添加layout
_o_layout_main.addStretch(1) # 中间拉伸,使按钮放置到最底下.
_o_layout_main.addLayout(_o_layout_1)
return _o_layout_main
app = QtWidgets.QApplication(sys.argv)
win = CDemo()
win.show()
sys.exit(app.exec_())
3 QTabWidget(页签)
效果图
代码
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
class CDemo(QtWidgets.QTabWidget):
def __init__(self):
super().__init__()
'''设置tab标签的位置'''
self.setTabPosition(QtWidgets.QTabWidget.North)
'''设置tab可以关闭, 默认情况下tab不可关'''
self.setTabsClosable(True)
self.tabCloseRequested.connect(self.__on_tab_close_clicked)
'''添加tab, 参数:widget, tab_name'''
self.addTab(QtWidgets.QTextEdit('A'), 'Tab 0')
self.addTab(QtWidgets.QTextEdit('B'), 'Tab 1')
self.setWindowTitle('A tab example')
def __on_tab_close_clicked(self, idx):
if self.count()>=1:
self.widget(idx).deleteLater()
self.removeTab(idx)
app = QtWidgets.QApplication(sys.argv)
win = CDemo()
win.show()
sys.exit(app.exec_())
4 QTreeWidget(树)
创建tree
#创建Tree, 指定表头和列数
o_tree = QtWidgets.QTreeWidget()
o_tree.setHeaderLabels['name', 'value']
o_tree.setColumnCount(2)
#给Tree添加item:
o_child_0 = QtWidgets.QTreeWidgetItem(o_tree) # 参数为它的上一级树
o_child_0.setText(0, 'node0') # 给第一列赋值
o_child_00 = QtWidgets.QTreeWidgetItem(o_child_0) # 参数为它的上一级树
o_child_00.setText(0, 'node00') # 给第一列赋值
遍历tree
#遍历tree
o_item_iter = QtWidgets.QTreeWidgetItemIterator(o_tree)
while o_item_iter.value():
_o_curr_tree_item = o_item_iter.value()
#do something for _o_curr_tree_item
_o_item_iter.__iadd__(1)
QTreeWidgetItem自带CheckBox,可以直接设置Check状态
#三种Check状态:
QtCore.Qt.Checked # 选中
QtCore.Qt.UnChecked # 未选中
QtCore.Qt.PartiallyChecked # 半选中
#设置、获取Check状态:
o_tree_item.setCheckState(0, QtCore.Qt.Unchecked) # 设置当前tree item第0列的check状态
o_tree_item.checkState(0) # 获取当前tree item第0列的check状态
QTreeWidgetItem设置图标/设置列宽
#设置第0列图标
o_tree_item.setIcon(0, QtGui.QIcon('xx.png'))
#设置第0列列宽
o_tree.setColumnWidth(0, 100)
获取当前Tree、Item的父容器、子Item
#获取tree item的父容器(可能是tree,也可能是item)
o_tree_or_item = o_tree_item.parent()
#获取tree item最顶部的tree widget
o_tree = o_tree_item.treeWidget()
#获取tree/item的child:
for i in range(o_tree_item.childCount()):
_o_child = o_tree_item.child(i)
5 QTableWidget(表格)
效果图:
创建表格
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
import sys
import time
class CDemo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.o_table = self._gen_table()
self.resize(500, 300)
self.setLayout(self._gen_layout())
def _gen_table(self):
_o_table = QtWidgets.QTableWidget()
'''设置行数、列数'''
_o_table.setRowCount(2)
_o_table.setColumnCount(3)
'''为第0行添加单元格,单元格内容为文本'''
for i in range(3):
_o_table.setItem(0, i, QtWidgets.QTableWidgetItem(f'cell0{i}'))
'''为第1行添加单元格,单元格内容为其它Widget'''
for i in range(3):
_o_table.setCellWidget(1, i, self._gen_combox())
'''设置水平、垂直表头'''
_o_table.setHorizontalHeaderLabels(['A', 'B', 'C'])
_o_table.setVerticalHeaderLabels(['0', '1'])
'''设置表头可见,默认可见'''
_o_table.horizontalHeader().setVisible(True)
_o_table.verticalHeader().setVisible(True)
'''设置鼠标悬停表头时的tip'''
_o_table.horizontalHeaderItem(0).setToolTip('This is Column A')
'''设置列宽、行高根据内容调整,
注意,设置些命令后,再重新给单元格赋值,列宽、行高不会自动调整
即这个设置是静态设置
'''
_o_table.resizeColumnsToContents()
_o_table.resizeRowsToContents()
'''设置特定行/列的列宽、行高'''
_o_table.setRowHeight(0, 20)
_o_table.setColumnWidth(0, 100)
return _o_table
def _gen_combox(self):
_o_combox = QtWidgets.QComboBox()
_o_combox.addItems(['0', '1', '2', '3'])
return _o_combox
def _gen_layout(self):
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addWidget(self.o_table)
return _o_layout_main
app = QtWidgets.QApplication(sys.argv)
win = CDemo()
win.show()
sys.exit(app.exec_())
表格常用设置
#清空整个表格的内容(行、列会保留):
o_table.clear()
o_table.clearSpan() # Span信息要单独清除
#行操作
o_table.rowCount() # 获取行数目
o_table.setRowCount(10) # 设置行数目
o_table.insertRow(7) # 在表格中第6行下面添加一行做为第7行(添加行后才能往行中添加单元格)
o_table.removeRow(i) # 删除行
#删除所有行:注意要倒序删除,因为删除过程中行序号是动态变化的。
for i in range(o_table.rowCount()-1, -1, -1):
o_table.removeRow(i)
#给单元格设置item、widget
o_table.setItem(i, j, o_table_item)
o_table.setCellWidget(i, j, o_widget)
#获取单元格item/widget:
o_table_item = o_table.item(i, j) # 普通文本单元格,类型是QTableWidgetItem
o_widget = o_table.cellWidget(i, j) # 单元格内容是QWidget时,通过cellWidget获取。
#遍历单元格:
for i in range(o_table.rowCount()):
for j in range(o_table.columnCount()):
o_item = o_table.item(i, j) # 如果该单元格是cellwidget, 则需要用o_table.cellwidget(i, j)
#获取行高之和
i_height = 0
for i in range(o_table.rowCount()):
i_height += o_table.rowHeight(i)
#设置单元格文本对齐方式:格式:水平对齐方式 | 垂直对齐方式
o_table_item.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)
#设置单元格背景色:
o_table_item.setBackground(QtGui.QColor(220, 220, 220))
#设置单元格不可编辑, 不可选中:
o_table_item.setFlags(o_table_item.flags() & ~QtCore.Qt.ItemIsEditable)
o_table_item.setFlags(o_table_item.flags() & ~QtCore.Qt.ItemIsSelectable)
#设置合并单元格:
# i_span是行span,表示(i, j)这个单元格占多少行,是在同一列中扩展,
# j_span是列span,表示(i, j)这个单元格占多少列,是在同一行中扩展
o_table.setSpan(i, j, i_span, j_span)
#设置表头内容:
o_table.setHorizontalHeaderLabels(['c0', 'c1', 'c2'])
o_table.setVerticalHeaderLabels(['r0', 'r1', 'r2'])
#获取行表头和列表头
o_table.VerticalHeader()
o_table.horizontalHeader()
#设置表头隐藏:
o_table.VerticalHeader().setVisible(False)
o_table.horizontalHeader().setVisible(False)
#获取表头item:
o_table.horizontalHeaderItem(i) # 水平第i个表头
o_table.verticalHeaderItem(j) # 垂直第j个表头
6 QDockWidget(可拖动窗口)
效果图:
代码:
导入模块
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
定义一个Dock
class CLeftDock(QtWidgets.QDockWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('left dock')
self.setWidget(QtWidgets.QTextEdit('left'))
#self.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea)
'''
设置属性, 只设置一个的话,会把其它默认属性去掉
比如dockwidget默认是可以从主窗口中拖出来,而且可关闭,
如果只设置Closable属性,则dockwidget就不能从主窗口拖出来了.
'''
self.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
又定义一个Dock
class CBasicDock(QtWidgets.QDockWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('basic dock')
self.setWidget(QtWidgets.QTextEdit('Basic'))
#self.setAllowedAreas(QtCore.Qt.TopDockWidgetArea)
'''同CLeftDock中的描述'''
self.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
再定义一个Dock
class CDetailDock(QtWidgets.QDockWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('detail dock')
self.setWidget(CDetailWidget())
#self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
'''同CLeftDock中的描述'''
self.setFeatures(QtWidgets.QDockWidget.DockWidgetClosable)
#_o_size_policy = self.sizePolicy()
#_o_size_policy.setHorizontalPolicy(QtWidgets.QSizePolicy.Expanding)
#_o_size_policy.setVerticalPolicy(QtWidgets.QSizePolicy.Preferred)
#_o_size_policy.setHorizontalStretch(100)
#_o_size_policy.setVerticalStretch(0)
#dock窗口内容
class CDetailWidget(QtWidgets.QTextEdit):
def __init__(self):
super().__init__()
self.append('Detail')
'''设置推荐尺寸, 用于界面启动时各dock初始尺寸'''
def sizeHint(self):
return QtCore.QSize(500, 300)
主窗口
class CMainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.o_left_dock = CLeftDock()
self.o_basic_dock = CBasicDock()
self.o_detail_dock = CDetailDock()
'''设置Dock的摆放关系'''
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.o_left_dock)
self.splitDockWidget(self.o_left_dock, self.o_basic_dock, QtCore.Qt.Horizontal)
self.splitDockWidget(self.o_basic_dock, self.o_detail_dock, QtCore.Qt.Vertical)
self.setGeometry(200, 200, 600, 400)
self.setWindowTitle('dock example')
'''隐藏默认的中心Widget,只显示Dock'''
o_central_widget = self.centralWidget()
if o_central_widget!=None:
o_central_widget.hide()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = CMainWindow()
win.show()
sys.exit(app.exec_())
7 自定义可折叠Widget
说明:可以用这种自定义的方式实现类似tree的效果,但实测速度方面并不如tree.
效果图:
代码:
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
class CollapseWidget(QtWidgets.QWidget):
def __init__(self, s_text, list_widgets=None):
super().__init__()
self.s_text = s_text
self.list_widgets = list_widgets if list_widgets!=None else []
self.o_btn = self._gen_btn() # 通过点击btn 显示/隐藏widget
self._set_list_widgets_visible(False) # 设置widget默认隐藏
self.setStyleSheet(self._gen_style_sheet())
self.setLayout(self._gen_layout())
def _gen_btn(self):
_o_btn = QtWidgets.QPushButton(self.s_text)
if len(self.list_widgets)>0:
_o_btn.setIcon(QtGui.QIcon('collapse_on.png'))
_o_btn.clicked.connect(self._on_btn_clicked)
return _o_btn
def _on_btn_clicked(self):
_o_btn = self.sender()
if len(self.list_widgets)>0:
_b_visible = self.list_widgets[0].isVisible()
if _b_visible==True:
_o_btn.setIcon(QtGui.QIcon('collapse_on.png'))
self._set_list_widgets_visible(False)
else:
_o_btn.setIcon(QtGui.QIcon('collapse_off.png'))
self._set_list_widgets_visible(True)
def _set_list_widgets_visible(self, b_visible):
for _o_widget in self.list_widgets:
_o_widget.setVisible(b_visible)
def _gen_style_sheet(self):
_list = list()
_list.append('QPushButton {')
_list.append(' text-align: left;')
_list.append(' border: none;')
#_list.append(' background-color: transparent;')
_list.append('}')
_list.append('QPushButton:hover {')
_list.append(' background-color: lightblue;')
_list.append('}')
_list.append('QPushButton:pressed {')
_list.append(' background-color: lightskyblue;')
_list.append('}')
return ' '.join(_list)
def _gen_layout(self):
_o_layout_btn = QtWidgets.QVBoxLayout()
_o_layout_btn.setContentsMargins(0,0,0,0)
_o_layout_btn.addWidget(self.o_btn)
_o_layout_w0 = QtWidgets.QVBoxLayout()
for _o_widget in self.list_widgets:
_o_layout_w0.addWidget(_o_widget)
_o_layout_w1 = QtWidgets.QHBoxLayout()
_o_layout_w1.addSpacing(40)
_o_layout_w1.addLayout(_o_layout_w0)
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_btn)
_o_layout_main.addLayout(_o_layout_w1)
#_o_layout_main.addStretch(1)
return _o_layout_main
class Demo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.o_widget_0 = CollapseWidget('1. size', [CollapseWidget('1.1 height'), CollapseWidget('1.2 width')])
self.o_widget_1 = CollapseWidget('2. head', [CollapseWidget('2.1 title' ), CollapseWidget('2.2 position')])
self.resize(300, 200)
self.setLayout(self._gen_layout())
def _gen_layout(self):
_o_layout = QtWidgets.QVBoxLayout()
_o_layout.addWidget(self.o_widget_0)
_o_layout.addWidget(self.o_widget_1)
_o_layout.addStretch(1)
return _o_layout
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
8 QMessageBox(消息框)
效果图:
代码:
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
class Demo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.o_btn_info = self._gen_btn_info()
self.setLayout(self._gen_layout())
self.resize(300, 150)
def _gen_btn_info(self):
_o_btn = QtWidgets.QPushButton('information')
_o_btn.clicked.connect(self._on_btn_info_clicked)
return _o_btn
def _on_btn_info_clicked(self):
QtWidgets.QMessageBox.information(
self, # 父容器, 可以为None
'Information', # 消息框标题
'This is a information', # 消息框文本内容
QtWidgets.QMessageBox.Ok # 消息框按钮
)
def _gen_layout(self):
_o_layout_main = QtWidgets.QHBoxLayout()
_o_layout_main.addWidget(self.o_btn_info)
_o_layout_main.addStretch(1)
return _o_layout_main
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
消息框:
QMessageBox.information(parent, 'title', 'msg', QMessageBox.Ok)
QMessageBox.warning(parent, 'title', 'msg', QMessageBox.Ok)
QMessageBox.critical(parent, 'title', 'msg', QMessageBox.Ok)
问题框:
reply = QtWidgets.QMessageBox.question(
parent, # 父容器, 可以为None
'Question', # 消息框标题
'Msg', # 消息框文本内容
QMessageBox.Yes|QMessageBox.No, # 消息框按钮
QMessageBox.No, # 默认按钮
)
if reply == QMessageBox.Yes: # 获取用户响应
do something
else:
do something
自定义对话框
效果图:
代码:
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
class Demo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.o_btn_dialog= self._gen_btn_dialog()
self.setLayout(self._gen_layout())
self.resize(300, 150)
def _gen_btn_dialog(self):
_o_btn = QtWidgets.QPushButton('Dialog')
_o_btn.clicked.connect(self._on_btn_dialog_clicked)
return _o_btn
def _on_btn_dialog_clicked(self):
_o_dialog = CMyDialog()
_o_dialog.select_done.connect(self._on_select_done)
_o_dialog.exec_()
_o_dialog.destroy()
def _on_select_done(self, s_text):
self.o_btn_dialog.setText(s_text)
def _gen_layout(self):
_o_layout_main = QtWidgets.QHBoxLayout()
_o_layout_main.addWidget(self.o_btn_dialog)
_o_layout_main.addStretch(1)
return _o_layout_main
class CMyDialog(QtWidgets.QDialog):
select_done = QtCore.pyqtSignal(str)
def __init__(self):
super().__init__()
self.o_combox = QtWidgets.QComboBox()
self.o_combox.addItems(['Java', 'C#', 'Python'])
self.o_btn_ok = self._gen_btn_ok()
self.o_btn_cancel = self._gen_btn_cancel()
self.setLayout(self._gen_layout())
def _gen_btn_ok(self):
_o_btn = QtWidgets.QPushButton('Ok')
_o_btn.clicked.connect(self._on_btn_ok_clicked)
return _o_btn
def _on_btn_ok_clicked(self):
_s_text = self.o_combox.currentText()
self.select_done.emit(_s_text)
self.close()
def _gen_btn_cancel(self):
_o_btn = QtWidgets.QPushButton('Cancel')
_o_btn.clicked.connect(self._on_btn_cancel_clicked)
return _o_btn
def _on_btn_cancel_clicked(self):
self.close()
def _gen_layout(self):
_o_layout_combox = QtWidgets.QHBoxLayout()
_o_layout_combox.addWidget(self.o_combox)
_o_layout_btn = QtWidgets.QHBoxLayout()
_o_layout_btn.addWidget(self.o_btn_ok)
_o_layout_btn.addWidget(self.o_btn_cancel)
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_combox)
_o_layout_main.addLayout(_o_layout_btn)
return _o_layout_main
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
9. 特殊对话框(打开文件, 保存文件, 选择颜色)
效果图:
代码
import sys
import os
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class CDemo(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.o_btn_open = self._gen_btn_open()
self.o_btn_save = self._gen_btn_save()
self.o_btn_color= self._gen_btn_color()
self.o_line_edit = self._gen_line_edit()
self.resize(300, 200)
self.setLayout(self._gen_layout())
def _gen_line_edit(self):
_o_line_edit = QtWidgets.QLineEdit('')
return _o_line_edit
def _gen_btn_open(self):
_o_btn = QtWidgets.QPushButton('open')
_o_btn.clicked.connect(self._on_btn_open_clicked)
return _o_btn
def _on_btn_open_clicked(self):
file_name, file_type = QtWidgets.QFileDialog.getOpenFileName(
self, # parent
'OpenFile', # title
os.getcwd(), # 起始目录
'All Files(*);; Text Files(*.txt)' # file_type filter, 要用两个分号
)
print(file_name) # 选中的全路径文件名
print(file_type) # 选择的文件类型,比如"All Files(*)"
self.o_line_edit.setText(file_name)
def _gen_btn_save(self):
_o_btn = QtWidgets.QPushButton('save')
_o_btn.clicked.connect(self._on_btn_save_clicked)
return _o_btn
def _on_btn_save_clicked(self):
file_name, file_type = QtWidgets.QFileDialog.getSaveFileName(
self, # parent
'SaveFile', # title
os.getcwd(), # 起始目录
'All Files(*);; Text Files(*.txt)' # file_type filter, 要用两个分号
)
print(file_name) # 选中/输入的全路径文件名
print(file_type) # 选择的文件类型,比如"All Files(*)"
self.o_line_edit.setText(file_name)
def _gen_btn_color(self):
_o_btn = QtWidgets.QPushButton('color')
_o_btn.clicked.connect(self._on_btn_color_clicked)
return _o_btn
def _on_btn_color_clicked(self):
_o_color = QtWidgets.QColorDialog.getColor() # 返回选择的颜色
print(_o_color.name()) # 颜色名,是"#00FF00"这种字符串名字
self.o_line_edit.setStyleSheet(f'QLineEdit {{background-color: {_o_color.name()} }}')
def _gen_layout(self):
_o_layout_0 = QtWidgets.QHBoxLayout()
_o_layout_0.addWidget(self.o_line_edit)
_o_layout_0.addWidget(self.o_btn_open)
_o_layout_0.addWidget(self.o_btn_save)
_o_layout_0.addWidget(self.o_btn_color)
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_0)
_o_layout_main.addStretch(1)
return _o_layout_main
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = CDemo()
win.show()
sys.exit(app.exec_())
10. 给Widget加滚动条
听说MainWidow自带滚动条, 但QWidget并没有, 所以如果想让QWidget中的内容可以滚动, 一般使用如下方法:
声明一个滚动条QScrollArea, 把QWidget添加到滚动条中(注意, 不是把滚动条添加到QWidget中), 这样QWidget就可以滚动了.
import sys
from PyQt5 import QtWidgets
class CDemo(QtWidgets.QScrollArea):
def __init__(self):
super().__init__()
self.list_btn = self._gen_list_btn() # 声明一系列button
self.o_widget = self._gen_widget() # 把这些button按行列放到widget中
self.setWidget(self.o_widget) # 把widget放到滚动条中, 这样这些button所在的widget就有滚动条了.
def _gen_list_btn(self):
_list = list()
for i in range(50):
_list_i = list()
for j in range(10):
_list_i.append(QtWidgets.QPushButton(f'{i}.{j}'))
_list.append(_list_i)
return _list
def _gen_widget(self):
_o_widget = QtWidgets.QWidget()
_o_widget.setLayout(self._gen_layout())
return _o_widget
def _gen_layout(self):
_o_layout_main = QtWidgets.QVBoxLayout()
for i in range(len(self.list_btn)):
_o_layout_i = QtWidgets.QHBoxLayout()
for j in range(len(self.list_btn[i])):
_o_btn = self.list_btn[i][j]
_o_layout_i.addWidget(_o_btn)
_o_layout_main.addLayout(_o_layout_i)
return _o_layout_main
app = QtWidgets.QApplication(sys.argv)
win = CDemo()
win.show()
sys.exit(app.exec_())
11 QProgressBar(进度条)
效果图:
代码
import sys
import time
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class Demo(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.o_progress_bar = self._gen_progress_bar()
self.o_btn_start = self._gen_btn_start()
self.o_btn_clear = self._gen_btn_clear()
self.setLayout(self._gen_layout())
def _gen_progress_bar(self):
_o_pbar = QtWidgets.QProgressBar()
#_o_pbar.setRange(0, 100) # 默认范围是0~100, 且默认会显示%
_o_pbar.setValue(30) # 设置进度条的当前值
return _o_pbar
def _gen_btn_start(self):
_o_btn = QtWidgets.QPushButton('Start')
_o_btn.clicked.connect(self._on_btn_start_clicked)
return _o_btn
def _on_btn_start_clicked(self):
self.o_btn_clear.setEnabled(False)
_i_start = self.o_progress_bar.value() # 获取进度条的当前值
print(type(_i_start))
for i in range(_i_start, 100+1): # 注意循环上限设置为101
time.sleep(0.1)
self.o_progress_bar.setValue(i+0)
self.o_btn_clear.setEnabled(True)
def _gen_btn_clear(self):
_o_btn = QtWidgets.QPushButton('Clear')
_o_btn.clicked.connect(self._on_btn_clear_clicked)
return _o_btn
def _on_btn_clear_clicked(self):
self.o_progress_bar.setValue(0)
def _gen_layout(self):
_o_layout = QtWidgets.QHBoxLayout()
_o_layout.addWidget(self.o_progress_bar)
_o_layout.addWidget(self.o_btn_start)
_o_layout.addWidget(self.o_btn_clear)
return _o_layout
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
12 QSlider和QSpinBox
效果图:
代码
import sys
import time
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class Demo(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.o_slider = self._gen_slider()
self.o_spinbox = self._gen_spinbox()
self.setLayout(self._gen_layout())
def _gen_slider(self):
_o_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) # 设置滑杆为水平方向, 默认垂直方向.
_o_slider.setRange(0, 127)
_o_slider.setSingleStep(1)
_o_slider.setValue(30)
_o_slider.valueChanged.connect(self._on_slider_value_changed)
return _o_slider
def _on_slider_value_changed(self):
self.o_spinbox.setValue(self.o_slider.value())
def _gen_spinbox(self):
_o_spinbox = QtWidgets.QSpinBox()
_o_spinbox.setRange(0, 127)
_o_spinbox.setSingleStep(1)
_o_spinbox.setValue(30)
_o_spinbox.valueChanged.connect(self._on_spinbox_value_changed)
return _o_spinbox
def _on_spinbox_value_changed(self):
self.o_slider.setValue(self.o_spinbox.value())
def _gen_layout(self):
_o_layout = QtWidgets.QHBoxLayout()
_o_layout.addWidget(self.o_slider)
_o_layout.addWidget(self.o_spinbox)
return _o_layout
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
13 QComboBox
效果图:
代码
import sys
import time
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class Demo(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.o_combox = self._gen_combox()
self.o_label = QtWidgets.QLabel('Null')
self.setLayout(self._gen_layout())
self.resize(200, 100)
def _gen_combox(self):
_o_combox = QtWidgets.QComboBox()
_o_combox.addItems(['Python', 'Java', 'C++']) # 设置待选项
_o_combox.setCurrentIndex(1) # 设置当前选中值
_o_combox.currentIndexChanged.connect(self._on_combox_idx_changed) # 当前索引变化时
return _o_combox
def _on_combox_idx_changed(self):
_o_combox = self.sender()
_i = _o_combox.currentIndex() # 获取当前索引
_s = _o_combox.currentText() # 获取当前文本
self.o_label.setText(f'{_i}: {_s}')
def _gen_layout(self):
_o_layout = QtWidgets.QHBoxLayout()
_o_layout.addWidget(self.o_combox)
_o_layout.addSpacing(10)
_o_layout.addWidget(self.o_label)
return _o_layout
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
14 QRadioButton(单选框)
效果图:
说明:
同一父容器下的QRadioButton都是互斥的, 要对它们分组有两种方法:
- 不同组的QRadioButton放到不同的父容器中.
- 不同组的QRadioButton使用QButtonGroup.
不过QButtonGroup是不可见的组件, 它也没有什么好用的方法,
所以我们倾向于定义一个容器专门存放QRadioButton, 并在容器中定义些好用的method.
代码:
import sys
import time
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class CMyWidgetRadioButton(QtWidgets.QWidget):
toggled = QtCore.pyqtSignal()
def __init__(self, parent=None, list_items=None):
super().__init__(parent)
self._list_items = list_items if list_items!=None else []
self._list_radio_btn = self._gen_list_radio_btn()
self.setLayout(self._gen_layout())
def _gen_list_radio_btn(self):
_list = list()
for _s_text in self._list_items:
_o_radio_btn = QtWidgets.QRadioButton()
_o_radio_btn.setText(str(_s_text)) # radio button设置文本
_o_radio_btn.toggled.connect(self._on_radio_btn_toggled) # 选择情况切换时
_list.append(_o_radio_btn)
return _list
def _on_radio_btn_toggled(self):
self.toggled.emit()
def _gen_layout(self):
_o_layout = QtWidgets.QVBoxLayout()
for _o_radio_btn in self._list_radio_btn:
_o_layout.addWidget(_o_radio_btn)
return _o_layout
def current_idx(self):
_i_out = None
for _i, _o_radio_btn in enumerate(self._list_radio_btn):
if _o_radio_btn.isChecked()==True: # radio button是否选中
_i_out = _i
break
else:
continue
return _i_out
def current_text(self):
_s_out = None
_i = self.current_idx()
if _i!=None:
_s_out = self._list_radio_btn[_i].text() # 获取radio button的文本
else:
_s_out = None
return _s_out
class Demo(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.o_widget_radio_0 = self._gen_widget_radio_btn_0() # 把一组RadioButton都放到这个Widget中.
self.o_widget_radio_1 = self._gen_widget_radio_btn_1() # 把一组RadioButton都放到这个Widget中.
self.o_label = QtWidgets.QLabel('Null')
self.setLayout(self._gen_layout())
self.resize(200, 100)
def _gen_widget_radio_btn_0(self):
_o_widget = CMyWidgetRadioButton(list_items=['苹果', '香蕉', '西瓜', '桔子'])
_o_widget.toggled.connect(self._on_widget_radio_btn_toggled)
return _o_widget
def _gen_widget_radio_btn_1(self):
_o_widget = CMyWidgetRadioButton(list_items=['一个', '二个', '三个'])
_o_widget.toggled.connect(self._on_widget_radio_btn_toggled)
return _o_widget
def _on_widget_radio_btn_toggled(self):
_s_0 = self.o_widget_radio_0.current_text()
_s_1 = self.o_widget_radio_1.current_text()
self.o_label.setText(f'{_s_0}, {_s_1}')
def _gen_layout(self):
_o_layout_btn = QtWidgets.QHBoxLayout()
_o_layout_btn.addWidget(self.o_widget_radio_0)
_o_layout_btn.addWidget(self.o_widget_radio_1)
_o_layout_label = QtWidgets.QVBoxLayout()
_o_layout_label.addWidget(self.o_label)
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_btn)
_o_layout_main.addLayout(_o_layout_label)
return _o_layout_main
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())
15 QCheckBox(复选框)
效果图:
代码:
import sys
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5 import QtGui
class CMyWidgetCheckBox(QtWidgets.QWidget):
state_changed = QtCore.pyqtSignal()
def __init__(self, parent=None, list_items=None):
super().__init__(parent)
self._list_items = list_items if list_items!=None else []
self._list_chkbox = self._gen_list_chkbox()
self.setLayout(self._gen_layout())
def _gen_list_chkbox(self):
_list = list()
for _s_text in self._list_items:
_o_chkbox = QtWidgets.QCheckBox()
_o_chkbox.setText(str(_s_text)) # chkbox设置文本
_o_chkbox.stateChanged.connect(self._on_chkbox_state_changed) # 选择情况切换时
_list.append(_o_chkbox)
return _list
def _on_chkbox_state_changed(self):
self.state_changed.emit()
def _gen_layout(self):
_o_layout = QtWidgets.QVBoxLayout()
for _o_chkbox in self._list_chkbox:
_o_layout.addWidget(_o_chkbox)
return _o_layout
def list_checked_idx(self):
_list_out = list()
for _i, _o_chkbox in enumerate(self._list_chkbox):
if _o_chkbox.isChecked()==True:
_list_out.append(_i)
else:
continue
return _list_out
def list_checked_text(self):
_list_out = list()
for _i in self.list_checked_idx():
_s_text = self._list_chkbox[_i].text()
_list_out.append(_s_text)
return _list_out
class Demo(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.o_widget_chkbox_0 = self._gen_widget_chkbox_0() # 把一组CheckBox都放到这个Widget中.
self.o_widget_chkbox_1 = self._gen_widget_chkbox_1() # 把一组CheckBox都放到这个Widget中.
self.o_label = QtWidgets.QLabel('Null')
self.setLayout(self._gen_layout())
self.resize(200, 100)
def _gen_widget_chkbox_0(self):
_o_widget = CMyWidgetCheckBox(list_items=['苹果', '香蕉', '西瓜', '桔子'])
_o_widget.state_changed.connect(self._on_widget_chkbox_state_changed)
return _o_widget
def _gen_widget_chkbox_1(self):
_o_widget = CMyWidgetCheckBox(list_items=['一个', '二个', '三个'])
_o_widget.state_changed.connect(self._on_widget_chkbox_state_changed)
return _o_widget
def _on_widget_chkbox_state_changed(self):
_list_text_0 = self.o_widget_chkbox_0.list_checked_text()
_list_text_1 = self.o_widget_chkbox_1.list_checked_text()
self.o_label.setText(f'{" ".join(_list_text_0)}\n{" ".join(_list_text_1)}')
pass
def _gen_layout(self):
_o_layout_btn = QtWidgets.QHBoxLayout()
_o_layout_btn.addWidget(self.o_widget_chkbox_0)
_o_layout_btn.addWidget(self.o_widget_chkbox_1)
_o_layout_label = QtWidgets.QVBoxLayout()
_o_layout_label.addWidget(self.o_label)
_o_layout_main = QtWidgets.QVBoxLayout()
_o_layout_main.addLayout(_o_layout_btn)
_o_layout_main.addLayout(_o_layout_label)
return _o_layout_main
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Demo()
win.show()
sys.exit(app.exec_())