python GUI库图形界面开发之PyQt5中QWebEngineView内嵌网页与Python的数据交互传参详细方法实例

这几天研究了下PyQt5中QWebEngineView内嵌网页与Python的数据交互,今天把实例方法与代码发布出来供大家参数

数据交互需要load进一个网页,这里我选择load进一个本地html网页:JSTest.html。

同时,QWebEngineView与外面的交互还需要Qt官方提供的一个js文件:qwebchannel.js,这个文件可以在网上下载。

JSTest.html和qwebchannel.js两个文件放在同一个目录下,我这边都是放在Python工程目录下。

qwebchannel.js:

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**  * Redistributions of source code must retain the above copyright
**   notice, this list of conditions and the following disclaimer.
**  * Redistributions in binary form must reproduce the above copyright
**   notice, this list of conditions and the following disclaimer in
**   the documentation and/or other materials provided with the
**   distribution.
**  * Neither the name of The Qt Company Ltd nor the names of its
**   contributors may be used to endorse or promote products derived
**   from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
"use strict";

var QWebChannelMessageTypes = {
  signal: 1,
  propertyUpdate: 2,
  init: 3,
  idle: 4,
  debug: 5,
  invokeMethod: 6,
  connectToSignal: 7,
  disconnectFromSignal: 8,
  setProperty: 9,
  response: 10,
};

var QWebChannel = function(transport, initCallback)
{
  if (typeof transport !== "object" || typeof transport.send !== "function") {
    console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +
           " Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send));
    return;
  }

  var channel = this;
  this.transport = transport;

  this.send = function(data)
  {
    if (typeof(data) !== "string") {
      data = JSON.stringify(data);
    }
    channel.transport.send(data);
  }

  this.transport.onmessage = function(message)
  {
    var data = message.data;
    if (typeof data === "string") {
      data = JSON.parse(data);
    }
    switch (data.type) {
      case QWebChannelMessageTypes.signal:
        channel.handleSignal(data);
        break;
      case QWebChannelMessageTypes.response:
        channel.handleResponse(data);
        break;
      case QWebChannelMessageTypes.propertyUpdate:
        channel.handlePropertyUpdate(data);
        break;
      default:
        console.error("invalid message received:", message.data);
        break;
    }
  }

  this.execCallbacks = {};
  this.execId = 0;
  this.exec = function(data, callback)
  {
    if (!callback) {
      // if no callback is given, send directly
      channel.send(data);
      return;
    }
    if (channel.execId === Number.MAX_VALUE) {
      // wrap
      channel.execId = Number.MIN_VALUE;
    }
    if (data.hasOwnProperty("id")) {
      console.error("Cannot exec message with property id: " + JSON.stringify(data));
      return;
    }
    data.id = channel.execId++;
    channel.execCallbacks[data.id] = callback;
    channel.send(data);
  };

  this.objects = {};

  this.handleSignal = function(message)
  {
    var object = channel.objects[message.object];
    if (object) {
      object.signalEmitted(message.signal, message.args);
    } else {
      console.warn("Unhandled signal: " + message.object + "::" + message.signal);
    }
  }

  this.handleResponse = function(message)
  {
    if (!message.hasOwnProperty("id")) {
      console.error("Invalid response message received: ", JSON.stringify(message));
      return;
    }
    channel.execCallbacks[message.id](message.data);
    delete channel.execCallbacks[message.id];
  }

  this.handlePropertyUpdate = function(message)
  {
    for (var i in message.data) {
      var data = message.data[i];
      var object = channel.objects[data.object];
      if (object) {
        object.propertyUpdate(data.signals, data.properties);
      } else {
        console.warn("Unhandled property update: " + data.object + "::" + data.signal);
      }
    }
    channel.exec({type: QWebChannelMessageTypes.idle});
  }

  this.debug = function(message)
  {
    channel.send({type: QWebChannelMessageTypes.debug, data: message});
  };

  channel.exec({type: QWebChannelMessageTypes.init}, function(data) {
    for (var objectName in data) {
      var object = new QObject(objectName, data[objectName], channel);
    }
    // now unwrap properties, which might reference other registered objects
    for (var objectName in channel.objects) {
      channel.objects[objectName].unwrapProperties();
    }
    if (initCallback) {
      initCallback(channel);
    }
    channel.exec({type: QWebChannelMessageTypes.idle});
  });
};

function QObject(name, data, webChannel)
{
  this.__id__ = name;
  webChannel.objects[name] = this;

  // List of callbacks that get invoked upon signal emission
  this.__objectSignals__ = {};

  // Cache of all properties, updated when a notify signal is emitted
  this.__propertyCache__ = {};

  var object = this;

  // ----------------------------------------------------------------------

  this.unwrapQObject = function(response)
  {
    if (response instanceof Array) {
      // support list of objects
      var ret = new Array(response.length);
      for (var i = 0; i < response.length; ++i) {
        ret[i] = object.unwrapQObject(response[i]);
      }
      return ret;
    }
    if (!response
      || !response["__QObject*__"]
      || response.id === undefined) {
      return response;
    }

    var objectId = response.id;
    if (webChannel.objects[objectId])
      return webChannel.objects[objectId];

    if (!response.data) {
      console.error("Cannot unwrap unknown QObject " + objectId + " without data.");
      return;
    }

    var qObject = new QObject( objectId, response.data, webChannel );
    qObject.destroyed.connect(function() {
      if (webChannel.objects[objectId] === qObject) {
        delete webChannel.objects[objectId];
        // reset the now deleted QObject to an empty {} object
        // just assigning {} though would not have the desired effect, but the
        // below also ensures all external references will see the empty map
        // NOTE: this detour is necessary to workaround QTBUG-40021
        var propertyNames = [];
        for (var propertyName in qObject) {
          propertyNames.push(propertyName);
        }
        for (var idx in propertyNames) {
          delete qObject[propertyNames[idx]];
        }
      }
    });
    // here we are already initialized, and thus must directly unwrap the properties
    qObject.unwrapProperties();
    return qObject;
  }

  this.unwrapProperties = function()
  {
    for (var propertyIdx in object.__propertyCache__) {
      object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]);
    }
  }

  function addSignal(signalData, isPropertyNotifySignal)
  {
    var signalName = signalData[0];
    var signalIndex = signalData[1];
    object[signalName] = {
      connect: function(callback) {
        if (typeof(callback) !== "function") {
          console.error("Bad callback given to connect to signal " + signalName);
          return;
        }

        object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
        object.__objectSignals__[signalIndex].push(callback);

        if (!isPropertyNotifySignal && signalName !== "destroyed") {
          // only required for "pure" signals, handled separately for properties in propertyUpdate
          // also note that we always get notified about the destroyed signal
          webChannel.exec({
            type: QWebChannelMessageTypes.connectToSignal,
            object: object.__id__,
            signal: signalIndex
          });
        }
      },
      disconnect: function(callback) {
        if (typeof(callback) !== "function") {
          console.error("Bad callback given to disconnect from signal " + signalName);
          return;
        }
        object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
        var idx = object.__objectSignals__[signalIndex].indexOf(callback);
        if (idx === -1) {
          console.error("Cannot find connection of signal " + signalName + " to " + callback.name);
          return;
        }
        object.__objectSignals__[signalIndex].splice(idx, 1);
        if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) {
          // only required for "pure" signals, handled separately for properties in propertyUpdate
          webChannel.exec({
            type: QWebChannelMessageTypes.disconnectFromSignal,
            object: object.__id__,
            signal: signalIndex
          });
        }
      }
    };
  }

  /**
   * Invokes all callbacks for the given signalname. Also works for property notify callbacks.
   */
  function invokeSignalCallbacks(signalName, signalArgs)
  {
    var connections = object.__objectSignals__[signalName];
    if (connections) {
      connections.forEach(function(callback) {
        callback.apply(callback, signalArgs);
      });
    }
  }

  this.propertyUpdate = function(signals, propertyMap)
  {
    // update property cache
    for (var propertyIndex in propertyMap) {
      var propertyValue = propertyMap[propertyIndex];
      object.__propertyCache__[propertyIndex] = propertyValue;
    }

    for (var signalName in signals) {
      // Invoke all callbacks, as signalEmitted() does not. This ensures the
      // property cache is updated before the callbacks are invoked.
      invokeSignalCallbacks(signalName, signals[signalName]);
    }
  }

  this.signalEmitted = function(signalName, signalArgs)
  {
    invokeSignalCallbacks(signalName, signalArgs);
  }

  function addMethod(methodData)
  {
    var methodName = methodData[0];
    var methodIdx = methodData[1];
    object[methodName] = function() {
      var args = [];
      var callback;
      for (var i = 0; i < arguments.length; ++i) {
        if (typeof arguments[i] === "function")
          callback = arguments[i];
        else
          args.push(arguments[i]);
      }

      webChannel.exec({
        "type": QWebChannelMessageTypes.invokeMethod,
        "object": object.__id__,
        "method": methodIdx,
        "args": args
      }, function(response) {
        if (response !== undefined) {
          var result = object.unwrapQObject(response);
          if (callback) {
            (callback)(result);
          }
        }
      });
    };
  }

  function bindGetterSetter(propertyInfo)
  {
    var propertyIndex = propertyInfo[0];
    var propertyName = propertyInfo[1];
    var notifySignalData = propertyInfo[2];
    // initialize property cache with current value
    // NOTE: if this is an object, it is not directly unwrapped as it might
    // reference other QObject that we do not know yet
    object.__propertyCache__[propertyIndex] = propertyInfo[3];

    if (notifySignalData) {
      if (notifySignalData[0] === 1) {
        // signal name is optimized away, reconstruct the actual name
        notifySignalData[0] = propertyName + "Changed";
      }
      addSignal(notifySignalData, true);
    }

    Object.defineProperty(object, propertyName, {
      configurable: true,
      get: function () {
        var propertyValue = object.__propertyCache__[propertyIndex];
        if (propertyValue === undefined) {
          // This shouldn't happen
          console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__);
        }

        return propertyValue;
      },
      set: function(value) {
        if (value === undefined) {
          console.warn("Property setter for " + propertyName + " called with undefined value!");
          return;
        }
        object.__propertyCache__[propertyIndex] = value;
        webChannel.exec({
          "type": QWebChannelMessageTypes.setProperty,
          "object": object.__id__,
          "property": propertyIndex,
          "value": value
        });
      }
    });

  }

  // ----------------------------------------------------------------------

  data.methods.forEach(addMethod);

  data.properties.forEach(bindGetterSetter);

  data.signals.forEach(function(signal) { addSignal(signal, false); });

  for (var name in data.enums) {
    object[name] = data.enums[name];
  }
}

//required for use with nodejs
if (typeof module === 'object') {
  module.exports = {
    QWebChannel: QWebChannel
  };
}

Python主函数代码

import sys
import Web_UI
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QObject,pyqtProperty
from PyQt5.QtWebChannel import QWebChannel
from MySharedObject import MySharedObject
from PyQt5.QtWidgets import QApplication
import os

BASE_DIR = os.path.dirname(__file__)#获取当前文件夹的绝对路径

if __name__ == '__main__':
  app = QtWidgets.QApplication(sys.argv)
  MainWindow = QtWidgets.QFrame()
  ui = Web_UI.Ui_Form()
  ui.setupUi(MainWindow)
  ui.webView1.load(QtCore.QUrl(r""+BASE_DIR+"/JSTest.html"))

  channel = QWebChannel() ##创建一个QwebChannel对象,用于传递PyQt的参数到JavaScript
  myObj = MySharedObject()
  print(myObj.strval)

  channel.registerObject('bridge', myObj)
  ui.webView1.page().setWebChannel(channel)

  MainWindow.show()
  sys.exit(app.exec_())

继承了QWidget类的MySharedObject(Python文件)

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

class MySharedObject(QWidget):
  def __init__(self,strval = '100'):
    super(MySharedObject,self).__init__()
    self.strval = strval
  def _getStrValue(self):
    return self.strval
  def _setStrValue(self,str):
    self.strval = str
    print('获得页面参数:%s'% str)
    QMessageBox.information(self,"Infomation", '获得的页面参数%s' % str)
  #需要定义的对外发布的方法
  strValue= pyqtProperty(str,_getStrValue,_setStrValue)

页面代码HTML

<!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>A Demo Page</title>
        <script src = "qwebchannel.js"></script>

        <script language = "javascript">
          function completeAndReturnName(){
            var fname = document.getElementById('fname').value;
            var lname = document.getElementById('lname').value;
            var fullname = fname +' '+ lname;

            document.getElementById('fullname').value = fullname;
            document.getElementById('submit-btn').style.display = 'block';
            return fullname;
          }
          document.addEventListener("DOMContentLoaded",function(){
            new QWebChannel(qt.webChannelTransport, function (channel) {
              //alert('111 chanel='+channel)
              window.bridge = channel.objects.bridge;
              alert('bridge='+bridge.strValue +'\n从pyqt传来的参数='+window.bridge.strValue);
              //alert('111 chanel='+ channel.objects.strValue)
            })
          } )
          function onShowMsgBox() {
            if(window.bridge != null){
              var fname = document.getElementById('fname').value;
              window.bridge.strValue = fname; //调用对象
            }
          }
        </script>
      </head>

      <body>
        <form>
          <label id = "name">User Name:</label>
          <input type = "text" name = "fname" id = "fname"></input>
          <br />
          <input type = "button" value="传递参数到pyqt" οnclick="onShowMsgBox()"></input>
          <br />
          <input type = "reset" value="重置"></input>

        </form>
      </body>
    </html>

实现效果

本文详细介绍了PyQt5中使用QWebEngineView控件内嵌网页与Python的数据交互的方法与实例,更多关于这方面的知识请查看下面的相关链接

(0)

相关推荐

  • python GUI库图形界面开发之PyQt5浏览器控件QWebEngineView详细使用方法

    PyQt5浏览器控件QWebEngineView PyQt5使用QWebEngineView控件来展示HTML页面,对老版本的QWebView类不在进行维护,因为QWebEngineView使用CHromium内核可以给用户带来更好的体验 QWebEngineView类中常用方法 方法 描述 load(QUrl url) 加载指定的URL并显示 setHtml(QString&html) 将网页视图的内容设置为指定的HTML内容 QWebEngineView控件使用load()函数加载一个Web

  • python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性

    QTableWidget介绍 QTableWidget是Qt程序中常用的显示数据表格的控件,类似于c#中的DataGrid.QTableWidget是QTableView的子类,它使用标准的数据模型,并且其单元数据是通过QTableWidgetItem对象来实现的,使用QTableWidget时就需要QTableWidgetItem.用来表示表格中的一个单元格,整个表格就是用各个单元格构建起来的 QTableWidget类中的常用方法 方法 描述 setROwCount(int row) 设置Q

  • python GUI库图形界面开发之PyQt5窗口控件QWidget详细使用方法

    QWidget基本介绍 基础窗口控件QWidget类是所有用户界面对象的基类,所有的窗口或者控件都直接或者间接的继承自QWidget类. 窗口坐标系统 PyQt使用统一的坐标系统来定位窗口控件的位置和大小,具体如下 以屏幕左上角为原点,也就是(0, 0)点,从左向右为x轴正方向,从上向下为y轴正方向,整个屏幕的坐标系统用来定位顶层窗口. 在窗口内部也有自己的坐标系统,该坐标系统以客户区的左上角为原点,从左向右为x轴正方向,从上到下为y轴正方向,在客户区周围有标题栏和边框. 从上图中,可以将这些成

  • python GUI库图形界面开发之PyQt5信号与槽基本操作

    信号与槽基本操作 进入Qt Designer,加入控件,本文以按钮为例. 按F4开始后,选择需要加入信号与槽的按钮,如下图所示该按钮会变红,按住鼠标拉出一条红线,若该按钮需控制旁边的label,则红线连接到label上(图1),若对框体(MainWindow)进行操作,则链接到框体上,会出现一个像物理中"地线"似的符号(图2). 图1 图2 连接后,会弹出如下窗体(图3),左侧界面选择信号,如下图中选择"clicked()"代表点击按钮触发右侧对应槽的操作. 勾选下

  • python GUI库图形界面开发之PyQt5开发环境配置与基础使用

    PyQt5安装 在cmd下输入 pip install PyQt5 完成PyQt5安装,再安装qt designer,可以使用pip安装 pip install PyQt5-tools 安装完成后,在python安装目录下可以看到 配置PyCharm 配置PyCharm是为了在Pycharm里面实现打开qt designer,然后生成qt文件,然后将qt文件转换成python语言的软件文件. 打开Pycharm,按下图操作 打开Extrernal Tools之后,点击上如绿色的+,添加Tools

  • python GUI库图形界面开发之PyQt5中QMainWindow, QWidget以及QDialog的区别和选择

    PyQt中MainWindow, QWidget以及Dialog的区别和选择 1. Qt界面分类 在Qt Designer设计界面时,首先需要选择界面模板,主要分为三个类: Main Window Widget Dialog 2. 三种模板的区别(官方文档介绍) MainWindow QMainWindow类提供一个有菜单条.锚接窗口(例如工具条)和一个状态条的主应用程序窗口. 主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单.工具条和一个状态条.QMainWind

  • python GUI库图形界面开发之PyQt5美化窗体与控件(异形窗体)实例

    在默认情况下,我们使用PyQt5创建出来的窗口和部件都是默认的样式,虽然谈不上很丑,但是也毫无美感可言.其实,在PyQt5中,我们可以有较高的自由度来自定义窗口和各种小部件的样式,通过自定义这些样式,以达到美化图形界面的目的. 本篇文章中,我们就通过一个实际的例子,使用QSS和PyQt5的配置属性,实现图形用户界面的美化工作. 首先上效果图: 一.对界面进行布局和组件的布置 在图像界面编程中,一个好的布局有助于全局把控界面的形态,而在PyQt5中,有多种布局的方式供我们选择,比较常用的布局有以下

  • Python GUI库PyQt5图形和特效样式QSS介绍

    QSS介绍前言 QSS即Qt样式表,是用来自定义控件外观的一种机制,QSS大量参考了Css的内容,但QSS的功能要比Css弱得多,体现在选择器少,可以使用的QSS属性也少,而且并不是所有的属性都可以应用在PyQt的控件上,QSS使页面美化跟代码层分开,利于维护 QSS的语法规则 QSS的语法规则几乎与CSS相同,QSS样式由两部分组成,其中一部分是选择器(Selector),指定哪些软件会受到影响,另一部分是声明(Declaration),指定哪些属性应该在控件上进行设置,声明部分是一系列的"属

  • python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

    QThread是Qt的线程类中最核心的底层类.由于PyQt的的跨平台特性,QThread要隐藏所有与平台相关的代码 要使用的QThread开始一个线程,可以创建它的一个子类,然后覆盖其它QThread.run()函数 class Thread(QThread): def __init __(self): super(Thread,self).__ init __() def run(self): #线程相关的代码 pass 接下来创建一个新的线程 thread = Thread() thread

  • python GUI库图形界面开发之PyQt5时间控件QTimer详细使用方法与实例

    QTimer控件介绍 如果在应用程序中周期性地进行某项操作,比如周期性的检测主机的cpu值,则需要用到QTimer定时器,QTimer类提供了重复和单次的定时器,要使用定时器,需要先创建一个QTimer实例,将其Timeout信号连接到槽函数,并调用start(),然后,定时器,会以恒定的间隔发出timeout信号 当窗口的控件收到Timeout信号后,他就会停止这个定时器,这是在图形用户界面中实现复杂工作的一个典型用法,随着技术的进步,多线程在越来越多的平台上被使用,QTimer对象会被替代掉

  • python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例

    窗口背景主要包括,背景色与背景图片,设置窗口背景有三种方法 使用QSS设置窗口背景 使用QPalette设置窗口背景 实现PainEvent,使用QPainter绘制背景 QSS设置窗口背景 在QSS中,我们可以使用Background或者background-color的方式来设置背景色,设置窗口背景色之后,子控件默认会继承父窗口的背景色,如果想要为控件设置背景图片或图标,则可以使用setPixmap或则setIcon来完成.关于这两个函数的用法,可以参考本博客下的PyQt5的基础控件分栏 实

  • python GUI库图形界面开发之PyQt5 Qt Designer工具(Qt设计师)详细使用方法及Designer ui文件转py文件方法

    PyQt5 Qt Designer (Qt设计师) PyQt5是对Qt所有类进行封装, Qt能开发的东西, PyQt都能开发. Qt是强大的GUI库之一, 用C++开发, 并且跨平台. PyQt双许可证, 要么选择GPL(自由软件协议)将代码开源, 要么选择商业许可交商业许可费. PySide拥有LGPL 2.1授权许可, 可开发 免费开源软件 和 私有商业软件. 把PyQt5代码切换到PySide2代码是相当容易的, 这也是为什么选择学习PyQt5的原因 准备工作 安装PyQt5: pip i

  • python GUI库图形界面开发之PyQt5动态加载QSS样式文件

    在Qt中经常需要使用样式,为了降低耦合性(与逻辑代码分离),我们通常会定义一个QSS文件,然后编写各种控件(QLabel,QLIneEdit,QPushButton等)的样式,最后使用QApplication或QMainWindow来加载样式,这样就可以让整个应用程序共享一种样式了 编写QSS 首先新建一个扩展名为.qss的文件,如style.qss,然后将其加入资源文件(.qrc)中,在style.qss文件中编写样式代码,例如 QMainWindow{ border-image:url(./

  • Python GUI库PyQt5样式QSS子控件介绍

    QSS子控件 QSS子控件实际上也是一种选择器,其应用在一些复合控件上,典型的如QComboBox,该控件的外观是,有一个矩形的外边框,右边有一个下拉箭头,点击之后会弹出下拉列表,例如: QComboBox:drop-down {image:url(dropdown.png)} 上面的样式指定所有的QComboBox下拉箭头的图片是自定义的,图片文件为dropdown.png ::drop-down子控件选择器可以与上面提到到的选择器一起联合使用,例如 QComboBox#myQComboBox

  • python GUI库图形界面开发之PyQt5窗口类QMainWindow详细使用方法

    QMainWindow QMainWindow类中比较重要的方法 方法 描述 addToolBar() 添加工具栏 centralWidge() 返回窗口中心的一个控件,未设置时返回NULL menuBar() 返回主窗口的菜单栏 setCentralWidget() 设置窗口中心的控件 setStatusBar() 设置状态栏 statusBar() 获得状态栏对象后,调用状态栏对象的showMessage(message,int timeout=0)方法 显示状态栏信息,其中第一个参数是要显

  • python GUI库图形界面开发之PyQt5信号与槽机制、自定义信号基础介绍

    信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解.信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方. 在linux.windows等 GUI 工具包中,GUI组件都会注册回调函数用于处理组件所触发的动作,通常是注册对应的函数的函数指针.在之前关于Button的文章中提到了信号与槽的机制的使用,通过该机制可以很好的将组件的信号(如button的clocked.toggled.pressed等)和处理该信号的槽关

  • python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例

    在做界面开发时,无论是移动端的Android,还是我们这里讲的PyQt5,经常会有一个界面开发准则,那就是UI主线程与耗时子线程一定要分开,主线程负责刷新界面,耗时操作,如网络交互.磁盘IO等,都应该放在子线程里执行,它们各司其职,保证系统正常运行,提升整体用户体验. 软硬件环境 windows 10 64bit PyQt5 Anaconda3 with python 3.6.5 实例代码 首先看下工程目录结构 main.py,这是工程入口文件,它负责创建app # -*- coding: ut

  • python GUI库图形界面开发之PyQt5拖放控件实例详解

    本篇,我们学习PyQt5界面中拖放(Drag 和Drop)控件. 拖放动作 在GUI中,拖放指的是点击一个对象,并将其拖动到另一个对象上的动作.比如百度云PC客户端支持的拖放文件以快速移动文件: 拖放动作能够很直观很方便的在GUI程序中完成一些很复杂或繁琐的操作. 在PyQt中实现拖放 在PyQt5中,我们也可以很轻松地使用拖放功能. 使用Qt设计师或者使用API都可以实现.我们先使用Qt设计师将GUI的图形设计出来,在之前的GUI的基础上,我们新建一个选项卡. 我们新建了一个选项卡,然后在里面

随机推荐