PyQt5快速入门(七)PyQt5扩展

一、PyQt5项目发布

1、PyInstaller简介

PyInstaller是一款免费易用的打包工具,支持Windows、Linux、MacOS,并且支持32位和64位系统。
http://www.pyinstaller.org/
PyInstaller安装:
pip install pyinstaller

2、PyInstaller使用

PyInstaller使用命令如下:
pyinstaller yourprogram.py
PyInstaller使用时需切换至xxx.py文件所在目录下。
常用可选项如下:
-F:打包后只生成单个可执行文件
-D:默认选项,创建一个目录,包含可执行文件以及大量依赖文件
-c:默认选项,使用控制台
-w:不使用控制台
-p:添加搜索路径,让其找到对应的库
-i:改变生成程序的icon图标。

3、PyInstaller原理

PyInstaller将Python解释器和Python脚本打包成一个可执行文件,并没有编译为机器码。PyInstaller打包的可执行文件不会提高运行效率,而且可能会降低运行效率。打包的优势是在运行机器上不用安装Python和Python脚本所依赖的库。在Linux系统下,PyInstaller主要使用binutil工具包中的ldd和objdump命令。
PyInstaller会分析指定的Python脚本所依赖的其它依赖,然后进行查找和复制,把所有的依赖都收集起来并进行加密处理,包括Python解释器,最后将文件打包到一个目录或打包到可执行文件中。
使用PyInstaller打包生成的可执行文件,只能在和打包机器相同的环境下运行,如果要在不同的操作系统上运行,必须在新的操作系统环境上重新打包。

二、网页交互

1、QWebEngineView简介

PyQt5使用QWebEngineView来展示HTML页面,WebEngine是基于谷歌Chromium引擎开发的,PyQt5中可以使用PyQt5.QtWebKitWidgets.QWebEngineView来使用网页控件。
QWebEngineView使用load(QUrl url)加载指定的URL定显示,setHtml(QString &html)用于将网页视图的内容设置为指定的HTML内容。
QWebEngineView使用load加载一个Web页面,实际是使用HTTP GET方法加载Web页面。

2、加载显示外部Web页面

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *

class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.layout = QVBoxLayout()
        self.browser = self.browser = QWebEngineView()
        self.layout.addWidget(self.browser)
        self.setLayout(self.layout)
        self.browser.load(QUrl("http://www.51cto.com/"))

        self.setWindowTitle("HuaWei Web")
        self.setGeometry(5, 30, 1355, 730)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

3、加载本地Web页面

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *

class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.layout = QVBoxLayout()
        self.browser = self.browser = QWebEngineView()
        self.layout.addWidget(self.browser)
        self.setLayout(self.layout)
        self.browser.load(QUrl(r"/home/user/PyQt.html"))

        self.setWindowTitle("Local HTML")
        self.setGeometry(5, 30, 1355, 730)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

4、加载并显示嵌入的HTML代码

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *

class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.layout = QVBoxLayout()
        self.browser = self.browser = QWebEngineView()
        self.layout.addWidget(self.browser)
        self.setLayout(self.layout)
        self.browser.setHtml('''
                            <!DOCTYPE html>
                            <html>
                            <head>
                           <meta charset="UTF-8">
                           <title>PyQt5</title>
                            </head>
                           <body>
                              hello PyQt5
                              <h2>hello PyQt5<h2>
                           </body>
                            </html>
                            ''')

        self.setWindowTitle("Local HTML")
        self.setGeometry(5, 30, 1355, 730)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

5、PyQt5调用JavaScript代码

通过QWebEnginePage的runJavaScript(str, callable)可以方便地实现PyQt5和HTMP/JavaScript的双向通信,实现了Python代码和HTMP/JavaScript代码的解耦,便于开发人员进行分工协作,

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView
import sys

html = '''
      <html>
        <head>
          <title>A Demo Page</title>
          <script language="javascript">
            // Completes the full-name control and
            // shows the submit button
            function completeAndReturnName() {
              var fname = document.getElementById('fname').value;
              var lname = document.getElementById('lname').value;
              var full = fname + ' ' + lname;
              document.getElementById('fullname').value = full;
              document.getElementById('submit-btn').style.display = 'block';
              return full;
            }
          </script>
        </head>
        <body>
          <form>
            <label for="fname">First name:</label>
            <input type="text" name="fname" id="fname"></input>
            <br />
            <label for="lname">Last name:</label>
            <input type="text" name="lname" id="lname"></input>
            <br />
            <label for="fullname">Full name:</label>
            <input disabled type="text" name="fullname" id="fullname"></input>
            <br />
            <input style="display: none;" type="submit" id="submit-btn"></input>
          </form>
        </body>
      </html>
    '''

class MainWindow(QWidget):
    def __init__(self,parent=None):
        super(MainWindow, self).__init__(parent)
        self.result = None
        self.layout = QVBoxLayout()
        self.webView = QWebEngineView()
        self.webView.setHtml(html)
        self.layout.addWidget(self.webView)
        button = QPushButton('设置全名')
        self.layout.addWidget(button)
        self.setLayout(self.layout)
        self.resize(400, 200)
        self.setWindowTitle("PyQt JS")
        button.clicked.connect(self.complete_name)

    def complete_name(self):
        self.webView.page().runJavaScript('completeAndReturnName();', self.js_callback)

    def js_callback(self, result):
        self.result = result
        print(result)

if __name__ == "__main__":
    # 创建一个 application实例
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

6、JavaScript调用PyQt5代码

JavaScript调用PyQt代码是指PyQt可以与加载的Web页面进行双向的数据交互。首先,使用QWebEngineView对象加载Web页面后可以获得页面中表单输入数据,在Web页面中通过JavaScript代码收集用户提交的数据。然后,在Web页面中,JavaScript通过桥连接方式传递数据给PyQt。PyQt接收到Web传递的数据,经过业务处理后,把处理过后的数据返回给Web页面。
(1)创建QWebChannel对象
创建QWebChannel对象,注册一个需要桥接的对象,以便Web页面的JavaScript使用。
channel = QWebChannel()
obj = ClassName()
channel.registerObject("bridge", obj)
view.page().setWebChannel(channel)
(2)创建共享数据的PyQt对象
创建的共享对象需要继承自QWidget或QObject。

from PyQt5.QtCore import QObject
from PyQt5.QtCore import pyqtProperty
from PyQt5.QtWidgets import QWidget, QMessageBox

class SharedObject(QWidget):

    def __init__(self):
        super(SharedObject, self).__init__()

    def _getStrValue(self):
        #
        return '100'

    def _setStrValue(self, str):
        # get web parameter
        print("web parameter: ", str)

    # 需要定义对外发布的方法
    strValue = pyqtProperty(str, fget=_g
```etStrValue, fset=_setStrValue)

(3)创建调用PyQt的Web页面
在Web页面访问PyQt中注册的对象,获得channel.objects.bridge共享对象,bridge是在PyQt中注册共享对象时指定的名称,核心代码如下:

document.addEventListener("DOMContentLoaded", function()
{

new QWebChannel(qt.webChannelTransport, function(channel){
    window.bridge = channel.objects.bridge;
    alert('bridge=' + bridge + '\n从pyqt传来的参数=' + window.bridge.strValue);
});

});