你喜歡手動,自動,還是半自動?
Qt有個獨特的地方,有類似html+css一般的ui檔可以建構畫面,也能以底層的library去新增以及排版(C++ / Python皆有)。而寫程式有時候,只要喜歡、情況允許,有有何不可呢?
About GUI Rendering
首先,要來了解一下Qt當中的畫面,有一下兩種方式可以實作
- ui file: 使用QtCreator 或 QtDesigner經由GUI介面拖拉修改完成
- Qt LIB: 使用Qt 內建的各種元件類別做宣告、初始化、給予客製化參數
其中兩者各有好壞,會在下面一一介紹,但事實上在實際開發中,這兩種方式其實是並用的,差異在於比例分配多寡,這也因開發時程、內容而有所差異。
Using .ui file in PySide2
使用QtDesigner開發UI只需要拖曳,並且在右方的參數欄位修改即可完成,比起Qt Library煩雜的宣告,還要一行行的設定初始化,如果不是需要動態修改的內容,使用ui檔能省上許多時間。
使用ui file 在PySide2中有兩個方法:
- 使用QUILoader:將建立好的 .ui 以動態的方式runtime的import到程式中
- 使用 pyside2-uic: 將 .ui檔案編譯成python原始碼,直接import 並使用
結論先上!經過研究,在開發上如果不是特別需求,會建議使用QUILoader來做處理,原因請看…
pyside2-uic
這是一個官方提供的套件,非常方便,只要將你由QtDesigner做出的.ui檔用這個tool直行即可。
pyside2-uic mainwindow.ui > ui_mainwindow.py
使用上也非常方便, 就如同一般python module一樣 (這邊使用官方教學)
import sys
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtCore import QFile
from ui_mainwindow import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
But! 人生就是有這麼個但是,
pyside2-uic所編譯出來的.py檔案,有以下幾個缺點:
- coding style: 亂七八糟,完全沒按照 PEP8
- 直譯式翻譯: 這才是最大的問題,沒有for loop,也沒有資料結構,因此比較複雜的畫面編譯後將會動輒3、4千行不在話下。
考慮到後續的維護,以及程式的可讀性,最後選擇放棄使用這個方法。
QUILoader
顧名思義,UI Loader使用上也非常簡單,就是將外部的ui檔動態讀取並宣告到記憶體。
缺點也很明顯,會佔用較大的記憶體容量 …so what?
使用方法如下 (再次引用官方教學):
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QFile
if __name__ == "__main__":
app = QApplication(sys.argv)
ui_file_name = "mainwindow.ui"
ui_file = QFile(ui_file_name)
if not ui_file.open(QIODevice.ReadOnly):
print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString()))
sys.exit(-1)
loader = QUiLoader()
window = loader.load(ui_file)
ui_file.close()
if not window:
print(loader.errorString())
sys.exit(-1)
window.show()
sys.exit(app.exec_())
Using Qt Library
UI檔雖然開發上非常方便,也很快速,但有一好沒兩好,同樣一個物件,在QtDesigner 的attribute介面總是會少了幾個參數,要畫表格時,總是想用for-loop一次填滿所有的格子,這時候使用程式碼就更加方便了。
上一篇 [PyQt] PySide2 教程 #10: 專案!學以致用!的範例便是以Qt library所畫的,可以看到其中沒有用到任何ui檔案也能畫出畫面。
#!venv/bin/python3 import sys from PySide2 import QtWidgets from PySide2.QtWidgets import QLabel from PySide2.QtWidgets import QMainWindow from PySide2.QtWidgets import QPushButton class MainWindow(QMainWindow): def __init__(self, parent=None): """Main window, holding all user interface including. Args: parent: parent class of main window Returns: None Raises: None """ super(MainWindow, self).__init__(parent) self._width = 800 self._height = 600 self._title = QLabel('PySide2 is Great', self) self._exit_btn = QPushButton('Exit', self) self.setMinimumSize(self._width, self._height) if '__main__' == __name__: app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.show() ret = app.exec_() sys.exit(ret)
結論
可以說,動態且複雜的UI處理就交給後台的Qt Library,而靜態又不常修改的就交給ui 檔案去做設定。有沒有覺得很像web的開發呢?沒錯,就是相同的概念喔!
總結一下,我們開發時,ui 以及 Qt Lib 是共用的,兩者可以相互串接、互相修改,而uic這個工具,知道就可以了,如果真的想要靜態生成,那我會建議,全部用Qt Lib手刻吧!(我以前就是這個流派的愛好者呢…只是同事說code太長看的很痛苦…)