#PYTHON3 #QT #PYSISE2 #TUTORIAL #QDIALOG #QMESSAGEBOX

PySide #14: 跳出原始的框框, Qdialog, QMessageBox

殺了一個視窗,還有千千萬萬個視窗

DekBan
Bucketing

--

Photo by Jessica Ruscello on Unsplash

許多應用程式都會有多個介面,除了鑲嵌在主畫面中,也常常看到獨立視窗的設定頁面、操作視窗等等。 另外,通知使用者或是與使用者互動,彈跳視窗也是不可少的優質功能,就讓我們來一探視窗處理的風貌吧。

💬 QMessageBox

許多時候都會用到彈跳視窗來達到提醒、警告、認證等等效果,這時候我們可以使用MessageBox來達成,QMessageBox提供了一些內建的按鈕選項,而我們也可以自己去新增喜歡的按鈕選項。

Inline MessageBox

在一些簡單的情況,例如通知、警告使用者等情況下,我們只需要快速的用MessageBox來確認使用者的選擇,這時候就可以使用Inline的方式,快速的宣告並顯示MessageBox。

ret = QMessageBox.information(
self._window, 'Inline Msg Box',
'This is inline message box, with return',
QMessageBox.Ok, QMessageBox.Cancel)
print('press: ' + str(ret))
Inline MessageBox Demo

Inline的Icon有很多種可以選擇,上述使用的是 QMessageBox.information()方法,而其他還有 question(), warning(), critical()這些選項可以使用。

Standard Button

官方有提供非常多的預設按鈕,並且有固定的回值做判斷,要注意不是每個按鈕都可以新增上去唷!因為回傳值固定式ButtonRole類型,並且有重複,使用時要注意啊~!

enum QMessageBox::StandardButton

Custom MessageBox

客製化是我們最愛的東西了,MessageBox客製化可以選擇Icon, 自訂Title, 訊息, detail訊息,還有最重要的按鈕,宣告方法如下:

@QtCore.Slot()
def custom_message(self):
msg_box = QMessageBox(self._window)
msg_box.setIcon(QMessageBox.Information)
msg_box.setWindowTitle('Custom Box')
msg_box.setText('Dekban Massage')
msg_box.setInformativeText('Welcome to tutorial! plz follow us')
msg_box.setDetailedText(
'Follow our Bucketing page, and learn more'
'about PySide2, Java, Design pattern!\n'
'Enjoy!')
msg_box.addButton('Follow', QMessageBox.AcceptRole)
msg_box.show()
Custom MessageBox Demo

QDialog

QMessageBox是不是限制太多啦?回傳值什麼的都不能自訂,真討厭!
那就要來點QDialog! 在主視窗外開啟一個子視窗的方法很多,同時我們也可以使用QWidget, QDialog, 甚至QMainWindow,那為什麼用QDialog呢?

QWidget通常是指視窗內的物件,例如QButton其實也是繼承於QWidget的,所以對於一個新開的視窗,QWidget應該是新視窗的CentralWidget而非視窗本身。
至於MainWindow應該很明顯吧,一山不容二虎,一個程式怎麼可以有兩個主話面呢?!因此子視窗或是工具視窗我通常會建議使用QDialog來實作,而且QDialog同MainWindow一樣含有視窗的各種功能跟屬性。

Create Dialog

基本上,Dialog就是一個視窗,所以可以用UiLoader來讀取一個dialog的ui檔,也可以直接用程式碼來撰寫UI介面。

這邊為方便,我就直接創建並複製一個相同的UI到QDialog的物件中了。

串接Dialog

要在MainWindow中呼叫新的Dialog物件非常簡單,就如同QApp呼叫QMainWindow的方法一樣,使用 exec_()這個函式。

from popup_windows.dialog import Dialog@QtCore.Slot()
def popup(self):
dialog = Dialog(self._window)
ret = dialog.window.exec_()
print(ret)
popup window demo

Return Value

Dialog通常會讓使用者操作完後會傳操作的結果,如果只是回傳數值,其實非常簡單,QDialog也可以想QMessage一般使用standard button,但我們更希望有多元的回傳值,因此我們可自定義按鈕來完成。

# in __init__()self._ret = 999

設定按鈕

def set_buttons(self):
"""Setup buttons"""
self._window.send_btn.setText('Send Msg')
self._window.exit_btn.setText('Exit')

ret22_button = QPushButton('Ret 22')
ret10_button = QPushButton('Ret 10')

self._window.dialogbtn_widget.setLayout(QVBoxLayout())
self._window.dialogbtn_widget.layout().addWidget(ret22_button)
self._window.dialogbtn_widget.layout().addWidget(ret10_button)

ret22_button.clicked.connect(self.ret22_clicked)
ret10_button.clicked.connect(self.ret10_clicked)
self._window.exit_btn.clicked.connect(self.exit)

@QtCore.Slot()
def ret22_clicked(self):
self._ret = 22
self._window.close()

@QtCore.Slot()
def ret10_clicked(self):
self._ret = 10
self._window.close()

最後串接QDialog的 finished()函式定設定Result就可以了!

self._window.finished.connect(self.finish_dialog)@QtCore.Slot(int)
def finish_dialog(self, code):
self._window.setResult(self._ret)
Dialog return value demo

Collect Data

最後了!我們有時候還想要搜集Dialog的資料內容,這個簡單,因為我們Dialog是個獨立物件,沒有繼承於QDialog所以相對單純,只要在關閉時,將資料存到一個變數就可以了!

@QtCore.Slot(int)
def finish_dialog(self, code):
self._window.setResult(self._ret)
self.data = {'title': self._window.title_line.text(),
'Message': self._window.msg_edit.toPlainText()}
Collect data from dialog

Source Code

完整代碼請看 :popup_window

結論

跳出視窗是常常使用到的東西,尤其是QMessageBox這種提醒視窗相信大家都不陌生,只要操作失誤就會出現XD,也可以搭配Exception來使用非常實用啊!至於QDialog還有非常多的把玩空間,就留給各位去創造了。

我是夜海中的宅男DekBan,我們下次見,see ya next night.

Next Step: PySide #15: 老闆菜單!這是啥? QMenu, QAction, ToolTip, StatusTip

--

--

DekBan
Bucketing

เด็กบ้าน | 🌃夜裡溜搭的宅男,漂泊於月色鋪成的海