1.每個應用必須創建一個 QtGui.QApplication(sys.argv), 此時 QtGui.qApp 為此應用的實例
app = QtGui.QApplication(sys.argv) sys.exit(app.exec_()); #因為exec是關鍵字, 所以 Qt 用的 exec_, app.exec_() 表示進入循環
2.所有界面圖形類都繼承自 QtGui.QWidget, 比如 QtGui.QPushButton 等都可以使用 setGeometry() 等方法, QWidget 如果沒有指定父, 那么它就是頂級窗口
必須設置可以顯示的父類, 或者調用自身的 show()/exec_() 方法才可以顯示
3.QtGui.QPushButton('Quit', widget), 創建一個 QPushButton 實例, 放在 widget 上
4.PyQt4 事件處理系統建立在 信號-槽 的基礎上
槽詳解可以參考以下兩篇文章, PyQt4信號和槽用法總結, 信號和槽詳解
事件(Events) 是 GUI 程序中很重要的一部分, 它由用戶或系統產生, 當我們調用程序的 exec_() 方法時, 程序就會進入主循環中, 主循環捕獲事件並將它們發送給相應的對象進行處理, 當用戶單擊一個按鈕, 拖動一個滑塊或進行其它動作時, 相應的信號就會被發射, 除此之外, 信號還可以因為環境的變化而被發射, 比如一個運行的時鍾將會發射時間信號等, 而所謂的槽則是一個方法, 該方法將會響應它所連接的信號
信號與槽機制作為 Qt 最重要的特性, 提供了任意兩個 Qt 對象之間的通信機制, 信號會在某個特定情況或動作下被觸發, 槽是用於接收並處理信號的函數
每個Qt對象都包含預定的信號和槽, 當一某一特定事件發生時, 一個信號被發射, 與信號相關聯的槽則會響應信號完成相應的處理
信號與槽機制常用的連接方式為: connect(Object1,SIGNAL(signal),Object2,SLOT(slot)), 其中槽函數可以是 PyQt 自帶的的槽函數, 也可以是自定義的槽函數(@QtCore.pyqtSlot()), 甚至是任何 Python 可以調用的函數
w.connect(btn, QtCore.SIGNAL("clicked()"), QtGui.qAPP, QtCore.SLOT("quit()"))
或
#coding:utf-8 from PyQt4 import QtGui, QtCore app = QtGui.QApplication([]) w = QtGui.QWidget() def showMsg(): QtGui.QMessageBox.information(w, u"信息", u"ok") btn = QtGui.QPushButton(u"點我", w) w.connect(btn, QtCore.SIGNAL("clicked()"), showMsg) #或者 btn.clicked.connect(showMsg) w.show() app.exec_()
button 對象的 clicked() 信號連接到 showMsg 函數, 也就是說 ShowMsg 響應了一個按鈕的點擊事件
5.建立帶菜單欄、工具欄、狀態欄的窗口, 可使用或者繼承 QMainWindow 類
statusBar(), menuBar(), addToolBar() 返回對應的類實例
fileMenu = xxx.menuBar().addMenu("&File")
fileMenu.addAction(aaa)
同理 toolBar
6.布局方式:
絕對定位: 使用 move(), setGeometry()
盒子定位: QHBoxLayout(水平定位), QVBoxLayout(垂直定位)
網格定位: QGridLayout(addWidget 的時候可以指定行或列的跨度)
addStretch() 增加一個可伸縮的占位符, 也相當於一個元素, 其中在添加 Widget 的時候也可以指定 stretch, 表示伸縮比例
addSpacing() 增加一個固定寬高的空白符
在使用布局時, 可以不指定控件的父窗口, 當父窗口 addLayout() 或者 setLayout() 時, 布局內的所有控件都會重定義其父窗口到父窗口
布局對象.setSizeConstraint(val) 用來設置窗體約束尺寸, 比如 val 可以為 QLayout.setFixedSize
6.常見對話框 QColorDialog、QErrorMessage、QFileDialog、QFontDialog、QInputDialog、QMessageBox、QProgressDialog、QTabDialog、QWizard
7.常用控件類
空白占位符: QSpacerItem
圖標: QIcon
氣泡: QToolTip
按鈕: QPushButton
按鈕組: QButtonGroup
會話框按鈕組: QDialogButtonBox
文本: QLabel
文本瀏覽器: QTextBrowser 可以認為是不可編輯的QTextEdit
時間編輯器: QDateTimeEdit
單文本編輯器: QLineEdit
多文本編輯器: QTextEdit
加減數字: QSpinBox
數字LCD顯示器: QLCDNumber(槽 display(int))
滑動條: QSlider(信號 valueChanged(int) 等)
顏色類: QColor
窗口或控件的調色板: QPalette, 每個窗口或空間都會有, 此類有兩個基本概念: ColorGroup(包括焦點/失去/不可用) 和 ColorRole(指窗體的哪部分)
圖片類: QPixMap(主要用來顯示圖片), QImage(主要用來修改圖片), label->setPixMap(QtGui.QPixMap("icon/logo.png"))
進度條: QProgressBar
計時器: QBasicTimer, QTimer, 配合 "timeout()" 信號, 或者重定義 timerEvent 事件
時間: QTime
單選框: QRadioButton
多選框: QCheckbox
下拉列表: QStringList
下拉列表: QComboBox
圖片按鈕: QToolButton
工具箱列表: QToolBox
表格: QTableWidget
標簽欄: QTabWidget
多窗口: QWorkspace, 使用時可以用 QMainWindow 實例的 setCentralWidget(QWorkspace())
分割窗口: QSplitter
可挪動窗口: QDockWidget
菜單: QMenu
菜單欄/工具欄按鈕: QAction, "triggered()"
堆棧窗口實現: QListWidget, QStackedWidget 分別配合自身的 currentRowChanged(int) 和 setCurrentIndex(int) 實現, 另需配合 QSplitter
啟動畫面: QSplashScreen
打印機: QPrinter, QPrintDialog
圖形: QPainerPath 它是由一些圖形如曲線、矩形、橢圓組成的對象
8.信號與槽
所有繼承自 QObject 的類都可以發射信號, emit 方法用來發射信號
自定義信號
class Emit(QtGui.QWidget): def __init__(self, parent = None): QtGui.QWidget.__ini__(self, parent) self.setWindowTitle("Emit") self.resize(250, 150) self.connect(self, QtCore.SIGNAL("closeEmitApp()"), self, QtCore.SLOT("close()")) def mousePressEvent(self, event): self.emit(QtCore.SIGNAL("closeEmitApp()"))
clicked(), 被點擊時
valueChanged(int), 數值被該表時
triggered() 菜單欄/工具欄被觸發時
9.槽
quit()
10.位置坐標等函數
self.x()
self.y()
self.frameGeometry().x(), self.frameGeometry().y(), self.frameGeometry().width(), self.frameGeometry().height()
self.pos().x(), self.pos().y()
self.geometry().x(), self.geometry().y(), self.geometry().width(), self.geometry().height()
self.width()
self.height()
self.rect().x(), self.rect().y(), self.rect().width(), self.rect().height()
self.size().width(), self.size().height()
rect()和 size(),調用它們獲得的結果也都是對於窗體的中央區域而言的, size() 獲得的是窗體中央區域的長,寬值, rect()與 geometry()一樣返回一個 QRect 對象。其中, 兩個函數獲得的長,寬值是一樣的,都是窗體中央區域的長,寬值,只是左上頂點坐標值不 一樣, geometry()獲得的左上頂點坐標是相對於父窗體而言的坐標,而 rect()獲得的左上頂 點坐標始終為(0,0)。
12.禁止最大化和調整
#禁止最大化按鈕 其中MainWindow可以為任何QWidget MainWindow.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint) #禁止調整窗口大小 其中MainWindow可以為任何QWidget MainWindow.setFixedSize(MainWindow.width(), MainWindow.height());
13.創建顏色 Icon
for color in QColor.colorNames(): pix = QPixmap(QSize(70, 20)) pix.fill(QColor(color)) icon = QIcon(pix)
14.自定義移動
def mousePressEvent(self,event): if event.button()==Qt.LeftButton: self.dragPosition=event.globalPos()-self.frameGeometry().topLeft() event.accept() def mouseMoveEvent(self,event): if event.buttons() & Qt.LeftButton: self.move(event.globalPos()-self.dragPosition) event.accept()
15.在 QListWidget 中添加 QCheckBox 對象
list = QListWidget() item = QListWidgetItem() checkbox = QCheckBox(self.tr("英語")) list.addItem(item) list.setItemWidget(item, checkbox)
16.獲取 QListWidget 中的 QWidget 對象
for i in range(list.count()): item = list.item(i) widget = list.itemWidget(item)
17.QDialog 的 exec_() 與 self.done(int) 配合
dialog = MyDialog() r = dialog.exec_() #其中 r 為 dialog 調用 done 時返回的值
18.QLineEdit 密碼時顯示星號, 而不是點號
lineEdit.setStyleSheet("lineedit-password-character: 42");
19.關閉窗口函數
1).關閉主窗口並退出程序是 QApplication::exit()
2).如果是QDialog, 就 accept() 或 reject() 或 done()
3).對於所有QWidget, 就close()
20.信號
1).QObject 類及其子類可以隨意發射信號 比如: 一個button中self.emit("mysignal()"), 另一個接收 QObject.connect(btn, SIGNAL("mysignal()"), self.showMsg)
2).在QObject 類中自定義信號 QtCore.pyqtSignal([int[, str[, float[, list[, dict[, tuple[, object]]]]]]]), 此種方式不能在 __init__ 中, 只能是預定義好的成員屬性
3).可以用 signal.emit(var, ...), 或者 obj.emit(SIGNAL("mysignal(int...)", var, ...) 來發射帶參數的信號
21.信號與槽的觸發關系
1).一個信號可以與另一個信號相連
connect(Object1,SIGNAL(signal1),Object2,SIGNAL(signal1)) 即表示Object1的信號1發射可以觸發Object2的信號1發射
2).表示一個信號可以與多個槽相連
connect(Object1,SIGNAL(signal2),Object2,SLOT(slot2))
connect(Object1,SIGNAL(signal2),Object3,SLOT(slot1))
3).表示同一個槽可以響應多個信號
connect(Object1,SIGNAL(signal2),Object2,SLOT(slot2))
connect(Object3,SIGNAL(signal2),Object2,SLOT(slot2))
22.設置 QTextEdit/QTextBrowser 自動滾動
cursor = textBrowser.textCursor()
cursor.movePosition(QTextCursor.End)
textBrowser.setTextCursor(cursor)
23.多線程
談到 Python 的多線程, 不得不說全局解釋器鎖(GIL), Python 代碼的執行由Python 虛擬機(也叫解釋器主循環)來控制, Python 在設計之初就考慮到要在主循環中, 同時只有一個線程在執行, 就像單 CPU 的系統中運行多個進程那樣, 內存中可以存放多個程序, 但任意時刻, 只有一個程序在 CPU 中運行, 同樣地, 雖然 Python 解釋器中可以“運行”多個線程, 但在任意時刻, 只有一個線程在解釋器中運行
1). 設置GIL
2). 切換到一個線程去運行
3). 運行:
a.指定數量的字節碼指令
b.線程主動讓出控制(可以調用time.sleep(0))
c.在調用外部代碼(如C/C++擴展函數)的時候, GIL 將會被鎖定, 直到這個函數結束為止(由於在這期間沒有Python 的字節碼被運行, 所以不會做線程切換)
4). 把線程設置為睡眠狀態
5). 解鎖GIL
6). 再次重復以上所有步驟
守護線程一般是一個等待客戶請求的服務器, 果你設定一個線程為守護線程, 就表示你在說這個線程是不重要的, 在進程退出的時候, 不用等待這個線程退出, 需要在 thread.start() 之前設置 deamon 屬性
24.PyQt 的多線程實例
http://www.cppblog.com/mirguest/archive/2012/02/05/164984.html
http://ju.outofmemory.cn/entry/141128
25.PyQt 學習資料
http://www.cnblogs.com/txw1958/archive/2011/12/18/2291928.html
26.多線程使用信號和槽進行通信
27.在槽端可以使用 self.sender() 獲取發送信號的對象