--- title: Python and PySide 筆記 lang: zh-tw description: Python and PySide tags: RD, Article, Python --- Python and PySide 筆記 === # 目錄 > #### 關於 Python > #### 關於 QtGui smart git ,bitbucket.org ## 關於 Python ------------------ ### Package 和 應用程式 當目錄裡面有 `__init__` 這個檔案的時候, python 會將這個目錄視為一個 `package` , 這時可以使用相對目錄取得 module , 如果目錄裡面有 `__main__` 這個檔案時, python 會將目錄視為一個應用程式, 可以使用 python folderName 的方式執行 ### 基礎中的基礎 #### 添加 api 將 Api 目錄複製到 \Python27\Lib\site-packages #### 添加系統環境路徑 需要載入外部模組時,要先在系統添加需要的路徑,例: ```python= import sys sys.path.append(r"T:\Script\DL_Tools\modules") sys.path.append(r'T:\DeadlineRepository7\api\python') import mDeadline ``` 這樣就可以載入該目錄下的模組 #### 路徑的使用方式 與Python,路徑名可以用三種方式表達: ```python= mypath = r"C:\folder\temp.shp" mypath = "C:\\folder\\temp.shp" mypath = "C:/folder/temp.shp" ``` 路徑前面加 r 表示 raw 格式,可以避免許多逃逸字元的問題(/t /n 之類的), 非常方便,但是注意路徑最後不能是\。 其他 \\ 和 / 都是用來規避逃逸字元的方法。 [說明文件 Raw String Notation](https://docs.python.org/3.3/library/re.html#raw-string-notation) #### 時間計算 datetime python 的時間計算透過 datetime 處理 如果你要指定一個時間,可以用: ```python= from datetime import datetime, timedelta mytime = datetime.strptime('2010-11-16 20:10:58', '%Y-%m-%d %H:%M:%S') ``` 或是 ```python= mytime = datetime(2010, 11, 16, 20, 10, 58) ``` > 但是須注意 datetime 不能為 float,例如 > datetime.strptime('20:10:32.25', '%H:%M:%S') > 這樣就會回傳錯誤。[color=red] 接下來如果你要做時間的增減,則須使用 timedelta 建立一個時間區段: ```python= mytime = datetime.strptime('2010-11-16 20:10:58', '%Y-%m-%d %H:%M:%S') addtime = timedelta(weeks=40, days=84, hours=23, minutes=10, seconds = 30) mytime + addtime >>>datetime.datetime(2011, 11, 16, 19, 21, 28) ``` 你也可以直接對兩個時間區段進行運算: ```python= # class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]]) # timedeltam 參數如果沒特別指定的話會依照上面的奇怪順序指定 timeA = timedelta(minutes=10,seconds=20) timeB = timedelta(minutes=8,seconds=23) timeC = timedelta(0,300000) timeA + timeB + timeC #在沒有特別指定的情下,timedelta 會回傳天數與秒數總和 >>>datetime.timedelta(3, 41923) #days 和 seconds 只會回傳指定的屬性 timedelta(3, 41923).seconds >>>41923 #total_seconds() 可以回傳秒數總和 timedelta(3, 41923).total_seconds() >>>301123.0 ``` [關於 timedelta 的詳細說明](https://docs.python.org/2/library/datetime.html#datetime.timedelta "") #### 從字串轉為時間的技巧 通常拿到時間資料的時候會是一組字串,例如: ```python= '2010-11-16 20:10:58' ``` 雖然可以直接用 datetime 處理,但是這樣之後進行運算時反而很麻煩, 這時透過 str.split(':') 這樣的方式將字串轉為陣列就有利於運算, ```python= '2010-11-16 20:10:58'.split(':') >>>['2010-11-16 20', '10', '58'] ``` 因為 split 每次只能判斷一個符號,所以要先將日期中的'-'和空格統一換成':' ```python= '2010-11-16 20:10:58'.replace('-',':').replace(' ',':').split(':') >>>['2010', '11', '16', '20', '10', '58'] ``` 或是使用更高段的使用re正則表達式 ```python= import re re.split('-|:| |','2010-11-16 20:10:58') >>>['2010', '11', '16', '20', '10', '58'] ``` [關於 Regular expression 的詳細說明](https://docs.python.org/2/library/re.html) --- ### Modules, Classes, and Objects --- #### Modules,很類似 Dictionaries, Dictionaries 是一個很簡單的 Python 用法 也就是: ```python= myFunction = {'name': "I am Sai"} print myFunction['name'] ``` 其實就是基本的變數設定, 只是當這些資料是從另外一個檔案 import 進來之後, 這樣的方式就會被稱做 Modules: ```python= # save this as myModule.py def myFunction(): print ('I am Sai') x=65535 ``` ```python= # import myModule.py import myModule myModule.myFunction() print (myModule.x) ``` 所以基本上的觀念都一樣,從 A 物件拿取 A 的 B 參數, 只是語法上的不同而已。 #### Class 跟 Module 很像 ~~WTF...I know the feel~~ :laughing: 其實就是一樣的物件導向觀念,你可以把 Module 當作一本你編輯的字典, 你可以透過 .(dot) 去取得字典裡的東西, 而 Class 也提供類似的功能,讓你可以把 function 和變數整理在一個 Class 裡, 之後一樣可以用 .(dot) 去取得 Class 裡的東西。 例如: ```python= class myClass(): name = 'Sai' age = 18 def myPrint(self): print ('I am Sai') myObj = myClass() print (myObj.name) myObj.myPrint() ``` 其實就跟編書一樣,你會有目錄、大綱、章節,甚至分冊等等, 觀念上都是在整理內容以便於引用而已。 參考資料: - [Python 中的 classmethod 和 staticmethod 有什么具体用途?](http://www.zhihu.com/question/20021164) - [Exercise 40: Modules, Classes, and Objects](http://learnpythonthehardway.org/book/ex40.html) ## 關於 QtGui ------------------ ### 介面階層規則 ![](http://i.imgur.com/ZXQeixL.png) PySide 要產生視窗最基本的必須先有一個 QWidget 物件, 在 PySide 中,有很多種物件可以產生視窗, 但是差異在於你產生的那個物件裡面可以放的東西, 例如 QMainWindow 就是屬於預設帶有上方選單、中間 、下方 status bar 的物件, ![](http://i.imgur.com/5jCPfkq.png) QDialog 則是帶有預設按鈕行為的物件。 而 QWidget 就是一個最底層的物件, 能透過加入各種 QtGui 組合出自己想要的介面, 也可以把多個 QMainWindow 加到 QWidget 裡。 另一個重要的是 Layout 物件 ![](http://i.imgur.com/XbzBYMs.png) 雖然沒有 Layout 物件, QWidget 也可以放些按鈕之類的元件, 但不使用 Layout 物件,就很難對多個 QWidget 做位置編排, 而且有些物件需要透過 Layout 來突破某些元件"只能放一個"的限制。 以 QWidget 作為基本介面的狀況,可以用 setLayout 指定一個主區域, >window.setLayout(Mainlayout) 或是定義 Layout 時直接附加指定 >self.myLayout = QVBoxLayout(self) 之後添加的 QWidget 就可以用 >Mainlayout.addWidget(myWidget) 而如果要增加 Layout 物件,則是使用 >MainLayout.addLayout(newLayout) 而最終,你做的所有東西,都是屬於"一個程式"的資源, 所以你必須,而且只能有一個 QApplication 物件, 也就是 QtGui.QApplication(sys.argv) 這一行的作用, QApplication 會掌握所有在這個介面內的資源,包括滑鼠游標、按鍵等等操作行為, 而當你在撰寫其他由 PyQT 撰寫的程式時(例如 The Foundry Nuke), 這一行就必須拿掉, 或是用 QtGui.QApplication.instance() 去拿軟體本身的 QApplication 因為軟體本身就已經是一個 QApplication 了。 ---- ### 屬性繼承: ------------------ 閱讀 PySide 的官方文件時會常看到像這樣的圖 ![](http://i.imgur.com/nqg2Jnp.png) 這張圖說明了各種物件的繼承關係, 簡單說就是右邊的物件會繼承左邊物件的屬性, 以 QPushButton 來說,他便繼承了 QAbatractButton 的屬性, 所以當我們只看 QPushButton 的時候會覺得它功能少的有點誇張, 也缺少按下按鈕之後要做的各種行為偵測。 ```python= def autoDefault () def initStyleOption (option) def isDefault () def isFlat () def menu () def setAutoDefault (arg__1) def setDefault (arg__1) def setFlat (arg__1) def setMenu (menu) ``` 但實際上他繼承了 QAbatractButton 的屬性之後就追加了: ```python= def autoExclusive () def autoRepeat () def autoRepeatDelay () def autoRepeatInterval () def group () def icon () def iconSize () def isCheckable () def isChecked () def isDown () def setAutoExclusive (arg__1) def setAutoRepeat (arg__1) def setAutoRepeatDelay (arg__1) def setAutoRepeatInterval (arg__1) def setCheckable (arg__1) def setDown (arg__1) def setIcon (icon) def setShortcut (key) def setText (text) def shortcut () def text () ``` 以及重要的 Signals 和 Slots ```python= >Slots def animateClick ([msec=100]) def click () def setChecked (arg__1) def setIconSize (size) def toggle () >Signals def clicked ([checked=false]) def pressed () def released () def toggled (checked) ``` ---- #### Signals and Slots ------------------ Signals 和 Slots 是 PySide 較複雜但也是關鍵的部分, 而簡單來看其實跟一般我們認知的按鈕行為一樣, 也就是當按下button(發出 Signal)之後要做什麼(Slot), 然後中間用 connect 做連結, 所以最基本的 Signals/Slots 組就會是: ```python= def myfunction(): print "button clicked!" button = QtGui.QPushButton("Call myfunction") button.clicked.connect(myfunction) ``` 傳統較複雜的寫法, 則是用一個 QObject 的 connect 去把 Signals 和 Slots 做連結: >def connect (sender, signal, member[, type=Qt.AutoConnection]) ```python= def myfunction(): print "button clicked!" button = QtGui.QPushButton("Call myfunction") QtCore.QObject.connect(button, QtCore.SIGNAL ('clicked()'), myfunction) ``` #### 什麼是 lambda ? ------------------ lambda 稱作匿名函式(anonymous function), 聽起來很厲害,但其實只是懶惰想少打幾個字的用法 :stuck_out_tongue_closed_eyes: 一般定義 function 的方式: ```python= def myFunction(name): print (name + ' say: Hello World') myFunction('sai') ``` 使用 lambda 的方式: > lambda param1, param2, ... : expression ```python= myFunction = lambda name:(name + ' say: Hello World') print (myFunction('sai')) ``` lambda 可以將後面的 expression 轉變成一個匿名函式,寫成這樣: ```python= def myFunction(name): print (name + ' say: Hello World') whoSay = lambda:(myFunction('sai')) whoSay() ``` 因此就有了一個特殊用法, 是當我們使用 Signal/Slot 時,slot 裡只能放 callable 物件, 簡單說就是一個不能帶有參數的 function, 例如: ```python= def myfunction(): print 'Hello' button = QtGui.QPushButton("Call myfunction") button.clicked.connect(myfunction) ``` 不能是這樣: ```python= def myfunction(any): print any button = QtGui.QPushButton("Call myfunction") button.clicked.connect(myfunction('Hello')) ``` 這時就可以用 lambda 的特性將 function 包起來, ```python= def myfunction(any): print any fakeFunc = lambda: myfunction('Hello') button = QtGui.QPushButton("Call myfunction") button.clicked.connect(fakeFunc) ``` 簡化後就可以變成這樣 ```python= def myfunction(any): print any button = QtGui.QPushButton("Call myfunction") button.clicked.connect(lambda: myfunction('Hello')) ``` #### 相關連結: - [關於 QApplication 的詳細說明](http://openhome.cc/Gossip/Qt4Gossip/FirstQt.html) - [PySide 1.1.0 Reference](https://deptinfo-ensip.univ-poitiers.fr/ENS/pyside-docs/index.html) ----------------------------------------------------------- ## 範例: ------------------ ##### 偵測目前 QApplication 軟體名稱 ```python= import os from os.path import basename from PySide import QtGui thisApp = QtGui.QApplication.instance() appname = basename(thisApp.applicationFilePath()) fileName, fileExtension = os.path.splitext(appname) print fileName #以下是 maxscript 的寫法供參考 pytext = "" pytext += "import os \n" pytext += "from os.path import basename \n" pytext += "from PySide import QtGui \n" pytext += "thisApp = QtGui.QApplication.instance() \n" pytext += "appname = basename(thisApp.applicationFilePath()) \n" pytext += "fileName, fileExtension = os.path.splitext(appname) \n" pytext += "print fileName \n" python.Execute pytext ``` 理論上應該要使用 QApplication.applicationName(), 但是這樣回傳是空的東西,所以只能透過 app 的路徑名稱取得。 ##### 產生一個視窗和按鈕,按鈕按下出現詢問是否要關閉視窗 ```python= # -*- coding: utf-8 -*- import sys import PySide from PySide import QtGui from PySide import QtCore ## QApplication = QtGui.QApplication QWidget = QtGui.QWidget QMessageBox = QtGui.QMessageBox class sampleWindow(QWidget): """ My First Windows """ def __init__(self): QWidget.__init__(self) self.setWindowTitle("SampleWindow") myButton_01 = QtGui.QPushButton('Quit', self) myButton_01.setToolTip("Close Window") myButton_01.clicked.connect(self.quitApp) # myChecker_01 = QtGui.QCheckBox('Checker', self ) def quitApp(self): """ Function for quit app""" userInfo = QMessageBox.question(self, "Confirmation", "Quit?", QMessageBox.Yes|QMessageBox.No) if userInfo == QMessageBox.Yes: self.close() if userInfo == QMessageBox.No: pass if __name__ == '__main__': myApp = QApplication("") myWindow = sampleWindow() myWindow.show() myApp.exec_() sys.exit('Goodbye') ``` ##### 基本 python 對檔案的操作語法 ```python= import sys file = open(sys.argv[1], 'r') content = file.read() print content file.close() ``` ##### 將界面用 QWdiget 打包,並塞入 QMainWindows ```python= # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'D:\1_Git\MyPython\GXUploader_UI.ui' # # Created: Tue Oct 31 16:48:24 2017 # by: pyside-uic 0.2.15 running on PySide 1.2.4 # # WARNING! All changes made in this file will be lost! from PySide import QtCore, QtGui from PySide.QtCore import * from PySide.QtGui import * import sys class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(380, 450) self.verticalLayoutWidget = QtGui.QWidget(Dialog) self.verticalLayoutWidget.setGeometry(QtCore.QRect(0, 160, 151, 281)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.QV_AssetDefiend = QtGui.QVBoxLayout(self.verticalLayoutWidget) self.QV_AssetDefiend.setContentsMargins(0, 0, 0, 0) self.QV_AssetDefiend.setObjectName("QV_AssetDefiend") self.label = QtGui.QLabel(self.verticalLayoutWidget) self.label.setObjectName("label") self.QV_AssetDefiend.addWidget(self.label) self.treeView = QtGui.QTreeView(self.verticalLayoutWidget) self.treeView.setObjectName("treeView") self.QV_AssetDefiend.addWidget(self.treeView) self.verticalLayoutWidget_2 = QtGui.QWidget(Dialog) self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(0, 0, 151, 55)) self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2") self.QV_Account = QtGui.QVBoxLayout(self.verticalLayoutWidget_2) self.QV_Account.setContentsMargins(0, 0, 0, 0) self.QV_Account.setObjectName("QV_Account") self.button_login = QtGui.QPushButton(self.verticalLayoutWidget_2) self.button_login.setObjectName("button_login") self.QV_Account.addWidget(self.button_login) self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.lineEdit_2 = QtGui.QLineEdit(self.verticalLayoutWidget_2) self.lineEdit_2.setObjectName("lineEdit_2") self.horizontalLayout.addWidget(self.lineEdit_2) self.lineEdit = QtGui.QLineEdit(self.verticalLayoutWidget_2) self.lineEdit.setObjectName("lineEdit") self.horizontalLayout.addWidget(self.lineEdit) self.QV_Account.addLayout(self.horizontalLayout) self.verticalLayoutWidget_3 = QtGui.QWidget(Dialog) self.verticalLayoutWidget_3.setGeometry(QtCore.QRect(0, 60, 151, 92)) self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3") self.QV_ServerSetting = QtGui.QVBoxLayout(self.verticalLayoutWidget_3) self.QV_ServerSetting.setContentsMargins(0, 0, 0, 0) self.QV_ServerSetting.setObjectName("QV_ServerSetting") self.label_serversetting = QtGui.QLabel(self.verticalLayoutWidget_3) self.label_serversetting.setObjectName("label_serversetting") self.QV_ServerSetting.addWidget(self.label_serversetting) self.lineEdit_4 = QtGui.QLineEdit(self.verticalLayoutWidget_3) self.lineEdit_4.setObjectName("lineEdit_4") self.QV_ServerSetting.addWidget(self.lineEdit_4) self.lineEdit_3 = QtGui.QLineEdit(self.verticalLayoutWidget_3) self.lineEdit_3.setObjectName("lineEdit_3") self.QV_ServerSetting.addWidget(self.lineEdit_3) self.lineEdit_5 = QtGui.QLineEdit(self.verticalLayoutWidget_3) self.lineEdit_5.setObjectName("lineEdit_5") self.QV_ServerSetting.addWidget(self.lineEdit_5) self.verticalLayoutWidget_4 = QtGui.QWidget(Dialog) self.verticalLayoutWidget_4.setGeometry(QtCore.QRect(160, 0, 211, 192)) self.verticalLayoutWidget_4.setObjectName("verticalLayoutWidget_4") self.QV_UploadSetting = QtGui.QVBoxLayout(self.verticalLayoutWidget_4) self.QV_UploadSetting.setContentsMargins(0, 0, 0, 0) self.QV_UploadSetting.setObjectName("QV_UploadSetting") self.horizontalLayout_2 = QtGui.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.lineEdit_6 = QtGui.QLineEdit(self.verticalLayoutWidget_4) self.lineEdit_6.setObjectName("lineEdit_6") self.horizontalLayout_2.addWidget(self.lineEdit_6) self.pushButton = QtGui.QPushButton(self.verticalLayoutWidget_4) self.pushButton.setObjectName("pushButton") self.horizontalLayout_2.addWidget(self.pushButton) self.QV_UploadSetting.addLayout(self.horizontalLayout_2) self.label_4 = QtGui.QLabel(self.verticalLayoutWidget_4) self.label_4.setObjectName("label_4") self.QV_UploadSetting.addWidget(self.label_4) self.comboBox_3 = QtGui.QComboBox(self.verticalLayoutWidget_4) self.comboBox_3.setObjectName("comboBox_3") self.QV_UploadSetting.addWidget(self.comboBox_3) self.label_2 = QtGui.QLabel(self.verticalLayoutWidget_4) self.label_2.setObjectName("label_2") self.QV_UploadSetting.addWidget(self.label_2) self.comboBox = QtGui.QComboBox(self.verticalLayoutWidget_4) self.comboBox.setObjectName("comboBox") self.QV_UploadSetting.addWidget(self.comboBox) self.label_3 = QtGui.QLabel(self.verticalLayoutWidget_4) self.label_3.setObjectName("label_3") self.QV_UploadSetting.addWidget(self.label_3) self.comboBox_2 = QtGui.QComboBox(self.verticalLayoutWidget_4) self.comboBox_2.setObjectName("comboBox_2") self.QV_UploadSetting.addWidget(self.comboBox_2) self.pushButton_2 = QtGui.QPushButton(self.verticalLayoutWidget_4) self.pushButton_2.setObjectName("pushButton_2") self.QV_UploadSetting.addWidget(self.pushButton_2) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "GalaxyMassiveUploader", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("Dialog", "Categries:", None, QtGui.QApplication.UnicodeUTF8)) self.button_login.setText(QtGui.QApplication.translate("Dialog", "User Login", None, QtGui.QApplication.UnicodeUTF8)) self.label_serversetting.setText(QtGui.QApplication.translate("Dialog", "Server Setting", None, QtGui.QApplication.UnicodeUTF8)) self.pushButton.setText(QtGui.QApplication.translate("Dialog", "Files Path", None, QtGui.QApplication.UnicodeUTF8)) self.label_4.setText(QtGui.QApplication.translate("Dialog", "Asset Type", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("Dialog", "Upload by DCC:", None, QtGui.QApplication.UnicodeUTF8)) self.label_3.setText(QtGui.QApplication.translate("Dialog", "RenderEngine", None, QtGui.QApplication.UnicodeUTF8)) self.pushButton_2.setText(QtGui.QApplication.translate("Dialog", "Start Upload", None, QtGui.QApplication.UnicodeUTF8)) class MyWidget(QtGui.QWidget,Ui_Dialog): def __init__(self, parent=None): super(MyWidget,self).__init__(parent) self.setupUi(self) class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None): super(MainWindow,self).__init__(parent) self.setCentralWidget(MyWidget()) self.myQMenuBar01 = QtGui.QMenuBar() newMenu = self.myQMenuBar01.addMenu('File') newMenu.addAction('Open') newMenu.addAction('Close') newMenu = self.myQMenuBar01.addMenu('Edit') newMenu.addAction('Copy') newMenu.addAction('Past') self.setMenuBar(self.myQMenuBar01) self.setFixedSize(380, 460) if __name__ == '__main__': Program = QtGui.QApplication(sys.argv) Window=MainWindow() Window.show() Program.exec_() ``` ##### 產生一個帶有多重 QMainWindow 的 QWidget ```python= # -*- coding: utf-8 -*- import sys from PySide import QtCore from PySide import QtGui # class myWindow(QtGui.QWidget): class myWindow(QtGui.QWidget): def __init__(self): # initial the basic QWidget QtGui.QWidget.__init__(self) self.setWindowTitle("My Main Widget") self.resize(600,800) # defined MainLayout self.mainLayout = QtGui.QVBoxLayout() # defined QMainWindow Object self.myQMainWindow01 = QtGui.QMainWindow() # defined QMenubar for myQMainWindow01 self.myQMenuBar01 = QtGui.QMenuBar(self.myQMainWindow01) newMenu = self.myQMenuBar01.addMenu('File') newMenu.addAction('Open') newMenu.addAction('Close') newMenu = self.myQMenuBar01.addMenu('Edit') newMenu.addAction('Copy') newMenu.addAction('Past') # Add myQMenuBar01 to myQMainWindow01 self.myQMainWindow01.setMenuBar(self.myQMenuBar01) # ---------------------------------------------------------------------- self.myQMainWindow02 = QtGui.QMainWindow() self.myQMenuBar02 = QtGui.QMenuBar(self.myQMainWindow02) newMenu = self.myQMenuBar02.addMenu('File') newMenu.addAction('Open') newMenu.addAction('Close') newMenu = self.myQMenuBar02.addMenu('Edit') newMenu.addAction('Copy') newMenu.addAction('Past') self.myQMainWindow02.setMenuBar(self.myQMenuBar02) # ---------------------------------------------------------------------- # Add myQMainWindow01 to mainLayout self.mainLayout.addWidget(self.myQMainWindow01) self.mainLayout.addWidget(self.myQMainWindow02) # set basic QWidget Layout,for insert multi Widget self.setLayout(self.mainLayout) # Show window object if __name__ == '__main__': Program = QtGui.QApplication(sys.argv) Window=myWindow() Window.show() Program.exec_() ``` ##### 產生一個帶有兩個 Dockwidget 的視窗 ```python= # -*- coding: utf-8 -*- import sys from PySide import QtCore, QtGui class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") Form.resize(562, 581) self.dockWidget = QtGui.QDockWidget(Form) self.dockWidget.setGeometry(QtCore.QRect(10, 60, 281, 191)) self.dockWidget.setFloating(True) self.dockWidget.setFeatures(QtGui.QDockWidget.AllDockWidgetFeatures) self.dockWidget.setObjectName("dockWidget") self.dockWidgetContents = QtGui.QWidget() self.dockWidgetContents.setObjectName("dockWidgetContents") self.dockWidget.setWidget(self.dockWidgetContents) self.dockWidget_2 = QtGui.QDockWidget(Form) self.dockWidget_2.setGeometry(QtCore.QRect(90, 350, 331, 181)) self.dockWidget_2.setFloating(True) self.dockWidget_2.setObjectName("dockWidget_2") self.dockWidgetContents_2 = QtGui.QWidget() self.dockWidgetContents_2.setObjectName("dockWidgetContents_2") self.dockWidget_2.setWidget(self.dockWidgetContents_2) self.retranslateUi(Form) QtCore.QMetaObject.connectSlotsByName(Form) def retranslateUi(self, Form): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) self.dockWidget.setWindowTitle(QtGui.QApplication.translate("Form", "DockWidget01", None, QtGui.QApplication.UnicodeUTF8)) self.dockWidget_2.setWindowTitle(QtGui.QApplication.translate("Form", "DockWidget02", None, QtGui.QApplication.UnicodeUTF8)) " \ 重點在這邊,一般我們定義視窗時會用 \ class myWindow(QtGui.QWidget):或是class myWindow(QtGui.QMainWindow): \ 這些是基本的視窗物件, \ 但這邊為了某些原因使用了 python 原生的 object class 來盡可能的保有可變性, \ 而 object class 並沒有辦法產生視窗, \ 因此另外定義一個 QMainWindow 的 class,並讓它繼承上面 Ui_Form 定義的物件內容 \ 這樣才可以讓最後的 Window=MainWindow(),Window.show() 產生作用 \ 根據原本 QtDesigner 的用法,下面這部分會寫在另一個檔案,並 import 上半段的檔案 \ " class MainWindow(QtGui.QMainWindow,Ui_Form): def __init__(self, parent=None): super(MainWindow,self).__init__(parent) self.setupUi(self) self.myQMenuBar01 = QtGui.QMenuBar() newMenu = self.myQMenuBar01.addMenu('File') newMenu.addAction('Open') newMenu.addAction('Close') newMenu = self.myQMenuBar01.addMenu('Edit') newMenu.addAction('Copy') newMenu.addAction('Past') self.setMenuBar(self.myQMenuBar01) if __name__ == '__main__': Program = QtGui.QApplication(sys.argv) Window=MainWindow() Window.show() Program.exec_() ``` ##### 產生一個主 layout 和一個附加 Layout ```python= # -*- coding: utf-8 -*- import sys from PySide import QtCore from PySide import QtGui class myMainWidget(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.setWindowTitle('Multi Layout Sample') self.resize(300,200) # main layout self.myMainLayout01 = QtGui.QVBoxLayout() self.myButton01 = QtGui.QPushButton('Button001') self.myButton02 = QtGui.QPushButton('Button002') self.myButton03 = QtGui.QPushButton('Button003') self.myButton04 = QtGui.QPushButton('Button004') self.myButton05 = QtGui.QPushButton('Button005') self.myButton06 = QtGui.QPushButton('Button006') self.myButton07 = QtGui.QPushButton('Button007') self.myMainLayout01.addWidget(self.myButton01) self.myMainLayout01.addWidget(self.myButton02) self.myMainLayout01.addWidget(self.myButton03) self.myMainLayout01.addWidget(self.myButton04) self.myMainLayout02 = QtGui.QHBoxLayout() self.myMainLayout02.addWidget(self.myButton05) self.myMainLayout02.addWidget(self.myButton06) self.myMainLayout02.addWidget(self.myButton07) self.myMainLayout01.addLayout(self.myMainLayout02) self.setLayout(self.myMainLayout01) if __name__ == '__main__': myProgram = QtGui.QApplication('') myApp = myMainWidget() myApp.show() myProgram.exec_() ``` ##### 用 lambda 突破 Signal 不能輸出自訂參數的限制 ```python= from PySide.QtCore import * from PySide.QtGui import * class MyForm(QMainWindow): def __init__(self, parent=None): super(MyForm, self).__init__(parent) button1 = QPushButton('Button 1') button2 = QPushButton('Button 2') button1.clicked.connect(lambda: on_button(button1,1)) button2.clicked.connect(lambda: on_button(button2,2)) layout = QHBoxLayout() layout.addWidget(button1) layout.addWidget(button2) main_frame = QWidget() main_frame.setLayout(layout) self.setCentralWidget(main_frame) def on_button(self, n): print (self.text()) print('Button {0} clicked'.format(n)) if __name__ == "__main__": import sys app = QApplication(sys.argv) form = MyForm() form.show() app.exec_() ``` [參考資料: Passing extra arguments to PyQt slots ](http://eli.thegreenplace.net/2011/04/25/passing-extra-arguments-to-pyqt-slot/) ##### 各種送出按鈕訊息的方式 ```python= # -*- coding: utf-8 -*- import sys from PySide import QtCore from PySide import QtGui class myMainWidget(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.setWindowTitle('Button Signal and Trigger') self.resize(600,400) # Layout Area self.myMainLayout = QtGui.QVBoxLayout(self) self.myMainLayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.myMainLayout) self.subLayout01 = QtGui.QHBoxLayout() self.subLayout02 = QtGui.QHBoxLayout() self.subLayout03 = QtGui.QHBoxLayout() # button Area # Traditional syntax: SIGNAL () and SLOT() self.sendSignal_01 = QtGui.QPushButton('Say Hellow') QtCore.QObject.connect(self.sendSignal_01, QtCore.SIGNAL ('clicked()'), ButtonPressed_A) # New syntax: Signal() and Slot() self.sendSignal_02 = QtGui.QPushButton('Say Yes') self.sendSignal_02.clicked.connect(ButtonPressed_B) # New syntax: Signal() and Slot() self.sendSignal_03 = QtGui.QPushButton('Say Byebye') self.sendSignal_03.clicked.connect(lambda: ButtonPressed_C(self.sendSignal_03)) # Def in self class can use sander self.sendSignal_04 = QtGui.QPushButton('AAAAAA') self.sendSignal_04.setObjectName('GetAAA') self.sendSignal_04.clicked.connect(self.selfButtonPressed) self.sendSignal_05 = QtGui.QPushButton('BBBBBB') self.sendSignal_05.setObjectName('GetBBB') self.sendSignal_05.clicked.connect(self.selfButtonPressed) self.sendSignal_06 = QtGui.QPushButton('CCCCCC') self.sendSignal_06.setObjectName('GetCCC') self.sendSignal_06.clicked.connect(self.selfButtonPressed) # send message out self.sendSignal_07 = QtGui.QPushButton('Say Anything') def emptyfunction (): ButtonPressed_D('WOWOWOWOW') self.sendSignal_07.clicked.connect(emptyfunction) # show how lambda work self.sendSignal_08 = QtGui.QPushButton('Say Anything') def lambdafunction(any): print any anyfunction = lambda :lambdafunction((u'成功啦!!!!')) self.sendSignal_08.clicked.connect(anyfunction) # use lambda to expose class attribute self.sendSignal_09 = QtGui.QPushButton('Say Anything') self.sendSignal_09.clicked.connect(lambda: ButtonPressed_D(u'超爽 der~')) # Add Widgets To layout myMainLayout = self.myMainLayout myMainLayout.addLayout(self.subLayout01) myMainLayout.addLayout(self.subLayout02) myMainLayout.addLayout(self.subLayout03) # -- self.subLayout01.addWidget(self.sendSignal_01) self.subLayout01.addWidget(self.sendSignal_02) self.subLayout01.addWidget(self.sendSignal_03) #-- self.subLayout02.addWidget(self.sendSignal_04) self.subLayout02.addWidget(self.sendSignal_05) self.subLayout02.addWidget(self.sendSignal_06) #-- self.subLayout03.addWidget(self.sendSignal_07) self.subLayout03.addWidget(self.sendSignal_08) self.subLayout03.addWidget(self.sendSignal_09) def selfButtonPressed(self): sender = self.sender() print (sender.objectName()) def ButtonPressed_A(): print ('Say Hellow') def ButtonPressed_B(): print ('Say Yes') def ButtonPressed_C(button): print (button.text()) def ButtonPressed_D(anything): print (anything) if __name__ == '__main__': myProgram = QtGui.QApplication('') myApp = myMainWidget() myApp.show() myProgram.exec_() ``` ##### 在 python console 內列印中文 ```python= #-*- coding: utf-8 -*- for i in range(10): print u'HackMD 超帥的' print 'HackMD 超帥的V2'.decode('utf8') ``` ## 關於 Eclipse: 添加 ------------------ ## 待了解的東西 ------------------ #### 不定引數 ```python= def a123( *args, **kargs): count = len(args) if 'a' in kargs.keys(): pass b = {'a':123,'b':456} a123( "123",456, b, c= 123, d =456) b['a'] = 999 print b.keys() print b['a'] ``` ###### tags: `python` `PySide`