Hello World
PyQt與Qt具有極其相似的類族和API,而且不再使用qmake系統和Q_OBJECT宏使得PyQt在沒有編譯鏈接時頻繁的錯誤而且代碼更加友好。
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_())
將項目中所有文件均放入工作目錄下,使用python
或pythonw
命令執行入口文件,即可啟動PyQt應用。
可視化組件
PyQt的可視化組件依舊以QtGui.QWidget作為基類,與Qt的API非常類似。更多信息參見
布局使用示例:
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:
# -*- 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_())