從Qt到PyQt

Hello World

PyQt與Qt具備極其類似的類族和API,並且再也不使用qmake系統和Q_OBJECT宏使得PyQt在沒有編譯連接時頻繁的錯誤並且代碼更加友好。html

from PyQt4 import QtCore, QtGui
import sys

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv);
    mainWindow = QtGui.QMainWindow();
    mainWindow.setWindowTitle('Hello World from PyQt')
    mainWindow.show()
    label = QtGui.QLabel('Hello World', mainWindow)
    label.show()
    sys.exit(app.exec_())

將項目中全部文件均放入工做目錄下,使用pythonpythonw命令執行入口文件,便可啓動PyQt應用。python

可視化組件

PyQt的可視化組件依舊以QtGui.QWidget做爲基類,與Qt的API很是相似。更多信息參見數據庫

PyQt doc服務器

Qt doc網絡

佈局使用示例:app

from PyQt4 import QtCore, QtGui
import sys

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv);
    # init Gui
    mainWindow = QtGui.QMainWindow();
    mainWindow.setWindowTitle('Hello World from PyQt')
    button = QtGui.QPushButton('quit',mainWindow)
    # set layout
    mainLayout = QtGui.QVBoxLayout(mainWindow)
    mainLayout.addWidget(button)
    mainWindow.setLayout(mainLayout)
    # show GUI
    mainWindow.show()
    button.show()
    # init Signal-Slot , Run App
    QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), app, QtCore.SLOT('quit()'))
    # QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), app.quit)
    sys.exit(app.exec_())

使用Qt Designer

Qt Designer 依舊生成.ui後綴名的xml文件保存界面設計,pyuic4工具能夠將.ui格式編譯爲.py格式的Python類。函數

確保pyuic4命令所目錄在path中,執行:pyuic4 firstDesign.ui > ui_firstDesign.py,工具

能夠獲得文件 ui_firstDesign.py:oop

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'firstDesign.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        # ...
        # something has been deleted 
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton.setText(_translate("MainWindow", "OK", None))

導入ui_firstDesign模塊,調用Ui_MainWindow.setupUi()方法創建UI:佈局

#main.pyw
import sys
from PyQt4 import QtCore, QtGui

from ui_firstDesign import Ui_MainWindow

class MyForm(QtGui.QMainWindow):
    def __init__(self, parent = None):
        QtGui.QMainWindow.__init__(self,parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    form = MyForm()
    form.show()
    sys.exit(app.exec_())

運行:

使用Python標準庫

PyQt包含如下模塊:

  • QtCore

核心非GUI組件,包括QObject,事件與信號槽,數據流等。

  • QtGui

可視化組件與繪圖系統。

  • QtOpenGL

OpenGL 支持並與QtGui 結合

  • QtSvg

提供對可縮放矢量圖(SVG)的支持。

  • QtNetwork

提供IP,TCP,UDP協議套接字支持,能夠開發簡單客戶端與服務器。

  • QtXml

提供DOM與SAX兩種xml解析

  • QtSql

提供對Sql的支持

與C++不一樣,Python標準庫具備不少方便使用的功能。在使用C++/Qt時做筆者選擇使用QString取代std::string,並使用Qt庫提供的網絡操做,多任務模型,數據庫模塊等。

在使用PyQt時可使用標準的Python 網絡,多任務和數據庫模塊。PyQt的QThread具備支持Qt的事件循環,在須要事件驅動機制可使用,但沒法避開GIL形成性能損失。

信號槽與事件

信號槽

PyQt中絕大多數類均繼承了QObject類,QtCore.QObject與QtCore提供了一系列方法進行信號槽操做:

  • QtCore.pyqtSignal()

用於定義信號對象:signalObj = QtCore.pyqtSignal(*args)

  • @QtCore.pyqtSlot()

使用裝飾器將一個函數對象裝飾爲槽函數:

from PyQt4 import QtGui, QtCore

class MainWidget(QtGui.QWidget):
    def __init__():
        pass

    @QtCore.pyqtSlot()
    def onClicked(self):
        QtGui.QMessageBox.information(self, u"Message", u"Get a Signal")
  • QtCore.SIGNAL() 與 QtCore.SLOT()

將表明函數簽名的字符串轉化爲信號槽,與Qt中的SIGNAL()和SLOT宏功能相同。

  • QObject.connect()

connect具備兩種經常使用方式,即槽可使用Python函數對象或者@QtCore.pyqtSlot()修飾的PyQt槽。

QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), app, QtCore.SLOT('quit()'))

或者:

QtCore.QObject.connect(button, QtCore.SIGNAL('clicked()'), app.quit)
  • QObject.emit()

QObject.emit()用於發送信號,與Qt中的emit關鍵字功能相同。

class MyWidget(QtGui.QWidget):
    def emitSignal(self):
        self.emit(QtCore.SIGNAL('onClicked()'))

或者

class MyWidget(QtGui.QWidget):
    def emitSignal(self):
        self.mySignal = QtCore.pyqtSignal();

emit的可選參數能夠發送帶參數的信號:

self.emit(QtCore.SIGNAL('myClicked(QString)'), 'hello')

示例:

from PyQt4 import QtCore, QtGui
import sys

class MyButton(QtGui.QPushButton):

    def __init__(self, *args, **kwargs):
        QtGui.QPushButton.__init__(self, *args, **kwargs)
        self.connect(self, QtCore.SIGNAL("clicked()"), self.emitSignal)

    def emitSignal(self):
        self.emit(QtCore.SIGNAL('myClicked(QString)'), 'hello')




app = QtGui.QApplication(sys.argv);
mainWindow = QtGui.QMainWindow();

@QtCore.pyqtSlot()
def showMsg(sig):
    QtGui.QMessageBox.information(mainWindow, "Msg", "Siganl Received:" + sig)

if __name__ == '__main__':
    #my Signal
    button = MyButton('emit signal',mainWindow)
    mainWindow.connect(button,QtCore.SIGNAL('myClicked(QString)'), showMsg)
    #quit button
    quitButton = QtGui.QPushButton('quit', mainWindow)
    quitButton.move(0,40)
    QtCore.QObject.connect(quitButton, QtCore.SIGNAL('clicked()'), app, QtCore.SLOT('quit()'))
    # Start App
    mainWindow.show()
    button.show()
    sys.exit(app.exec_())

event()事件處理機制

QObject.event()是PyQt中處理處理事件的另外一個機制, 繼承QObject()的類均可以重寫event系列方
系列實現事件處理。

event()方法進行事件分發通常不直接處理事件,類族中event()鏈式調用能夠方便的自定義事件處理。

一個事件將從最末端派生類的event函數開始處理,當一個事件被處理後調用QObject.accept()方法通知Qt結束該事件處理過程;;若該事件未被處理,Qt將會把該事件交由其父類的event函數處理。
bool QOject::isAccepted()函數將返回表明事件是否被處理的邏輯值。

若在事件處理過程當中,調用了QObject::ignore()方法,Qt將會終止事件向上遞歸,即忽略事件直接終止事件處理過程.忽略事件是危險的,儘可能不要這麼作。

示例,自定義事件處理:

from PyQt4 import QtCore, QtGui
import sys

class MyWidget():
    def event(self,event):
        if(event.type() == QtCore.QEvent.KeyPress):
            if (event.key() == QtCore.Qt.Key_Escape):
                self.emit(QtCore.SIGNAL("escapePressed()"))
                event.accept()
                return True
        return super(MyWidget, self).event(event)

重寫鍵盤事件處理keyReleaseEvent()與繪圖paintEvent()等方法能夠方便的處理按鍵或者繪製界面。以及內置的計時系統timerEvent()。

注意必須設置位置參數event:def keyPressEvent(self, event):

示例,[ESC]鍵退出應用:

# !/usr/bin/python
import sys
from PyQt4 import QtGui, QtCore

class Escape(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.setWindowTitle('escape')
        self.resize(250, 150)
        self.connect(self, QtCore.SIGNAL('closeEmitApp()'),
        QtCore.SLOT('close()'))

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.close()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    qb = Escape()
    qb.show()
    sys.exit(app.exec_())

繪圖系統

由於不須要Q_PROPERTY因此使用更加方便。
QAnimation示例:

from  PyQt4 import QtCore, QtGui
import sys

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mainWindow = QtGui.QMainWindow()
    mainWindow.resize(400, 400)
    mainWindow.show()
    label = QtGui.QLabel('Animated Button', mainWindow)
    label.show()
    # Animation
    animation = QtCore.QPropertyAnimation(label, 'geometry', mainWindow)
    animation.setDuration(10 * 1000)
    animation.setKeyValueAt(0.5, QtCore.QRect(125, 250, 100, 30))
    animation.setEndValue(QtCore.QRect(250, 0, 100, 30))
    animation.start()
    #Run event loop
    sys.exit(app.exec_())

Graphics View示例:

from  PyQt4 import QtCore, QtGui
import sys

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mainWindow = QtGui.QMainWindow()
    mainWindow.resize(300, 200)
    mainWindow.show()
    # Graphics View
    scene = QtGui.QGraphicsScene(mainWindow)
    scene.addText('Graphics View Rotate')
    view =QtGui.QGraphicsView(scene,mainWindow)
    view.resize(200,150)
    view.rotate(+45)
    view.show()
    #Run event loop
    sys.exit(app.exec_())
相關文章
相關標籤/搜索