用Python線程中更新QML內容

來源:互聯網
上載者:User

這是一篇翻譯過來的文章,是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文檔中就有明確的說明。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.