一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

新手寫給新手的PyQt 5開發(fā)心得(上)

 goodwangLib 2020-02-22

0. 廢話

不是CS專業(yè),從來沒做過界面,入職就被分配了寫一個(gè)上位機(jī)的工作。幸虧讀master的時(shí)候被操練得盲目自信不怕困難,說干就干。邊學(xué)邊寫用Matlab寫了個(gè)很爛的上位機(jī),一旦啟動(dòng)阻塞電腦其他所有動(dòng)作…… 但是也算能用了,空閑了幾天,這時(shí)候有了新需求,那么就趁機(jī)學(xué)一下Qt吧。開始的時(shí)候,決定用PyQt 5 + Python 3,因?yàn)楦杏X比C++開發(fā)速度快。新需求完成后,就決定繼續(xù)把舊的功能移植過來了,最后……又做了一個(gè)很爛的上位機(jī)?!昂軤€”主要是性能問題,后面再細(xì)說。

請(qǐng)多指教。

1. 開發(fā)環(huán)境

1.1 Python 3

筆者也不知道Python 2用來開發(fā)會(huì)怎樣,選Python 3一是因?yàn)榭吹絇ython 2將停止維護(hù)還是什么的,二是用Vim的時(shí)候不少插件要Python 3支持。筆者是在Windows 7上開發(fā),安裝Python 3之后,就可以用pip安裝需要的包了,比如說最主要的PyQt 5。中途從Python 3.5換到3.6,因?yàn)楦铝薞im,結(jié)果是并無影響,至少是在這個(gè)項(xiàng)目涉及到的范圍內(nèi)沒有影響。

1.2 PyQt 5

不需要安裝Qt 5。一開始以為使用PyQt 5要先安裝Qt 5,后來在另外一臺(tái)電腦上搭環(huán)境的時(shí)候嘗試了一下,發(fā)現(xiàn)并不需要。開始用的時(shí)候是PyQt/Qt 5.9,寫這篇文章的時(shí)候是5.10了。PyQt 5相對(duì)于4,很多類都被移動(dòng)了,目前來說網(wǎng)上的PyQt 5的教程比4的少很多,雖然可以參考著來開發(fā),但是import的時(shí)候就要小心了,要去PyQt 5的網(wǎng)站或Qt官網(wǎng)查看一下。

1.3 Vim

既然提到了,就稍微說一下,并不是要引戰(zhàn)。筆者是學(xué)ROS的時(shí)候突然想起有這么個(gè)編輯器,懷著一顆好奇心就入坑了,花了一個(gè)星期入門——“入門”的意思是知道:wq等等。筆者腦子不好使,.h和.c(pp)分開看不行,界面和邏輯分開看也不行,也嘗試過學(xué)習(xí)Emacs之類,無奈再也沒有這么多時(shí)間了,所以一直用Vim。另外通過配置vimrc也可以直接在Vim中通過快捷鍵運(yùn)行Python代碼。

Vim用了快3年,配置上基本滿足當(dāng)前需求了,不能說是高端配置。先挖個(gè)坑,后面補(bǔ)一篇指南,比如語法檢查插件ALE我就搞了很久。

2. 開始

2.1 入門資料

還是先上點(diǎn)入門資料吧。

(1) First Programs in PyQt 5 - 建議先看這個(gè)。

(2) 《Matplotlib for Python Developers》的Chapter No. 6 - 第6章講的是怎么把matplotlib的坐標(biāo)嵌入到PyQt中去,但例子用的都是PyQt 4,需要讀者自行移植。其他matplotlib的內(nèi)容,筆者都是通過其官方文檔及Stack Overflow學(xué)習(xí)的。

2.2 main.py

也許主文件為其他命名也可以,但是筆者的主文件就是一鍋粥,以main概括就是了;里面是各個(gè)面板的實(shí)例化,以及最重要的——整個(gè)程序的實(shí)例化。這里要用到的是:

from PyQt5.QtWidgets import QApplication

PyQt 4的界面有很多種風(fēng)格可選,但是PyQt 5中刪減了。可通過setStyle函數(shù)來設(shè)置:

  1. if __name__ == '__main__':
  2. app = QApplication(sys.argv)
  3. app.setStyle('fusion')


2.3 界面

2.3.1 窗口:QMainWindow, QWidgets

在看過的教程里,似乎主窗口都要用到QMainWindow:

  1. from PyQt5.QtWidgets import QMainWindow
  2. class MainWindow(QMainWindow):
  3. def __init__(self):
  4. super().__init__()
  5. # Your code afterwards

用的時(shí)候并沒有深究為什么一定要用QMainWindow,后來其他部件全都是用QWidget。寫到這里,筆者去查了一下,有興趣的可以看一下——鏈接一,鏈接二,鏈接三。(“待審核”了,刪了,不好意思。)

QWidget用法和以上代碼差不多,就改個(gè)類名。主要用來做了一些從主窗口分離出去的小面板,例如嵌入了matplotlib的面板。

2.3.2 窗口屬性

筆者寫的軟件只定義了窗口初始大小和位置,以及圖標(biāo):

  1. from PyQt5.QtGui import QIcon
  2. from PyQt5.QtWidgets import QDesktopWidget
  3. from PyQt5.QtWidgets import QWidget
  4. class Panel(QWidget):
  5. def __init__(self):
  6. super().__init__()
  7. # Your code afterwards.
  8. def init_panel(self):
  9. screen = QDesktopWidget().availableGeometry()
  10. width = screen.width() * 0.5 # Change the scaler (0.5 here) at your will.
  11. height = screen.height() * 0.5 # Same as above.
  12. x = screen.width() * 0.01 # Same as above.
  13. y = screen.height() * 0.03 # Same as above.
  14. self.setGeometry(x, y, width, height)
  15. self.setWindowTitle('Panel')
  16. self.setWindowIcon(QIcon('icon.png'))

2.3.3 創(chuàng)建組件

先把用到的組件列一下:

  1. from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
  2. from matplotlib.figure import Figure
  3. from PyQt5.QtWidgets import QSizePolicy
  4. from PyQt5.QtWidgets import QCheckBox, \
  5. QComboBox, \
  6. QDial, \
  7. QGroupBox, \
  8. QLabel, \
  9. QLineEdit, \
  10. QProgressBar, \
  11. QPushBotton
  12. from PyQt5.QtWidgets import QStyleFactory

(1) 1至3行是用來嵌入matplotlib的,QSizePolicy的用法,筆者也是對(duì)著教程依樣畫葫蘆:

  1. class Canvas(FigureCanvasQTAgg):
  2. def __init__(self, parent):
  3. self.figure = Figure()
  4. FigureCanvasQTAgg.__init__(self, self.figure)
  5. self.axes = self.figure.add_subplot(1, 1, 1)
  6. self.setParent(parent)
  7. FigureCanvasQTAgg.setSizePolicy(self,
  8. QSizePolicy.Expanding,
  9. QSizePolicy.Expanding)
  10. FigureCanvasQTAgg.updateGeometry(self)

(2) 14行的QStyleFactory是與8行的QDial配合用的,筆者用QDial簡單封裝了一個(gè)羅盤,但是QDial的指針樣式在PyQt 5里默認(rèn)是一個(gè)圓點(diǎn),需要用QStyleFactory強(qiáng)制顯示為針狀(只列出部分代碼,其他屬性請(qǐng)自行設(shè)置):

  1. class Compass(QDial):
  2. def __init__(self, parent):
  3. super().__init__()
  4. self.setStyle(QStyleFactory.create('windows'))

(3) 第6行QCheckBox:很直接,用于勾選某些選項(xiàng)

(4) 第7行QComboBox:用于創(chuàng)建下拉菜單

  1. from PyQt5.QtWidgets import QComboBox
  2. from PyQt5.QtWidgets import QWidget
  3. class Panel(QWidget):
  4. def __init__(self):
  5. super().__init__()
  6. def create_widget(self):
  7. self.menu = QComboBox(self)
  8. def init_widget(self):
  9. self.menu.addItem('1', 1)
  10. self.menu.addItem('2', 2)
  11. self.menu.addItem('3', 3)

addItem的第一個(gè)參數(shù)為菜單顯示的字符串,第二個(gè)參數(shù)為item里對(duì)應(yīng)的數(shù)據(jù),可通過itemData來獲取,例如,在上述例子的前提下,以下語句為True:

  1. self.menu.itemData(0) == 1
  2. self.menu.itemData(1) == 2
  3. self.menu.itemData(2) == 3

(5) 第9行QGroupBox:就是在窗口里的一個(gè)小區(qū)域,視覺上將一些關(guān)系緊密組件放在一起,可以為這個(gè)group設(shè)置一個(gè)名字。QGroupBox在面板的QGridLayout上用addWidget從(0,0)開始擺放后,組內(nèi)要另外定義QGridLayout,從(0,0)開始擺放組件。其他細(xì)節(jié)請(qǐng)自行參考官方文檔。

(6) 第10、11行配合使用:QLabel即創(chuàng)建標(biāo)簽,通常用來標(biāo)記QLineEdit里顯示的數(shù)據(jù)是什么東西。QLineEdit中,用setText來設(shè)置要顯示的數(shù)據(jù),同時(shí)可用setReadOnly防止數(shù)據(jù)被誤改;如果是作為輸入框,用getText然后轉(zhuǎn)換數(shù)據(jù)類型。其他細(xì)節(jié)請(qǐng)自行參考官方文檔。

(7) 第12行QProgressBar:用來當(dāng)作電池顯示條。隨便鼓搗自己想要的功能,其中還用到一個(gè)網(wǎng)站(uiGradient)提供的漸變色配色方案。

(8) 第13行QPushButton:創(chuàng)建按鈕,可用setCheckable(True)來使得按鈕可以保持按下(Checked)的狀態(tài)。

2.3.4 組件布局

筆者只用了QGridLayout,因?yàn)楦杏X這個(gè)布局便于安排組件。雖然冥冥中感覺QVBoxLayout和QHBoxLayout能夠讓界面在resize的過程中使組件的位置保持得更好(如使用addStrecth等,若有誤懇請(qǐng)讀者賜教),但由于并不是產(chǎn)品級(jí)的軟件,所以什么方便快捷就用什么了。QGridLayout中的setRowStrecth和setColumnStretch只是用來對(duì)齊不同QBoxGroup中的組件,但效果也并不完美。

原理上,setRowStrecth和setColumnStretch可以用來調(diào)整不同組件所占空間的大小,但是筆者直接用addWidget來調(diào)整了:

  1. from PyQt5.QtWidgets import QGridLayout
  2. from PyQt5.QtWidgets import QLineEdit
  3. from PyQt5.QtWidgets import QWidget
  4. class Panel(QWidget):
  5. def __init__(self):
  6. super().__init__()
  7. self.layout = QGridLayout(self)
  8. # Your code afterwards
  9. def create_widgets(self):
  10. self.fat_box = QLineEdit(self)
  11. self.thin_box = QLineEdit(self)
  12. def add_widgets(self):
  13. self.layout.addWidget(self.fat_box, 0, 0, 3, 3)
  14. self.layout.addWidget(self.thin_box, 3, 0, 1, 1)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    中国一区二区三区不卡| 日韩人妻av中文字幕| 欧美三级精品在线观看| 99热九九在线中文字幕| 亚洲国产婷婷六月丁香| 日韩av欧美中文字幕| 欧美加勒比一区二区三区| 午夜精品福利视频观看| 开心久久综合激情五月天| 国产精品丝袜美腿一区二区| 日本免费一级黄色录像| 好吊色免费在线观看视频| 欧美国产极品一区二区| 精品人妻一区二区三区四在线| 中文字字幕在线中文乱码二区| 国产主播精品福利午夜二区| 精品熟女少妇av免费久久野外| 99久久精品国产麻豆| 欧美一区二区三区99| 欧美大胆美女a级视频| 亚洲欧洲一区二区中文字幕| 在线观看视频日韩精品 | 国产不卡的视频在线观看| 日本人妻免费一区二区三区| 久久精品久久精品中文字幕| 最新午夜福利视频偷拍| 日韩三极片在线免费播放| 日韩中文字幕人妻精品| 久久青青草原中文字幕| 国产亚洲欧美一区二区| 青青操成人免费在线视频| 国产精品日韩欧美一区二区| 久久热在线免费视频精品| 福利在线午夜绝顶三级| 日本少妇中文字幕不卡视频| 中国一区二区三区人妻 | 日韩欧美综合中文字幕| 欧美日韩有码一二三区| 视频一区二区 国产精品| 熟女白浆精品一区二区| 亚洲一区二区欧美在线|