您的位置:首页 > 编程语言 > Python开发

用Python线程中更新QML内容

2011-11-18 22:24 169 查看
这是一篇翻译过来的文章,是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
}

width: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执行应用。(官方的图片如下)



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

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

这样的交互方式其实是Qt与JavaScript交互的一个重要特性。QML使用的是JavaScript语法进行控制操作,而Qt本身就内建支持了JavaScript语法,在Qt对象导出给JavaScript时,属性,槽是可以直接在JavaScript中调用的,这个在QScriptValue文档中就有明确的说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: