用Python线程中更新QML内容
2011-11-18 22:24 ubunoon 阅读(1801) 评论(0) 编辑 收藏 举报这是一篇翻译过来的文章,是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,QtGui和QtDeclarative:
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文档中就有明确的说明。
*
* Copyright (c) 2011 Ubunoon.
* All rights reserved.
*
* email: netubu#gmail.com replace '#' to '@'
* http://www.cnblogs.com/ubunoon
* 欢迎来邮件定制各类验证码识别,条码识别,图像处理等软件
* 推荐不错的珍珠饰品,欢迎订购 * 宜臣珍珠(淡水好珍珠) */