技巧篇
在这里笔者会放上各种各样的PyQt5小技巧,方便快速查阅。大家可以直接用Ctrl+F来进行搜索(Mac上为Command+F),看看有没有自己需要的。
《快速掌握PyQt5》专栏已整理成书出版,书名为《PyQt编程快速上手》,详情请见该链接。感谢大家一直以来的支持!祝大家PyQt用得越来越顺!
拖曳无边框窗口
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.setWindowFlag(Qt.FramelessWindowHint) # 1
self.start_x = None
self.start_y = None
def mousePressEvent(self, event): # 2
if event.button() == Qt.LeftButton:
self.start_x = event.x()
self.start_y = event.y()
def mouseMoveEvent(self, event): # 3
if not self.start_x or not self.start_y:
return
dis_x = event.x() - self.start_x
dis_y = event.y() - self.start_y
self.move(self.x() + dis_x, self.y() + dis_y)
def mouseReleaseEvent(self, event):
self.start_x = None
self.start_y = None
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 调用窗口的setWindowFlag方法并传入Qt.FramelessWindowHint即可取消窗口边框。
2. 获取鼠标按下时的坐标位置(相对于窗口左上角)。
3. 当鼠标处于按下状态并开始移动时,鼠标离窗口左上角的位置会不断更新并保存在event.x()和event.y()中。我们将更新后的x和y值不断减去鼠标按下时的坐标位置,就可以知道鼠标移动的距离。最后再调用move方法将窗口当前坐标加上移动距离即可。
动态增加和删除控件
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout, QHBoxLayout
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.label_list = [] # 1
for i in range(5):
label = QLabel(str(i+1))
label.setAlignment(Qt.AlignCenter)
self.label_list.append(label)
self.add_btn = QPushButton('增加文本') # 2
self.minus_btn = QPushButton('删除文本')
self.add_btn.clicked.connect(self.add_slot)
self.minus_btn.clicked.connect(self.minus_slot)
self.v_layout = QVBoxLayout() # 3
h_layout = QHBoxLayout()
all_v_layout = QVBoxLayout()
for l in self.label_list:
self.v_layout.addWidget(l)
h_layout.addWidget(self.add_btn)
h_layout.addWidget(self.minus_btn)
all_v_layout.addLayout(self.v_layout)
all_v_layout.addLayout(h_layout)
self.setLayout(all_v_layout)
def add_slot(self): # 4
label = QLabel(str(len(self.label_list)+1))
label.setAlignment(Qt.AlignCenter)
self.label_list.append(label)
self.v_layout.addWidget(label)
def minus_slot(self): # 5
if len(self.label_list) == 1:
return
label = self.label_list.pop()
label.deleteLater()
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 首先实例化五个QLabel控件,并添加到self.label_list列表中,动态增删的关键其实就是这个列表。
2. 实例化两个按钮分别用于增加和删除QLabel控件。
3. self.v_layout垂直布局管理器用于布局各个QLabel控件,h_layout管理器用于摆放两个按钮,而all_v_layout用于总体布局。这里之所以要将v_layout作为成员变量是因为我们在增加QLabel控件时需要使用到。
4. add_slot槽函数用于增加QLabel控件,每实例化一个QLabel,我们就将其添加到self.label_list列表和self.v_layout布局管理器中。
5. minus_slot槽函数用于删除末尾的QLabel控件。如果控件数量只剩一个,那么就不允许删除,否则调用列表的pop()方法获取到最后一个QLabel控件,然后调用deleteLater()方法删除即可。
PS:
在动态增删控件时如果想要自动调整窗口大小,我们可以添加以下代码:
from PyQt5.QtWidgets import QLayout
all_v_layout.setSizeConstraint(QLayout.SetFixedSize)
QTableWidget单元格文本居中
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, QHeaderView, \
QPushButton, QVBoxLayout
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.resize(500, 300)
self.table = QTableWidget() # 1
self.set_table_properties()
self.btn = QPushButton('文本居中') # 2
self.btn.clicked.connect(self.center_slot)
v_layout = QVBoxLayout()
v_layout.addWidget(self.table)
v_layout.addWidget(self.btn)
self.setLayout(v_layout)
def set_table_properties(self):
"""设置表格属性"""
self.table.setColumnCount(3)
self.table.setRowCount(6)
self.table.setHorizontalHeaderLabels(['标题1', '标题2', '标题3'])
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table.verticalHeader().setHidden(True)
for row in range(self.table.rowCount()):
for col in range(self.table.columnCount()):
self.table.setItem(row, col, QTableWidgetItem(f'({row}, {col})'))
def center_slot(self):
"""文本居中槽函数"""
for row in range(self.table.rowCount()):
for col in range(self.table.columnCount()):
self.table.item(row, col).setTextAlignment(Qt.AlignCenter)
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 实例化一个表格控件,然后在set_table_property函数中笔者设置了表格的相关属性:
- 设置表格列数和行数为3和6
- 设置表格标题字段名称为'标题1',‘标题2’,‘标题3’
- 拉伸各列,使表格填充窗口
- 将表格左边自带的序列号隐藏
- 设置各个单元格内容
2. 点击按钮后可以让文本居中。在center_slot槽函数中循环各个单元格,然后对每个单元格调用setTextAlignment方法并传入Qt.AlignCenter即可。
在线程中获取窗口控件内容
import sys
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QLabel, QVBoxLayout, QHBoxLayout
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.line = QLineEdit()
self.btn = QPushButton('开始爬取')
self.btn.clicked.connect(self.start_slot)
h_layout = QHBoxLayout()
v_layout = QVBoxLayout()
h_layout.addWidget(QLabel('网址:'))
h_layout.addWidget(self.line)
v_layout.addLayout(h_layout)
v_layout.addWidget(self.btn)
self.setLayout(v_layout)
self.crawl_thread = CrawlThread(self) # 1
def start_slot(self): # 2
self.crawl_thread.start()
class CrawlThread(QThread):
def __init__(self, demo): # 3
super(CrawlThread, self).__init__()
self.demo = demo
def run(self): # 4
url = self.demo.line.text().strip()
print(f'要爬取的网址为:{url}')
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 实例化线程,注意此时我们需要把当前窗口类实例(也就是self)传入。
2. 按钮所连接的槽函数用来启动线程。
3. 给线程的初始化函数添加一个参数,用来获取窗口类实例。
4. 接着我们就可以在run函数中获取窗口上任何一个控件及其内容了。
窗口在屏幕居中显示
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.resize(100, 100)
self.center()
def center(self):
# 1
desktop = QApplication.desktop()
d_width = desktop.width()
d_height = desktop.height()
# 2
pos_x = d_width/2 - self.frameGeometry().width()/2
pos_y = d_height/2 - self.frameGeometry().height()/2
# 3
self.move(int(pos_x), int(pos_y))
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 获取屏幕宽高。
2. 屏幕中心的坐标是(d_width/2, d_height/2),但是我们知道窗口的锚点是在左上角,如果直接将移动到该坐标的话,窗口整体会出现在屏幕的右下方:
所以我们应该要将窗口往左上角移动下,横向移动距离是窗口宽度的一半,纵向移动距离是窗口高度的一半,这样就没问题了:
3. 调用move函数将窗口移动到指定位置,接收的参数为int类型。
有关窗口坐标的更多知识点,请阅读第十六章 窗口坐标。
浏览框滑动条自动下滑到底
import sys
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import QApplication, QWidget, QTextEdit, QTextBrowser, QPushButton, QHBoxLayout, QVBoxLayout
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
# 1
self.edit = QTextEdit()
self.browser = QTextBrowser()
self.add_btn = QPushButton('添加')
# 2
self.add_btn.clicked.connect(self.add_text)
h_layout = QHBoxLayout()
v_layout = QVBoxLayout()
h_layout.addWidget(self.edit)
h_layout.addWidget(self.browser)
v_layout.addLayout(h_layout)
v_layout.addWidget(self.add_btn)
self.setLayout(v_layout)
def add_text(self):
text = self.edit.toPlainText()
self.browser.append(text)
self.browser.moveCursor(QTextCursor.End)
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
1. 实例化一个QTextEdit文本编辑框控件、一个QTextBrowser文本浏览框控件以及一个按钮。
2. 进行信号和槽连接操作:每次点击按钮后,编辑框的文本就会被添加到浏览框中。在槽函数中的moveCursor(QTextCursor.End)方法是重点,每当浏览框中新增信息后,该方法都会将滑动条滑到最底部。
待更新
如果大家有想要了解的小技巧,可以在评论区留言。