• 用Python线程中更新QML内容


    这是一篇翻译过来的文章,是Qt和QML交互的一篇官方文章,原文地址在: http://developer.qt.nokia.com/wiki/Updating_QML_content_from_Python_threads

    这篇文章,是用PySide来制作的,因此练习之前,需要先安装PySide(Qt的另一种Python实现,由Nokia官方实现)。PySide的可以在下面下载:

    http://developer.qt.nokia.com/wiki/Category:LanguageBindings::PySide::Downloads

    如果你和我一样,使用的是Windows上的Python 2.6,则可以在下面路径下载:

    http://www.pyside.org/files/PySide-1.0.7qt474.win32-py2.6.exe

    =============================================================

    本文的PySide教程展现了如何使用内建的Python线程(非QThread,如threading.Thread)来负责背景的绘制(如下载文件)。在下载这个特殊的例子中,可能使用QNetworkAccessManager更加友好,但这是个例子,我们假定由于某种原因,你不能够使用QNetworkAccessManager这个类(如因为使用了Twisted或者因为已经有了特殊的下载代码,并且希望能够重用)。

    WorkingOnIt.py

    导入需要的模块

    我们将使用标准的Python线程模块(threading)和使用下载库(urllib)。对于PySide程序,我们需要标准的模块QtCore,QtGuiQtDeclarative:

    import os
    import sys
    import threading
    import urllib

    from PySide import QtCore, QtGui, QtDeclartive

    下载对象Downloader

    创建QObject的子类(这样我们可以在自己的下载对象中使用信号,槽和属性)和实现下载文件所需的所有属性以及在UI上显示当前状态。

    class Downloader(QtCore.QObject):
    def __init__(self, url, filename=None):
    super(Downloader, self).__init__()
    self._url = url
    if filename is None:
    filename = os.path.basename(self._url)

    self._filename = filename
    self._progress = 0
    self._running = False
    self._size = -1

    def _download(self):
    def reporthook(pos, block, total):
    if self.size != total:
    self._size = total
    self.on_size.emit()
    self.progress = float(pos * block ) / float(total)
    urllib.urlretrieve(self._url, self._filename, reporthook)
    self.running = False

    @QtCore.Slot()
    def start_download(self):
    if not self.running:
    self.running = True
    thread = threading.Thread(target = self._download)
    thread.start()

    def _get_progress(self):
    return self._progress

    def _set_progress(self, progress):
    self._progress = progress
    self.on_progress.emit()

    def _get_running(self):
    return self._running

    def _set_running(self, running):
    self._running = running
    self.on_running.emit()

    def _get_filename(self):
    return self._filename

    def _get_size(self):
    return self._size

    on_progress = QtCore.Signal()
    on_running = QtCore.Signal()
    on_filename = QtCore.Signal()
    on_size = QtCore.Signal()

    progress = QtCore.Property(float, _get_progress, _set_progress, notify=on_progress)
    running = QtCore.Property(bool, _get_running, _set_running, notify=on_running)
    filename = QtCore.Property(bool, _get_filename, notify=on_filename)
    size = QtCore.Property(bool, _get_size, notify=on_size)


    创建一个新的Downloader实例:

    作为一个例子,我们创建一个新的Downloader对象,用来从MeeGo库中下载N900的内核映像。(实际上测试的时候,发现该映像已经不能够被下载了,坑爹呀!,原先的代码是:

    downloader = Downloader('http://repo.meego.com/MeeGo/builds/trunk/1.1.80.8.20101130.1/handset/images/meego-handset-armv7l-n900/meego-handset-armv7l-n900-1.1.80.8.20101130.1-vmlinuz-2.6.35.3-13.6-n900')

    我替换为:)

    downloader = Downloader('http://www.pyside.org/files/PySide-1.0.7qt474.win32-py2.6.exe')

    QApplication,QDeclarativeView和上下文属性

    通常,我们创建一个QApplication和QDeclarativeView的实例。通过设置Downloader为view中的rootContext的上下文属性downloader,将Downloader导出到QML上下文中。然后简单的通过setSource导入QML文件,show出视图并执行应用:

        app = QtGui.QApplication(sys.argv)
    view = QtDeclarative.QDeclarativeView()
    view.rootContext().setContextProperty("downloader", downloader)
    view.setSource(__file__.replace('.py', '.qml'))
    view.show()
    sys.exit( app.exec_() )


    WorkingOnIt.qml

    该文件为downloader实例中的QML UI界面,最令人感兴趣的是:

    • 当按钮按下的时候,downloader.start_download()(一个PySide的槽)被调用,该方法启动线程
    • 当UI元素使用downloader的属性来决定元素可视与内容-当属性发出修改通知时自动更新。
    import Qt 4.7

    Rectangle
    {
    width
    :200; height:160;

    function formatProgress(size, progress){
    return "" + parseInt(progress*size/1024) + "KiB(" + parseInt(progress * 100.) + "%)";
    }

    Text
    {
    x
    : progressBar.x; y:20;
    width
    : progressBar.width;
    font.pixelSize
    :8;
    text
    :downloader.filename;
    elide
    :Text.ElideRight;
    }

    Rectangle
    {
    id
    :progressBar;
    color
    :"#aaa"

    x:20
    ; y:60;
    width
    :parent.width-40;
    height
    :20;

    Rectangle{
    color
    :downloader.progress<1?"#ee8":"#8e8"
    clip:true

    anchors{
    top:parent.top
    bottom:parent.bottom
    left:parent.left
    }

    parent.width * downloader.progress;

    Text
    {
    anchors{
    fill
    :parent;
    rightMargin
    :5;
    }
    color:"black";
    text:formatProgress(downloader.size, downloader.progress)
    verticalAlignment:Text.AlignVCenter;
    horizontalAlignment:Text.AlignRight;
    }
    }
    }

    Rectangle
    {
    anchors.left
    : progressBar.left;
    anchors.right
    : progressBar.right;

    color
    : "#aad";
    y
    : progressBar.y + progressBar.height + 20;
    height
    : 40;

    Text{
    anchors.fill
    :parent;
    color
    :"#003";
    text
    :downloader.running?"Please wait..." : "Start download"

    verticalAlignment : Text.AlignVCenter
    ;
    horizontalAlignment
    : Text.AlignHCenter;
    }

    MouseArea
    {
    anchors.fill
    : parent;
    onClicked
    : {
    downloader.start_download()
    ;
    }
    }
    }
    }


    (译注:没有合适的语法高亮,使用CSS类似的语法高亮机制。)

    例子执行的外观

    在同一个文件夹中保存文件WorkingOnIt.py和WorkingOnIt.qml,使用python WorkingOnIt.py执行应用。(官方的图片如下)

    thread-in-python-update-in-qml

    =============================================================

    我在windows上执行的时候,发现显示的时候会闪一下。

    这样的交互方式其实是Qt与JavaScript交互的一个重要特性。QML使用的是JavaScript语法进行控制操作,而Qt本身就内建支持了JavaScript语法,在Qt对象导出给JavaScript时,属性,槽是可以直接在JavaScript中调用的,这个在QScriptValue文档中就有明确的说明。

  • 相关阅读:
    The path "" is not valid path to the gcc binary.
    ADB命令介绍
    Android 中Message,MessageQueue,Looper,Handler详解+实例
    Sqlite 修改字段
    曾经光辉岁月 永远海阔天空
    用AchartEngineActivity引擎自定义图表控件和背景折线图
    一个帖子学会Android开发四大组件
    Android获得系统时间(24小时制)
    TagBuilder
    MVC
  • 原文地址:https://www.cnblogs.com/ubunoon/p/QML_PySide.html
Copyright © 2020-2023  润新知