PyQT5用法总结

文章目录

      • 写在前面
      • PyQT5 Usage
        • 通用提示框
        • 文件对话框
        • 计时器
        • 多线程
        • 嵌入网页
        • 网页交互
        • 带行号的文本框
        • 显示GIF
      • 其他
      • 参考

写在前面

最近各种实验一直在使用PyQT进行GUI编程,网上教程博客很多,但是良莠不齐,在此总结一下用到的组件。

PyQT5 Usage

通用提示框

from PyQt5.QtWidgets import  QMessageBox
class Message(QtWidgets.QWidget):
    def __init__(self):
        super(Message, self).__init__()

    def alert(self, msg):
        reply = QMessageBox.information(self,
                                        "警告",
                                        msg,
                                        QMessageBox.Yes | QMessageBox.No)
                                        
# 调用
 myshow = Message()
 myshow.alert("Your Message Here")

文件对话框

from PyQt5.QtWidgets import QFileDialog
fileName, filetype = QFileDialog.getOpenFileName(self,
                                                 "选取文件",
                                                 "./",
                                                 "PNG Files (*.png);;JPG Files (*.jpg)") 

self是表示所在的父面板
可以使用正则*匹配用户可选的文件类型

计时器

from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MyPyQT_Form(QtWidgets.QWidget, Ui_Form):

    def __init__(self):
        super(MyPyQT_Form, self).__init__()
        
        self.setupUi(self)
        
        self.pushButton_start.clicked.connect(self.start)
        self.pushButton_end.clicked.connect(self.end)
    def start(self):
        self.timer_id = self.startTimer(1000, timerType=QtCore.Qt.VeryCoarseTimer)
        self.pushButton_start.setEnabled(False)
        self.pushButton_end.setEnabled(True)

    def end(self):
        self.signal = False
        if self.timer_id:
            self.killTimer(self.timer_id)
            self.timer_id = 0
        self.pushButton_start.setEnabled(True)
        self.pushButton_end.setEnabled(False)

详见参考链接

多线程

主要解决一个问题,原始错误显示找不到了,大概就是,不能在非GUI的线程中创建或操作GUI组件
意思就是说,在GUI中使用threading.Thread(target=func),执行的func函数中,无法操作GUI组件。因为threading.Thread()不是GUI的线程,只有Qthread是GUI的线程,因此需要使用Qthread代替threading.Thread()

# ......
        self.thread = Thread()
        self.thread.start()
        self.thread.trigger.connect(self.output)
        def output(self):
			# .......
# ......
        
class Thread(QThread):
    """docstring for Thread"""
    trigger = pyqtSignal()
    def __init__(self):
        super(Thread, self).__init__()
    
    def run(self):
        os.system("python run_mrc.py")
        self.trigger.emit()

参考链接,讲的非常好

嵌入网页

参考上一篇博客[Python技能] QtWebView + Jinja2 + JavaScript + MySQL

网页交互

主要是在嵌入的网页上,如果用户点击了网页上的按钮,则产生Js时间,然后将信号传回Python进行下一步响应。
下面代码是创建一个传递给Js的对象,用于信号交互

# -*- coding: utf-8 -*-
from PyQt5.QtCore import *
import time
import random
from concurrent.futures import ThreadPoolExecutor
class MyObjectCls(QObject):
    sigSetParentWindowTitle = pyqtSignal(str)

    def __init__(self, parent=None):
        self.pool = ThreadPoolExecutor(10)
        QObject.__init__(self, parent)

	# 注册信息
    def enroll(self, user_id, friend_id, ):
        self.user_id = user_id
        self.friend_id = friend_id

    @pyqtSlot(str)
    def putMessage(self, msg):
    	# 线程池使用
        self.pool.submit(self.write_messages, msg)

    def write_messages(self, msg):
        cur_time = time.strftime('%Y-%m-%d', time.localtime(time.time()))
		print(cur_time)

下面在主面板创建并注册上述代码中的对象

		# ......
        self.view = QWebEngineView(self)
        self.view.setGeometry(QtCore.QRect(0, 0, 700, 600))
        # 绝对地址,否则无法正常显示
        self.view.setHtml(self.get_chat_msg(), baseUrl=QtCore.QUrl.fromLocalFile(os.path.abspath('templates/chat.html')))
		
		# 注册
        self.channel = QWebChannel(self.view.page())
        self.my_project = MyObjectCls(self.view)
        self.my_project.enroll(self.config["user_id"], self.friend["user_id"])
        self.channel.registerObject("MyObject", self.my_project)
        self.view.page().setWebChannel(self.channel)
        # ......

下面是HTML中的js代码

$(function(){
    $(".mui-btn").click(function () {
        // 事件代码
		
		// 向python进行数据交互,传递数据msg
        new QWebChannel(qt.webChannelTransport, function(channel) {
            var my_object = channel.objects.MyObject;
            my_object.putMessage(msg);
        });

		// 事件代码
    });
});

带行号的文本框

将以下代码保存到文件QCodeEditor.py,使用from QCodeEditor import QCodeEditor,代替本来的QTextEdit即可

#!/usr/bin/python3
# QcodeEditor.py by acbetter.
# -*- coding: utf-8 -*-

from PyQt5.QtCore import Qt, QRect, QSize
from PyQt5.QtWidgets import QWidget, QPlainTextEdit, QTextEdit
from PyQt5.QtGui import QColor, QPainter, QTextFormat


class QLineNumberArea(QWidget):
    def __init__(self, editor):
        super().__init__(editor)
        self.codeEditor = editor

    def sizeHint(self):
        return QSize(self.editor.lineNumberAreaWidth(), 0)

    def paintEvent(self, event):
        self.codeEditor.lineNumberAreaPaintEvent(event)


class QCodeEditor(QPlainTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.lineNumberArea = QLineNumberArea(self)
        self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
        self.updateRequest.connect(self.updateLineNumberArea)
        self.cursorPositionChanged.connect(self.highlightCurrentLine)
        self.updateLineNumberAreaWidth(0)

    def lineNumberAreaWidth(self):
        digits = 1
        max_value = max(1, self.blockCount())
        while max_value >= 10:
            max_value /= 10
            digits += 1
        space = 3 + self.fontMetrics().width('9') * digits
        return space

    def updateLineNumberAreaWidth(self, _):
        self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)

    def updateLineNumberArea(self, rect, dy):
        if dy:
            self.lineNumberArea.scroll(0, dy)
        else:
            self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
        if rect.contains(self.viewport().rect()):
            self.updateLineNumberAreaWidth(0)

    def resizeEvent(self, event):
        super().resizeEvent(event)
        cr = self.contentsRect()
        self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()))

    def highlightCurrentLine(self):
        extraSelections = []
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            lineColor = QColor(Qt.yellow).lighter(160)
            selection.format.setBackground(lineColor)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            extraSelections.append(selection)
        self.setExtraSelections(extraSelections)

    def lineNumberAreaPaintEvent(self, event):
        painter = QPainter(self.lineNumberArea)

        painter.fillRect(event.rect(), Qt.lightGray)

        block = self.firstVisibleBlock()
        blockNumber = block.blockNumber()
        top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
        bottom = top + self.blockBoundingRect(block).height()

        # Just to make sure I use the right font
        height = self.fontMetrics().height()
        while block.isValid() and (top <= event.rect().bottom()):
            if block.isVisible() and (bottom >= event.rect().top()):
                number = str(blockNumber + 1)
                painter.setPen(Qt.black)
                painter.drawText(0, top, self.lineNumberArea.width(), height, Qt.AlignRight, number)

            block = block.next()
            top = bottom
            bottom = top + self.blockBoundingRect(block).height()
            blockNumber += 1


if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    codeEditor = QCodeEditor()
    codeEditor.show()
    sys.exit(app.exec_())

参考StackOverflow Create text area (textEdit) with line number in PyQt

显示GIF

import sys
import os
import time
 #from myUI import Ui_MainWindow #导入生成myUI.py里生成的类
from tab import Ui_testTAB
from PyQt5 import QtWidgets, QtGui, QtCore 
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

#打开gif文件
movie = QtGui.QMovie("./icon/watch.gif") 
#设置cacheMode为CacheAll时表示gif无限循环,注意此时loopCount()返回-1
movie.setCacheMode(QtGui.QMovie.CacheAll) 
#播放速度
movie.setSpeed(100) 
#self.movie_screen是在qt designer里定义的一个QLabel对象的对象名,将gif显示在label上
self.movie_screen.setMovie(movie)   
#开始播放,对应的是movie.start()
movie.start()

其他

  • 无边框按钮
    QtDesigner 中StyleSheet设置为border:none

参考

  • 知乎专栏 PyQt5图形界面编程
    基本所有的PyQT5组件都涉及到了,可能有一些错误,但是仍然能够对PyQT5的功能有总体上的认识
  • Qt Documentation
    PyQt的所有API都在Qt中有对应,由于PyQt的库都被封装在文件中,所有很多都没有自动补全,因此可以在Qt文档中查看相关的类关系
  • 参考StackOverflow Create text area (textEdit) with line number in PyQt
  • PyQt5进阶(二)——多线程:QThread & 事件处理
  • 利用多线程在pyqt5中间接实现无限制录音
  • 【PyQt】在窗口中显示GIF

你可能感兴趣的:(Python)