經常有初學者搞不清楚如何在PyQt中彈出對話框,以及如何處理返回值。這篇文章會舉例說明,界面采用手工編寫。
我們一般說的對話框指的是模態對話框(Modal Dialogue Box),一旦彈出,就不能對話框以外的窗口進行操作,必須先關閉對話框。
在PyQt中我們一般從QDialog繼承創建一個類來操作,根據exec_()方法的返回值判斷用戶是【確定】還是【取消】了,當然也可以其他返回值,具體看文檔。
這個例子創建一個主窗口,有一個表格,記錄用戶姓名和年齡,一個【添加】按鈕,點擊彈出對話框,用戶輸入姓名和年齡,點擊【確定】返回,在主窗體表格中插入一行數據。
創建主窗體
為了方便起見使用QWdiget創建主窗體,當然你可以使用QMainWindow,用QTableView和QStandardItemModel來創建表格。
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
# 創建table和model
table = QtGui.QTableView(parent=self)
self.model = QtGui.QStandardItemModel(parent=self)
self.model.setHorizontalHeaderLabels((u'姓名', u'年齡'))
table.setModel(self.model)
# 創建添加按鈕
button = QtGui.QPushButton(u'添加', parent=self)
# 添加信號槽
button.clicked.connect(self.add)
# 創建一個垂直布局,用於防止表格和按鈕
layout = QtGui.QVBoxLayout()
layout.addWidget(table)
layout.addWidget(button)
self.setLayout(layout)
def add(self):
pass
創建對話框
對話框從QDialog繼承,按鈕這里使用QButtonBox來創建,用QButtonBox的好處是創建方便,定義參數即可,並且會自動根據不同平台顯示按鈕的位置,和各平台風格保持一致,當然默認是英文的,你可以通過國際化來做成中文的。
這里沒有做對話框內容的驗證,你可以覆蓋QDialog的accept方法來進行驗證。
下面是對話框的創建代碼,為了方便獲取姓名和年齡變量,我寫了兩個方法供外部調用。
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.resize(240, 200)
# 表格布局,用來布局QLabel和QLineEdit及QSpinBox
grid = QtGui.QGridLayout()
grid.addWidget(QtGui.QLabel(u'姓名', parent=self), 0, 0, 1, 1)
self.leName = QtGui.QLineEdit(parent=self)
grid.addWidget(self.leName, 0, 1, 1, 1)
grid.addWidget(QtGui.QLabel(u'年齡', parent=self), 1, 0, 1, 1)
self.sbAge = QtGui.QSpinBox(parent=self)
grid.addWidget(self.sbAge, 1, 1, 1, 1)
# 創建ButtonBox,用戶確定和取消
buttonBox = QtGui.QDialogButtonBox(parent=self)
buttonBox.setOrientation(QtCore.Qt.Horizontal) # 設置為水平方向
buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) # 確定和取消兩個按鈕
# 連接信號和槽
buttonBox.accepted.connect(self.accept) # 確定
buttonBox.rejected.connect(self.reject) # 取消
# 垂直布局,布局表格及按鈕
layout = QtGui.QVBoxLayout()
# 加入前面創建的表格布局
layout.addLayout(grid)
# 放一個間隔對象美化布局
spacerItem = QtGui.QSpacerItem(20, 48, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
layout.addItem(spacerItem)
# ButtonBox
layout.addWidget(buttonBox)
self.setLayout(layout)
def name(self):
return self.leName.text()
def age(self):
return self.sbAge.value()
編寫對話框調用代碼
調用對話框只要使用exec_方法即可,它會彈出對話框並根據用戶操作返回值,根據返回值判斷是【確定】還是【取消】。
dialog = Dialog(parent=self)
if dialog.exec_():
self.model.appendRow((
QtGui.QStandardItem(dialog.name()),
QtGui.QStandardItem(str(dialog.age())),
))
dialog.destroy()
完整代碼和截圖
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
# 創建table和model
table = QtGui.QTableView(parent=self)
self.model = QtGui.QStandardItemModel(parent=self)
self.model.setHorizontalHeaderLabels((u'姓名', u'年齡'))
table.setModel(self.model)
# 創建添加按鈕
button = QtGui.QPushButton(u'添加', parent=self)
# 添加信號槽
button.clicked.connect(self.add)
# 創建一個垂直布局,用於防止表格和按鈕
layout = QtGui.QVBoxLayout()
layout.addWidget(table)
layout.addWidget(button)
self.setLayout(layout)
def add(self):
dialog = Dialog(parent=self)
if dialog.exec_():
self.model.appendRow((
QtGui.QStandardItem(dialog.name()),
QtGui.QStandardItem(str(dialog.age())),
))
dialog.destroy()
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.resize(240, 200)
# 表格布局,用來布局QLabel和QLineEdit及QSpinBox
grid = QtGui.QGridLayout()
grid.addWidget(QtGui.QLabel(u'姓名', parent=self), 0, 0, 1, 1)
self.leName = QtGui.QLineEdit(parent=self)
grid.addWidget(self.leName, 0, 1, 1, 1)
grid.addWidget(QtGui.QLabel(u'年齡', parent=self), 1, 0, 1, 1)
self.sbAge = QtGui.QSpinBox(parent=self)
grid.addWidget(self.sbAge, 1, 1, 1, 1)
# 創建ButtonBox,用戶確定和取消
buttonBox = QtGui.QDialogButtonBox(parent=self)
buttonBox.setOrientation(QtCore.Qt.Horizontal) # 設置為水平方向
buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) # 確定和取消兩個按鈕
# 連接信號和槽
buttonBox.accepted.connect(self.accept) # 確定
buttonBox.rejected.connect(self.reject) # 取消
# 垂直布局,布局表格及按鈕
layout = QtGui.QVBoxLayout()
# 加入前面創建的表格布局
layout.addLayout(grid)
# 放一個間隔對象美化布局
spacerItem = QtGui.QSpacerItem(20, 48, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
layout.addItem(spacerItem)
# ButtonBox
layout.addWidget(buttonBox)
self.setLayout(layout)
def name(self):
return self.leName.text()
def age(self):
return self.sbAge.value()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())