Pyqt5

Posted by kifish on April 21, 2018

PyQT is a Python wrapper around the QT GUI application development framework

实际上很多项目都是用的pyqt4,但既然pyqt5已经出了。本次项目就干脆用pyqt5,方便后续维护。
然而,网上的资料还是pyqt4更多一些,pyqt5的资料较少,官方文档对于某些API的介绍只有一行,这种情况就只能翻翻qt的C++文档了。
install(max os X) :
brew install pyqt –with-python3

看到一个计算圆周率每一位的GUI小程序,觉得还不错。作者是用pyqt4和python2写的。直接复制过来,用pyqt5和python3会有些问题。另外,原作者贴的代码似乎漏了一个”/”,导致结果有误。

1
2
3
4
5
6
7
8
9
def pi_digits():
    """generator for digits of pi"""
    q,r,t,k,n,l = 1,0,1,1,3,3
    while True:
        if 4*q+r-t < n*t:
            yield n
            q,r,t,k,n,l = (10*q,10*(r-n*t),t,k,(10*(3*q+r))/t-10*n,l)
        else:
            q,r,t,k,n,l = (q*k,(2*q+r)*l,t*l,k+1,(q*(7*k+2)+r*l)/(t*l),l+2)

见so:
-https://stackoverflow.com/questions/9004789/1000-digits-of-pi-in-python
修正过的代码如下:

def pi_digits():
    q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
    for j in range(1000):
        if 4 * q + r - t < m * t:
            yield m
            q, r, t, k, m, x = 10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x
        else:
            q, r, t, k, m, x = q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2

完整代码,适用于pyqt5,python3.


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#---author:SErHo-----
#---url: https://gist.github.com/2773445

from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import (QWidget, QLabel,
    QComboBox, QApplication,QSpinBox,QTextEdit,QPushButton,QHBoxLayout,QGridLayout)
from time import sleep


class RockPI(QWidget):


    def __init__(self, parent=None):
        super(RockPI, self).__init__(parent)

        self.resize(480, 320)



        spinLabel = QLabel("位数: ")
        self.spinBox = QSpinBox()
        self.spinBox.setMaximum(100000)

        resultLabel = QLabel("结果: ")
        self.resultText = QTextEdit()
        self.resultText.setReadOnly(True)

        self.startButton = QPushButton("开始")
        self.resetButton = QPushButton("重置")


        buttonLayout2 = QHBoxLayout()
        buttonLayout2.addWidget(self.startButton)
        buttonLayout2.addWidget(self.resetButton)


        mainLayout = QGridLayout()
        mainLayout.addWidget(spinLabel, 0, 0)
        mainLayout.addWidget(self.spinBox, 0, 1)
        mainLayout.addWidget(resultLabel, 1, 0, QtCore.Qt.AlignTop)
        mainLayout.addWidget(self.resultText, 1, 1)
        mainLayout.addLayout(buttonLayout2, 3, 1)

        self.setLayout(mainLayout)
        self.setWindowTitle("Rock PI")
        #self.setWindowIcon(QtGui.QIcon('pi.png')) Icon for Windows

        self.timer = None
        self.startButton.clicked.connect(self.start)
        self.resetButton.clicked.connect(self.reset)

    def updateResult(self, value):
        newValue = self.resultText.toPlainText() + value
        self.resultText.setText(newValue)
        if len(newValue)==(self.spinBox.value() + 1):
            self.startButton.setText("开始")
            self.startButton.setEnabled(False)

    def reset(self):
        if self.timer:
            self.timer.add_post.disconnect(self.updateResult)
            self.timer.stop()
            self.timer.quit()
            self.timer.wait()
            self.timer.deleteLater()

        self.timer = None
        self.resultText.clear()
        self.spinBox.setValue(0)
        self.startButton.setText("开始")
        self.startButton.setEnabled(True)
        self.resetButton.setEnabled(False)
        self.startButton.clicked.disconnect(self.suspend)   ###连按两下重置  程序会崩溃。因为disconnect的前提是有connect
        #可以考虑加个类似互锁的机制
        self.startButton.clicked.connect(self.start)



    def start(self):
        self.digits = self.spinBox.value()
        if not self.digits:
            return
        if not self.timer:
            self.timer = Timer(self.digits)
            self.timer.add_post.connect(self.updateResult)

        self.timer.start()
        self.startButton.setText("暂停")
        self.resetButton.setEnabled(True)
        self.startButton.clicked.disconnect(self.start)
        self.startButton.clicked.connect(self.suspend)

    def suspend(self):
        self.timer.stop()
        self.startButton.setText("开始")
        self.startButton.clicked.disconnect(self.suspend)
        self.startButton.clicked.connect(self.start)

class Timer(QtCore.QThread):
    add_post = QtCore.pyqtSignal(str)

    def __init__(self, digits, parent=None):
        super(Timer, self).__init__(parent)
        self.stoped = False
        self.mutex = QtCore.QMutex() #Locker
        self.pi = pi_digits()
        self.digits = digits
        self.printed = False
        self.count = 0

    def run(self):
        with QtCore.QMutexLocker(self.mutex):
            self.stoped = False
        while True:
            if self.stoped or (self.count==self.digits):
                return
            value = next(self.pi)
            #print(value)  output to terminal
            if not self.printed:
                value = str(value) + "."
                self.printed = True
            self.add_post.emit(str(value))

            self.count += 1
            sleep(0.1)

    def stop(self):
        with QtCore.QMutexLocker(self.mutex):
            self.stoped = True




def pi_digits():
    q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
    for j in range(1000):
        if 4 * q + r - t < m * t:
            yield m
            q, r, t, k, m, x = 10*q, 10*(r-m*t), t, k, (10*(3*q+r))//t - 10*m, x
        else:
            q, r, t, k, m, x = q*k, (2*q+r)*x, t*x, k+1, (q*(7*k+2)+r*x)//(t*x), x+2


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)

    rockpi = RockPI()
    rockpi.show()
    sys.exit(app.exec_())


有一些网站上的文档还不错:
-https://pythonprogramming.net/basic-gui-pyqt-tutorial/
-http://pyqt.sourceforge.net/Docs/PyQt5/pyqt4_differences.html#qtgui-module

-https://stackoverflow.com/questions/41848769/pyqt5-object-has-no-attribute-connect

-http://pyqt.sourceforge.net/Docs/PyQt4/old_style_signals_slots.html?highlight=connect
-http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html?highlight=connect

-http://pyqt.sourceforge.net/Docs/PyQt5/
-http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html

-https://www.tutorialspoint.com/pyqt/pyqt_using_qt_designer.htm

-http://zetcode.com/gui/pyqt5/

-https://pythonspot.com/en/pyqt5/

中文论坛:
-http://www.qtcn.org/pyqtbook/