心情不好就少听悲伤的歌,饿了就自己找吃的,怕黑就开灯,想要的就自己赚钱买,即使生活给了你百般阻挠,也没必要用矫情放大自己的不易,现实就这么残酷。改变不了的事就别太在意,留不住的人就试着放弃,受了伤的心就尽力自愈,除了生死,都是小事,别为难自己。
安装
pip install pyqt5
安装速度太慢的解决办法:
- 采用国内源,加速下载模块的速度
- 常用pip源:
-- 豆瓣:https://pypi.douban.com/simple
-- 阿里:https://mirrors.aliyun.com/pypi/simple
-- 中科大:https://pypi.mirrors.ustc.edu.cn/simple
-- 清华:https://pypi.tuna.tsinghua.edu.cn/simple - 加速安装的命令:
-- >: pip install 模块名 -i https://pypi.douban.com/simple
创建主类
import sys
from PyQt5.QtWidgets import QApplication,QWidget,QDesktopWidget
继承QWidget类,相当于继承PyQt的插件,我们开发的是一个桌面插件。
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# 窗口标题
self.setWindowTitle('测试程序')
# 窗口尺寸,宽*高
self.resize(980,450)
# 窗口位置,显示在屏幕中间
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
# 显示窗体
self.show()
启动程序
# 创建一个QApplication对象
app = QApplication(sys.argv)
# 实例化我们的主程序,执行程序内部init初始化方法。
window = MainWindow()
sys.exit(app.exec_())
窗体布局
该布局类似于css的flex布局,有垂直布局和水平布局两种,由外向内布局。
弹簧作用:撑开页面,挤压页面元素。
from PyQt5.QtWidgets import QHBoxLayout,QVBoxLayout
QHBoxLayout:水平布局
QVBoxLayout:垂直布局
# 开始布局,创建整体的垂直布局(div的display:flex,flex-direction:column)
layout = QVBoxLayout()
# 1.创建内部区域布局(div的display:flex,flex-direction:row)
header_layout = QHBoxLayout()
# 把该区域加入到主layout中(加入主div中)
layout.addLayout(header_layout)
# 给窗体设置元素的排列方式,该布局是垂直布局,所以设置成垂直的排列方式。
self.setLayout(layout)
创建按钮元素(QPushButton)
from PyQt5.QtWidgets import QPushButton
# 创建一个 “开始” 按钮
btn_start = QPushButton('开始')
# 将按钮加入到布局中
header_layout.addWidget(btn_start)
加入弹簧(addStretch)
header_layout.addStretch()
创建单行输入框元素(QLineEdit)
from PyQt5.QtWidgets import QLineEdit
# 创建输入框
txt_asin = QLineEdit()
txt_asin.setPlaceholderText('请输入内容')
# 将输入框加入布局中
form_layout.addWidget(txt_asin)
创建表格元素(QTableWidget)
from PyQt5.QtWidgets import QTableWidget
# 创建2行8列的表格对象
table_widget = QTableWidget(2,8)
# 将表格对象加入到布局中
table_layout.addWidget(table_widget)
修改表头(创建单元格对象:QTableWidgetItem)
修改方式是通过索引找到该表格,创建单元格对象,设置单元格内容
item = QTableWidgetItem()
item.setText('标题')
# 通过索引设置该单元格对象
table_widget.setHorizontalHeaderItem(0,item)
# 通过索引设置列宽
table_widget.setColumnWidth(0,160)
优化修改表头方式
table_header = [
{'field':'asin','text':'ASIN','width':120},
{'field':'title','text':'标题','width':150},
{'field':'url','text':'URL','width':400},
{'field':'price','text':'底价','width':100},
{'field':'success','text':'成功次数','width':100},
{'field':'error','text':'503次数','width':100},
{'field':'status','text':'状态','width':100},
{'field':'frequency','text':'频率(N秒/次)','width':100},
]
for i,v in enumerate(table_header):
item = QTableWidgetItem()
item.setText(str(v['text']))
table_widget.setHorizontalHeaderItem(i,item)
table_widget.setColumnWidth(i,v['width'])
其余内容
优化代码
初始化表格内单元格数据
# 获取当前表格内总行数,无数据时current_row_count = 0
current_row_count = table_widget.rowCount()
# 循环加入数据,在列表内循环,row_list相当于数据的每一行
for row_list in data_list:
# 在第current_row_count行插入一行,此时表示在第0行插入一行
table_widget.insertRow(current_row_count)
# 通过在数据行内循环,把行内数据添加进单元格中。
for i,ele in enumerate(row_list):
cell = QTableWidgetItem(str(ele))
# 这里用table_widget的setItem方法来设置单元格对象。三个参数分别表示在第几行,第几列,插入一个QTableWidgetItem对象。
table_widget.setItem(current_row_count,i,cell)
# 一行循环结束,行数+1
current_row_count += 1
设置单元格是否可编辑
# 导入
from PyQt5.QtCore import Qt
# 如果单元格索引到i列时,设置该单元格的属性为不可修改
if i in [0,4,5,6]:
cell.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
获取输入框中的内容
由于初始化输入框和添加按钮所涉及的事件是在两个方法中,所以要在外层放置一个self.text_asin,并将其初始化为None,在初始化表单的时候,将对应对象赋值给self.text_asin,即可在该方法中的任何需要调用的地方用到该对象。
初始化:
对象赋值:
需要调用的地方:
按钮单击事件
# 假设有一个登陆按钮
login = QPushButton('登陆')
# 登录按钮需要触发该类自身的event_doLogin函数
login.clicked.connect(self.event_doLogin)
在event_doLogin方法中编写如下代码:
# 登录按钮需要做的事
def event_doLogin(self):
# 1.获取账号密码
account = self.input_account.text().strip()
password = self.input_password.text().strip()
if not account or not password:
QMessageBox.warning(self,'警告','请输入用户名和密码')
return
# 2.登录操作,将该任务委派给线程完成,要向线程传递的参数写在前,“self”在最后。
login_thread = loginTaskThread(account,password,self)
# 线程处理完毕(触发信号)后的回调函数
login_thread.success.connect(self.login_task_success_callback)
login_thread.error.connect(self.login_task_error_callback)
# 开始执行
login_thread.start()
pass
数据的更新(QThread、pyqtSignal)
创建一个单独的线程py文件,在其中引入QThread、pyqtSignal两类
from PyQt5.QtCore import QThread,pyqtSignal
开始线程类功能的编写:
# 继承QThread类
class loginTaskThread(QThread):
# 创建两个变量用于传递信号,一个用于登录成功的信号传递,另一个用于失败时的信号传递。
# pyqtSignal参数要填写待传递信息的type,如传递字符串,则写“str”。
success = pyqtSignal(str)
error = pyqtSignal(int)
# 必写初始化函数,形参个数根据待接收的实参设定。
def __init__(self,account,password,*args,**kwargs):
super().__init__(*args,**kwargs)
self.account = account
self.password = password
# 重构run方法,该方法内实现线程需要做的内容。
def run(self):
# 传递信息(成功/失败),参数类型要根前面设定的类型一致。
# 线程执行结束获取结果后,将该结果传递回前台界面接收处理。
self.success.emit(passport_name)
self.error.emit(0)
return
线程结束后的回调函数操作
# 登录成功或失败后的回调函数
def login_task_success_callback(self,passport_name):
self.nickname.setText(passport_name)
self.nickname.repaint()
# 线程执行失败()的回调函数
def login_task_error_callback(self,status):
QMessageBox.warning(self,'警告','用户名或密码错误')
弹窗
from PyQt5.QtWidgets import QMessageBox
# 第二个参数是弹窗标题,第三个参数是弹窗内容。
QMessageBox.warning(self,'警告','输入不能为空')
数据删除
# 选中行的获取
current_row_list = self.table_widget.selectionModel().selectedRows()
# 做一次列表反转操作,必做操作!!!!!!
current_row_list.reverse()
for row in current_row:
# 获取当前行的索引值
index = row.row()
# 通过索引值删除对应项
self.table_widget.removeRow(index)
弹窗
创建弹窗
需要创建一个新的弹窗类,继承QDialog,然后对弹窗进行布局。
from PyQt5.QtWidgets import QDialog,QVBoxLayout,QLabel
from PyQt5.QtCore import Qt
class AlertDialog(QDialog):
def __init__(self,*args, **kwargs):
super().__init__(*args, **kwargs)
# 创建弹窗界面,初始化ui
self.init_ui()
def init_ui(self):
self.setWindowTitle('配置')
self.resize(640,480)
layout = QVBoxLayout()
label = QLabel('弹窗界面')
layout.addWidget(label)
self.setLayout(layout)
调用弹窗
导入新建好的弹窗类
from utils.dialog import AlertDialog
在点击事件中对弹窗类进行实例化操作
def event_dialog(self):
dialog = AlertDialog()
dialog.setWindowModality(Qt.ApplicationModal)
dialog.exec_()
单元格右键操作
# 对表格对象开启右键功能,触发table_right_menu函数。
self.file_lists.setContextMenuPolicy(Qt.customContextMenu)
self.file_lists.customContextMenuRequested.connect(self.table_right_menu)
在table_right_menu函数下,导入QMenu控件。
from PyQt5.QtWidgets import QMenu
函数内容:
def table_right_menu(self,pos):
# 添加右键菜单按钮
menu = QMenu()
item_download = menu.addAction('下载')
item_delete = menu.addAction('删除云端文件')
# action表示右键选择哪个菜单行为
action = menu.exec_(self.file_lists.mapToGlobal(pos))
# action执行哪个操作?
if action == item_download :
# 如果选择了“下载”按钮,该执行的操作:
# 当前操作:打印选择的第1行的行号。
print(selected_item_list[0].row())
pass
if action == item_delete :
# 如果点击“删除云端文件”按钮,该执行的操作:
pass
文件/文件夹选择窗口
QFileDialog类方法
类方法 | 描述 |
---|---|
getOpenFileName() | 返回用户所选择文件的名称,并打开该文件 |
getSaveFileName() | 使用用户选择的文件名保存文件 |
setFileMode() | 可以选择的文件类型,枚举常量是: |
- | QFileDialog.AnyFile:任何文件 |
- | QFileDialog.ExistingFile:已存在的文件 |
- | QFileDialog.Directory:文件目录 |
- | QFileDialog.ExistingFiles:已经存在的多个文件 |
setFilter() | 设置过滤器,只显示过滤器允许的文件类型 |
使用QFileDialog类
引入QFileDialog类
from PyQt5.QtWidgets import QMessageBox,QMenu,QFileDialog
为按钮创建打开文件选择窗口事件
def choose_download_dir(self):
# 创建选择文件夹对话框
dir_dialog = QFileDialog()
# 选择类型限定为文件夹
dir_dialog.setFileMode(QFileDialog.Directory)
if dir_dialog.exec_():
dir_path = dir_dialog.selectedFiles()
download_path = dir_path[0]
# 选择的文件夹路径
print(download_path)