PyQt5-新手避坑指南(持续更新)


一.前言

本篇博客整理了一些初学者容易犯的错,将会持续更新解决PyQt5开发过程中的一些坑,对新手比较友好,大佬请绕道 /笑哭

二.开发环境

笔者是在Windows11上使用Pycharm配合Python3.8进行开发的,详细开发环境信息如下:

  1. 处理器:AMD Ryzen 7 7735H with Radeon Graphics 3.20 GHz
  2. 系统版本:Windows 11 家庭中文版
  3. 开发工具:PyCharm 2021.3
  4. Python版本:Python3.8
  5. PyQt5版本:PyQt5==5.15.10

三.坑

1.程序没有详细报错就退出了

代码执行时,直接报错Process finished with exit code - 1073740791 (Oxc0000409)然后就退出了。
在这里插入图片描述
按照下图指引打开“Emulate terminal in output console”
在这里插入图片描述
勾选后点击确定或应用
在这里插入图片描述
最新版本在这里插入图片描述

然后再执行代码,就能够看到详细报错信息了
在这里插入图片描述

2.qrc资源文件的使用

我们在设计师或者代码里使用的资源文件都统一地使用qrc管理,qrc是什么呢?

.qrc是一个XML文件,它允许开发者将应用程序所需的图像、样式表、声音文件等各种资源集中管理。
通过将资源文件.qrc加载到PyQt5应用程序中,开发者可以轻松地访问和使用这些资源。
.qrc文件使用XML格式编写,包含一个或多个元素。
每个元素内可以包含多个元素,每个元素指定一个资源的路径和名称。

我们这里有个例子,比如当前项目根目录有个名为logo.png的图片文件,我们想让QLabel显示这张图片,那么我们可以这么操作:

  1. 生成.qrc资源文件
  2. 将qrc通过rcc工具转为.py文件
  3. 在代码里使用资源

resources.qrc
在这里插入图片描述

demo.py
虽然第一步引入代码是灰色,但是不影响使用
在这里插入图片描述
有的同学可能会问,我直接写成**self.setPixmap(QPixmap(“logo.png”))**不也能使用资源么?我们这么写的目的是为了打包方便,当资源用多了就能体现得到。

3.QLabel文字自动换行

这个很好解决,一行代码

label.setWordWrap(True)

4.图片自适应大小

让我们的QLabel随着父控件的大小变化
这个很好解决,一行代码

label.setScaledContents(True)

5.checkbox自定义样式后✓不见了

当我们自定义了QCheckBox之后,发现左侧勾选区域的对号不见了,这通常是我们重写了QCheckBox::indicator::unchecked这很影响我们的ui,其实一张图片即可解决,在此我给出定义样式的qss:

#QCheckBox{
	color:rgb(44,206,162);
	font-size:11pt;
	font-weight:520;
	}
#QCheckBox::indicator::unchecked{ 
			width: 12px;  
            height: 12px;  
            border: 1px solid rgb(44,206,162);
            background-color:rgb(44,206,162)}
#QCheckBox::indicator::checked{ 
			width: 12px;  
             height: 12px;
             image:url(:res/tick.png);
             border: 1px solid rgb(44,206,162);
             background-color:rgb(44,206,162)}

这里我们需要一张:res/tick.png图片作为勾选后的样式,图片是用qrc转的。
tick.png下载地址:https://wwt.lanzoul.com/iwu9u1zxiehe

大致效果如下图:
在这里插入图片描述

6.多线程

这个问题对于新手来说可能不会涉及到,但是随着代码量和需求的叠加,难免会遇到这个问题:主线程(UI线程)耗时太久导致整个界面卡顿甚至卡死,在此我提供一种方案,就是多线程,但是多次的重写QThread会徒增代码量,我给出一种方案解决:

class WorkerThread(QThread):
	calc_finished = pyqtSignal(dict)

	def __init__(self, task, *arg, **args):
		super(WorkerThread, self).__init__()
		self.arg = arg
		self.args = args
		self.task = task

	def run(self):
		result = self.task(self, *self.arg, **self.args)

	def do_calc(self, **args):
		data=dict()
		try:
			data=xxx()
		except:
			traceback.print_exc()
		self.calc_finished .emit(data)

代码大致思路是创建一个线程类,里面通过定义不同的函数执行耗时操作,当耗时操作执行完毕后,使用“发射信号”的方式,将数据传递回主线程。

7.关于无边框

关于无边框将会介绍三种情况:无边框、无边框移动、无边框调整窗口宽高

1.设置无边框

在主窗口加入下面代码即可

self.setWindowFlag(Qt.FramelessWindowHint)

无边框可配合背景透明来用,效果比较好

self.setAttribute(Qt.WA_TranslucentBackground)

2.无边框窗口移动

当我们设置无边框后,窗口就被固定无法移动了,在此我提供一种方法,通过重写鼠标事件完成无边框窗口移动。
首先设置无边框

self.setWindowFlag(Qt.FramelessWindowHint)

然后加入重写事件

	# 无边框的拖动
	def mouseMoveEvent(self, e: QtGui.QMouseEvent):  # 重写移动事件
		try:
			self._endPos = e.pos() - self._startPos
			self.move(self.pos() + self._endPos)
		except (AttributeError, TypeError):
			pass

	def mousePressEvent(self, e: QtGui.QMouseEvent):
		if e.button() == Qt.LeftButton:
			self._isTracking = True
			self._startPos = QPoint(e.x(), e.y())

	def mouseReleaseEvent(self, e: QtGui.QMouseEvent):
		if e.button() == Qt.LeftButton:
			self._isTracking = False
			self._startPos = None
			self._endPos = None

	def keyPressEvent(self, event):
		if event.key() == Qt.Key_Escape:
			self.hide()

4.无边框窗口调整宽高

即使我们设置了窗口无边框、可拖动,但窗口大小是无法调整的,当然我们可以再次重写鼠标事件(判断鼠标位置,改变鼠标形状,重设窗口宽高),我提供一种简单的方法实现无边框窗口调整宽高
在此提供一下思路:向窗口内加入QSizeGrip,此组件能够帮我们调整窗口的宽高,很是实用

size_grip = QSizeGrip(self.centralwidget)  # 加入右下角窗口大小调节器
self.verticalLayout_2.addWidget(size_grip, 0, Qt.AlignBottom | Qt.AlignRight)

效果见图
请添加图片描述

5.窗口最大化 还原动画效果

在主窗口加入下面代码,即可实现窗口最大化~还原动画效果

	def control_max_size(self):
		"""
		控制全屏、还原
		:return:
		"""
		self.animation = QPropertyAnimation(self, b"geometry")
		self.animation.setDuration(100)  # 动画持续时间为 500 毫秒
		if self.is_max_size:
			end_geometry = self.original_geometry

		else:
			self.original_geometry = self.geometry()  # 保存当前窗口大小和位置
			end_geometry = self.screen().availableGeometry()
		self.animation.setStartValue(self.geometry())
		self.animation.setEndValue(end_geometry)
		self.animation.start()
		self.is_max_size = not self.is_max_size

8.分辨率自适应

在程序启动入口加入下面三行代码即可实现分辨率自适应


if __name__ == '__main__':
	QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
	QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
	QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

9.窗口居中

为了让我们的窗口启动后居中,可以采用下面的方法实现

def show_center(self):
	screen = QApplication.primaryScreen()
	screen_rect = screen.availableGeometry()
	window_rect = self.frameGeometry()
	center_point = screen_rect.center()
	window_rect.moveCenter(center_point)
	self.move(window_rect.topLeft())

10.QTabWidget页面背景透明

这里使用QSS来解决,提供了一组QSS代码

QTabWidget::pane {
    border: 1px solid rgba(255, 255, 255, 0.5); /* 半透明边框 */
    background: transparent; /* 背景透明 */
}

QTabBar::tab {
    background: rgba(255, 255, 255, 0.2); /* 半透明标签背景 */
    color: white; /* 标签文字颜色 */
    padding: 5px; /* 标签内边距 */
    border: 1px solid rgba(255, 255, 255, 0.5); /* 半透明标签边框 */
    border-radius: 5px;
}

QTabBar::tab:selected {
    background: rgba(255, 255, 255, 0.5); /* 选中标签更明显的透明背景 */
    color: black; /* 选中标签文字颜色 */
}

QTabBar::tab:hover {
    background: rgba(255, 255, 255, 0.3); /* 悬停效果 */
}

11.窗口关闭后淡出动画

	def closeEvent(self, event: QCloseEvent) -> None:
		self.show_close_anime(event)
		event.ignore()  # 忽略关闭事件

	def show_close_anime(self, event: QCloseEvent):
		"""
		展示关闭动画
		:return:
		"""
		self.close_animation = QPropertyAnimation(self, b"windowOpacity")
		self.close_animation.setDuration(600)
		self.close_animation.setStartValue(1.0)
		self.close_animation.setEndValue(0.0)
		self.close_animation.finished.connect(sys.exit)
		self.close_animation.start()

12.qrc资源生成脚本

import os
import subprocess


def generate_qrc_content(root_dir):
	files = [
		"<file>{}</file>".format(os.path.relpath(os.path.join(root, file), root_dir).replace('\\', '/'))
		for root, _, files in os.walk(root_dir)
		for file in files
		if
		".qrc" not in file and ".py" not in file
	]
	return "<RCC>\n    <qresource>\n" + "\n".join(
		"        {}".format(file) for file in files) + "\n    </qresource>\n</RCC>"


def generate_qrc_file(qrc_file_path, content):
	with open(qrc_file_path, 'w') as qrc_file:
		qrc_file.write(content)


def compile_qrc_to_py(qrc_file_path):
	py_file_path = qrc_file_path.replace('.qrc', '_rc.py')
	subprocess.run(['pyrcc5', qrc_file_path, '-o', py_file_path], check=True)


def main():
	root_dir = "../src/resource/"
	qrc_file_path = root_dir + "/resource.qrc"
	qrc_content = generate_qrc_content(root_dir)
	generate_qrc_file(qrc_file_path, qrc_content)
	compile_qrc_to_py(qrc_file_path)


if __name__ == "__main__":
	main()

13.支持图片自由拉伸做背景的组件


class BGWidget(QWidget):
	"""
	支持图片自由拉伸做背景的组件
	"""

	def __init__(self, p=None, bg_pic=""):
		super(BGWidget, self).__init__(p)
		self.bg_pic = bg_pic

	def set_bg_pic(self, bg_pic):
		self.bg_pic = bg_pic
		self.repaint()
		self.update()

	def paintEvent(self, event):
		super(BGWidget, self).paintEvent(event)
		painter = QPainter(self)
		pixmap = QPixmap(self.bg_pic)  # : 是 qrc 文件的标识符
		painter.drawPixmap(QRect(0, 0, self.width(), self.height()), pixmap)
		painter.end()

14.PyQt5环境问题

1.缺少Microsoft C++ 环境

Error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft

安装Microsoft C++ 生成工具 - Visual Studio:https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/
在这里插入图片描述
然后按照图中的操作步骤安装
在这里插入图片描述
在这里插入图片描述
最后安装PyQt5,问题解决~

pip install PyQt5

2. This application failed to start because no Qt platform plugin could be initialized.

在这里插入图片描述
解决办法:

添加环境变量

变量名:QT_QPA_PLATFORM_PLUGIN_PATH

变量值:“Python的实际安装目录”\Lib\site-packages\pyqt5_plugins\Qt\plugins
比如我的就是:

C:\Users\13978\AppData\Local\Programs\Python\Python38\Lib\site-packages\pyqt5_plugins\Qt\plugins

四.记录

本文会持续更新,大家点赞不迷路哈~

2024年5月27日更新1-6
2024年6月29日更新7
2024年12月7日更新8-10
2025年2月23日更新7.5
2025年2月27日更新11-12
2025年3月20日更新13
2025年4月27日更新14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懷淰メ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值