python GUI庫圖形介面開發之PyQt5美化窗體與控制元件(異形窗體)例項
在預設情況下,我們使用PyQt5創建出來的視窗和部件都是預設的樣式,雖然談不上很醜,但是也毫無美感可言。其實,在PyQt5中,我們可以有較高的自由度來自定義視窗和各種小部件的樣式,通過自定義這些樣式,以達到美化圖形介面的目的。
本篇文章中,我們就通過一個實際的例子,使用QSS和PyQt5的配置屬性,實現圖形使用者介面的美化工作。
首先上效果圖:
一、對介面進行佈局和元件的佈置
在影象介面程式設計中,一個好的佈局有助於全域性把控介面的形態,而在PyQt5中,有多種佈局的方式供我們選擇,比較常用的佈局有以下幾種:
表單佈局:QFormLayout
網格佈局:QGridLayout
水平排列布局:QHBoxLayout
垂直排列布局:QVBoxLayout
每種佈局都有自己對佈局內小部件的控制方式和特點,在此我們選擇網格佈局作為本次圖形介面佈局的方案。
在網格佈局內,使用兩個QWidget()部件分別作為左側選單模組的部件和右側內容模組的部件。所以這個圖形介面的最基本結構程式碼如下所示:
# coding:utf-8 from PyQt5 import QtCore,QtGui,QtWidgets import sys import qtawesome class MainUi(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.init_ui() def init_ui(self): self.setFixedSize(960,700) self.main_widget = QtWidgets.QWidget() # 建立視窗主部件 self.main_layout = QtWidgets.QGridLayout() # 建立主部件的網格佈局 self.main_widget.setLayout(self.main_layout) # 設定視窗主部件佈局為網格佈局 self.left_widget = QtWidgets.QWidget() # 建立左側部件 self.left_widget.setObjectName('left_widget') self.left_layout = QtWidgets.QGridLayout() # 建立左側部件的網格佈局層 self.left_widget.setLayout(self.left_layout) # 設定左側部件佈局為網格 self.right_widget = QtWidgets.QWidget() # 建立右側部件 self.right_widget.setObjectName('right_widget') self.right_layout = QtWidgets.QGridLayout() self.right_widget.setLayout(self.right_layout) # 設定右側部件佈局為網格 self.main_layout.addWidget(self.left_widget,12,2) # 左側部件在第0行第0列,佔8行3列 self.main_layout.addWidget(self.right_widget,2,10) # 右側部件在第0行第3列,佔8行9列 self.setCentralWidget(self.main_widget) # 設定視窗主部件 def main(): app = QtWidgets.QApplication(sys.argv) gui = MainUi() gui.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
執行程式碼,呈現出來的圖形介面如下圖所示:
空空蕩蕩,下面我們就開始往裡面填充小部件。
左側選單欄
在左側選單模組中,繼續使用網格對部件進行佈局。在左側選單的佈局中新增按鈕部件QPushButton()左側選單的按鈕、選單列提示和整個視窗的最小化和關閉按鈕。
在MainUi()類的init_ui()方法中,使用如下程式碼例項化建立按鈕:
self.left_close = QtWidgets.QPushButton("") # 關閉按鈕 self.left_visit = QtWidgets.QPushButton("") # 空白按鈕 self.left_mini = QtWidgets.QPushButton("") # 最小化按鈕 self.left_label_1 = QtWidgets.QPushButton("每日推薦") self.left_label_1.setObjectName('left_label') self.left_label_2 = QtWidgets.QPushButton("我的音樂") self.left_label_2.setObjectName('left_label') self.left_label_3 = QtWidgets.QPushButton("聯絡與幫助") self.left_label_3.setObjectName('left_label') self.left_button_1 = QtWidgets.QPushButton(qtawesome.icon('fa.music',color='white'),"華語流行") self.left_button_1.setObjectName('left_button') self.left_button_2 = QtWidgets.QPushButton(qtawesome.icon('fa.sellsy',"線上FM") self.left_button_2.setObjectName('left_button') self.left_button_3 = QtWidgets.QPushButton(qtawesome.icon('fa.film',"熱門MV") self.left_button_3.setObjectName('left_button') self.left_button_4 = QtWidgets.QPushButton(qtawesome.icon('fa.home',"本地音樂") self.left_button_4.setObjectName('left_button') self.left_button_5 = QtWidgets.QPushButton(qtawesome.icon('fa.download',"下載管理") self.left_button_5.setObjectName('left_button') self.left_button_6 = QtWidgets.QPushButton(qtawesome.icon('fa.heart',"我的收藏") self.left_button_6.setObjectName('left_button') self.left_button_7 = QtWidgets.QPushButton(qtawesome.icon('fa.comment',"反饋建議") self.left_button_7.setObjectName('left_button') self.left_button_8 = QtWidgets.QPushButton(qtawesome.icon('fa.star',"關注我們") self.left_button_8.setObjectName('left_button') self.left_button_9 = QtWidgets.QPushButton(qtawesome.icon('fa.question',"遇到問題") self.left_button_9.setObjectName('left_button') self.left_xxx = QtWidgets.QPushButton(" ")
在這裡,我們使用qtawesome這個第三方庫來實現按鈕中的Font Awesome字型圖示的顯示。然後將建立的按鈕新增到左側部件的網格佈局層中:
self.left_layout.addWidget(self.left_mini,1,1) self.left_layout.addWidget(self.left_close,1) self.left_layout.addWidget(self.left_visit,1) self.left_layout.addWidget(self.left_label_1,3) self.left_layout.addWidget(self.left_button_1,3) self.left_layout.addWidget(self.left_button_2,3,3) self.left_layout.addWidget(self.left_button_3,4,3) self.left_layout.addWidget(self.left_label_2,5,3) self.left_layout.addWidget(self.left_button_4,6,3) self.left_layout.addWidget(self.left_button_5,7,3) self.left_layout.addWidget(self.left_button_6,8,3) self.left_layout.addWidget(self.left_label_3,9,3) self.left_layout.addWidget(self.left_button_7,10,3) self.left_layout.addWidget(self.left_button_8,11,3) self.left_layout.addWidget(self.left_button_9,3)
繼續執行程式程式碼,呈現出來的圖形介面如下圖所示:
雖然很醜,但是基本的模型是顯示出來了,這裡先不作美化,先把完整的結構搭建出來。下面開始右側部件的搭建。
右側內容模組
在右側內容模組中,有以下幾個主要內容模組:
搜尋模組
推薦音樂模組
音樂列表模組
音樂歌單模組
音樂播放進度模組
音樂播放控制模組
在搜尋模組中,有一個文字和一個搜尋框,我們通過QLable()部件和QLineEdit()部件來實現,這兩個部件同時包裹在一個網格佈局的QWidget()部件,分列第一列和第二列,其程式碼如下所示:
self.right_bar_widget = QtWidgets.QWidget() # 右側頂部搜尋框部件 self.right_bar_layout = QtWidgets.QGridLayout() # 右側頂部搜尋框網格佈局 self.right_bar_widget.setLayout(self.right_bar_layout) self.search_icon = QtWidgets.QLabel(chr(0xf002) + ' '+'搜尋 ') self.search_icon.setFont(qtawesome.font('fa',16)) self.right_bar_widget_search_input = QtWidgets.QLineEdit() self.right_bar_widget_search_input.setPlaceholderText("輸入歌手、歌曲或使用者,回車進行搜尋") self.right_bar_layout.addWidget(self.search_icon,1) self.right_bar_layout.addWidget(self.right_bar_widget_search_input,8) self.right_layout.addWidget(self.right_bar_widget,9)
執行程式程式碼,其呈現的圖形介面如下圖所示:
然後是推薦音樂模組,在推薦音樂模組中,有一個推薦的標題,和一個橫向排列的音樂封面列表,在這裡:
推薦標題使用QLable()來實現;
音樂封面列表由多個QToolButton()組成,其繼續由一個佈局為QGridLayout()的QWidget()部件所包含。
所以,其程式碼為:
self.right_recommend_label = QtWidgets.QLabel("今日推薦") self.right_recommend_label.setObjectName('right_lable') self.right_recommend_widget = QtWidgets.QWidget() # 推薦封面部件 self.right_recommend_layout = QtWidgets.QGridLayout() # 推薦封面網格佈局 self.right_recommend_widget.setLayout(self.right_recommend_layout) self.recommend_button_1 = QtWidgets.QToolButton() self.recommend_button_1.setText("可馨HANM") # 設定按鈕文字 self.recommend_button_1.setIcon(QtGui.QIcon('./r1.jpg')) # 設定按鈕圖示 self.recommend_button_1.setIconSize(QtCore.QSize(100,100)) # 設定圖示大小 self.recommend_button_1.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) # 設定按鈕形式為上圖下文 self.recommend_button_2 = QtWidgets.QToolButton() self.recommend_button_2.setText("那首歌") self.recommend_button_2.setIcon(QtGui.QIcon('./r2.jpg')) self.recommend_button_2.setIconSize(QtCore.QSize(100,100)) self.recommend_button_2.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.recommend_button_3 = QtWidgets.QToolButton() self.recommend_button_3.setText("偉大的渺小") self.recommend_button_3.setIcon(QtGui.QIcon('./r3.jpg')) self.recommend_button_3.setIconSize(QtCore.QSize(100,100)) self.recommend_button_3.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.recommend_button_4 = QtWidgets.QToolButton() self.recommend_button_4.setText("榮耀征戰") self.recommend_button_4.setIcon(QtGui.QIcon('./r4.jpg')) self.recommend_button_4.setIconSize(QtCore.QSize(100,100)) self.recommend_button_4.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.recommend_button_5 = QtWidgets.QToolButton() self.recommend_button_5.setText("獵場合輯") self.recommend_button_5.setIcon(QtGui.QIcon('./r5.jpg')) self.recommend_button_5.setIconSize(QtCore.QSize(100,100)) self.recommend_button_5.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.right_recommend_layout.addWidget(self.recommend_button_1,0) self.right_recommend_layout.addWidget(self.recommend_button_2,1) self.right_recommend_layout.addWidget(self.recommend_button_3,2) self.right_recommend_layout.addWidget(self.recommend_button_4,3) self.right_recommend_layout.addWidget(self.recommend_button_5,4) self.right_layout.addWidget(self.right_recommend_label,9) self.right_layout.addWidget(self.right_recommend_widget,9)
繼續執行程式程式碼,得到的圖形介面如下圖所示:
接著建立音樂列表模組和音樂歌單模組。音樂列表模組和音樂歌單模組都有一個標題和一個小部件來容納具體的內容。
其中標題我們都使用QLabel()部件來實現,而音樂列表我們使用網格佈局的QWidget()部件下包裹著數個QPushButton()按鈕部件來實現,音樂歌單列表則使用網格佈局的QWidget()部件下包裹著數個QToolButton()工具按鈕部件來實現。
音樂列表的具體程式碼如下所示:
self.right_newsong_lable = QtWidgets.QLabel("最新歌曲") self.right_newsong_lable.setObjectName('right_lable') self.right_playlist_lable = QtWidgets.QLabel("熱門歌單") self.right_playlist_lable.setObjectName('right_lable') self.right_newsong_widget = QtWidgets.QWidget() # 最新歌曲部件 self.right_newsong_layout = QtWidgets.QGridLayout() # 最新歌曲部件網格佈局 self.right_newsong_widget.setLayout(self.right_newsong_layout) self.newsong_button_1 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.newsong_button_2 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.newsong_button_3 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.newsong_button_4 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.newsong_button_5 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.newsong_button_6 = QtWidgets.QPushButton("夜機 陳慧嫻 永遠的朋友 03::29") self.right_newsong_layout.addWidget(self.newsong_button_1,) self.right_newsong_layout.addWidget(self.newsong_button_2,) self.right_newsong_layout.addWidget(self.newsong_button_3,) self.right_newsong_layout.addWidget(self.newsong_button_4,) self.right_newsong_layout.addWidget(self.newsong_button_5,) self.right_newsong_layout.addWidget(self.newsong_button_6,)
音樂歌單模組的程式碼如下所示:
self.right_playlist_widget = QtWidgets.QWidget() # 播放歌單部件 self.right_playlist_layout = QtWidgets.QGridLayout() # 播放歌單網格佈局 self.right_playlist_widget.setLayout(self.right_playlist_layout) self.playlist_button_1 = QtWidgets.QToolButton() self.playlist_button_1.setText("無法釋懷的整天迴圈音樂…") self.playlist_button_1.setIcon(QtGui.QIcon('./p1.jpg')) self.playlist_button_1.setIconSize(QtCore.QSize(100,100)) self.playlist_button_1.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.playlist_button_2 = QtWidgets.QToolButton() self.playlist_button_2.setText("不需要歌詞,也可以打動你的心") self.playlist_button_2.setIcon(QtGui.QIcon('./p2.jpg')) self.playlist_button_2.setIconSize(QtCore.QSize(100,100)) self.playlist_button_2.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.playlist_button_3 = QtWidgets.QToolButton() self.playlist_button_3.setText("那些你熟悉又不知道名字…") self.playlist_button_3.setIcon(QtGui.QIcon('./p3.jpg')) self.playlist_button_3.setIconSize(QtCore.QSize(100,100)) self.playlist_button_3.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.playlist_button_4 = QtWidgets.QToolButton() self.playlist_button_4.setText("那些只聽前奏就中毒的英文歌") self.playlist_button_4.setIcon(QtGui.QIcon('./p4.jpg')) self.playlist_button_4.setIconSize(QtCore.QSize(100,100)) self.playlist_button_4.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.right_playlist_layout.addWidget(self.playlist_button_1,0) self.right_playlist_layout.addWidget(self.playlist_button_2,1) self.right_playlist_layout.addWidget(self.playlist_button_3,0) self.right_playlist_layout.addWidget(self.playlist_button_4,1)
然後將它們新增到右側佈局層中:
self.right_layout.addWidget(self.right_newsong_lable,5) self.right_layout.addWidget(self.right_playlist_lable,4) self.right_layout.addWidget(self.right_newsong_widget,5) self.right_layout.addWidget(self.right_playlist_widget,4)
繼續執行程式程式碼,顯示出來的圖形介面如下圖所示:
這樣,基本上能夠看得出來圖形介面的模樣了,還差最後的音樂播放進度條和音樂播放控制按鈕組。
音樂播放進度條我們使用QProgressBar()進度條部件來實現,音樂播放控制按鈕組則使用一個QWidget()部件下包裹著三個QPushButton()按鈕部件來實現。
其具體程式碼如下:
self.right_process_bar = QtWidgets.QProgressBar() # 播放進度部件 self.right_process_bar.setValue(49) self.right_process_bar.setFixedHeight(3) # 設定進度條高度 self.right_process_bar.setTextVisible(False) # 不顯示進度條文字 self.right_playconsole_widget = QtWidgets.QWidget() # 播放控制部件 self.right_playconsole_layout = QtWidgets.QGridLayout() # 播放控制部件網格佈局層 self.right_playconsole_widget.setLayout(self.right_playconsole_layout) self.console_button_1 = QtWidgets.QPushButton(qtawesome.icon('fa.backward',color='#F76677'),"") self.console_button_2 = QtWidgets.QPushButton(qtawesome.icon('fa.forward',"") self.console_button_3 = QtWidgets.QPushButton(qtawesome.icon('fa.pause',color='#F76677',font=18),"") self.console_button_3.setIconSize(QtCore.QSize(30,30)) self.right_playconsole_layout.addWidget(self.console_button_1,0) self.right_playconsole_layout.addWidget(self.console_button_2,2) self.right_playconsole_layout.addWidget(self.console_button_3,1) self.right_playconsole_layout.setAlignment(QtCore.Qt.AlignCenter) # 設定佈局內部件居中顯示 self.right_layout.addWidget(self.right_process_bar,9) self.right_layout.addWidget(self.right_playconsole_widget,9)
最後執行程式程式碼,我們就得到了這個圖形介面的完整部件的形態,其如下圖所示:
完成了基本的圖形介面小部件的搭建,接下來,我們可以對這個圖形介面進行一下美化了,因為現在的這個樣子實在是很醜陋很不好看。
二、使用QSS和部件屬性美化視窗部件
QSS全稱為Qt StyleSheet,是用來控制QT控制元件的樣式表。其和Web前段開發中的CSS樣式表類似,接下來,我們就通過QSS來對上面建立好的圖形介面進行美化。
視窗控制按鈕
首先從左側的選單欄開始。
左側的最頂端是三個視窗控制按鈕,我們需要將其設定為小圓點的形式。首先,我們使用QPushButton()的setFixedSize()方法,設定按鈕的大小:
self.left_close.setFixedSize(15,15) # 設定關閉按鈕的大小 self.left_visit.setFixedSize(15,15) # 設定按鈕大小 self.left_mini.setFixedSize(15,15) # 設定最小化按鈕大小
然後,通過setStyleSheet()方法,設定按鈕部件的QSS樣式,在這裡,左側按鈕預設為淡綠色,滑鼠懸浮時為深綠色;中間按鈕預設為淡黃色,滑鼠懸浮時為深黃色;右側按鈕預設為淺紅色,滑鼠懸浮時為紅色。所以它們的QSS樣式設定如下所示:
self.left_close.setStyleSheet('''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''') self.left_visit.setStyleSheet('''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''') self.left_mini.setStyleSheet('''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')
執行程式程式碼,可以發現三個控制按鈕已經變成了比較美觀的小圓點了:
左側選單按鈕
因為最後的圖形介面中,左側的部件背景是灰色的,所以我們需要將左側選單中的按鈕和文字顏色設定為白色,並且將按鈕的邊框去掉,在left_widget中設定qss樣式為:
self.left_widget.setStyleSheet(''' QPushButton{border:none;color:white;} QPushButton#left_label{ border:none; border-bottom:1px solid white; font-size:18px; font-weight:700; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; } QPushButton#left_button:hover{border-left:4px solid red;font-weight:700;} ''')
右側背景、搜尋框和模組文字
完成了左側部件的美化之後,我們接著對右側的內容部件進行處理,首先是頂部的搜尋框,因為搜尋框使用的是QLineEdit()部件,預設情況下稜角分明很是不好看,我們對其進行圓角處理:
self.right_bar_widget_search_input.setStyleSheet( '''QLineEdit{ border:1px solid gray; width:300px; border-radius:10px; padding:2px 4px; }''')
因為圖形介面是會呈現出無邊框的圓角形式,所以右側的部件的右上角和右下角需要先行處理為圓角的,同時背景設定為白色。對推薦模組、音樂列表模組和音樂歌單模組的標題我們也需要對其字型進行放大處理,所以最後的樣式為:
self.right_widget.setStyleSheet(''' QWidget#right_widget{ color:#232C51; background:white; border-top:1px solid darkGray; border-bottom:1px solid darkGray; border-right:1px solid darkGray; border-top-right-radius:10px; border-bottom-right-radius:10px; } QLabel#right_lable{ border:none; font-size:16px; font-weight:700; font-family: "Helvetica Neue",sans-serif; } ''')
執行程式程式碼,呈現出來的圖形介面已經越來越像最終的形態的:
推薦模組、歌單模組和歌曲列表模組
因為推薦模組和歌單模組中使用的都是QToolButton()部件,所以其樣式也類似:
self.right_recommend_widget.setStyleSheet( ''' QToolButton{border:none;} QToolButton:hover{border-bottom:2px solid #F76677;} ''') self.right_playlist_widget.setStyleSheet( ''' QToolButton{border:none;} QToolButton:hover{border-bottom:2px solid #F76677;} ''')
而音樂列表使用的是QPushButton()按鈕部件,我們需要對其去除邊框,修改字型和顏色等,所以其樣式為:
self.right_newsong_widget.setStyleSheet(''' QPushButton{ border:none; color:gray; font-size:12px; height:40px; padding-left:5px; padding-right:10px; text-align:left; } QPushButton:hover{ color:black; border:1px solid #F3F3F5; border-radius:10px; background:LightGray; } ''')
執行程式程式碼,現在的圖形介面如下圖所示:
播放進度條和播放控制按鈕組
接下來輪到播放進度條和播放控制按鈕組了,我們需要將播放進度條的樣色設定為淺紅色,然後去除播放控制按鈕的邊框,所以其QSS樣式為:
self.right_process_bar.setStyleSheet(''' QProgressBar::chunk { background-color: #F76677; } ''') self.right_playconsole_widget.setStyleSheet(''' QPushButton{ border:none; } ''')
到了這一步,執行程式程式碼所出現的圖形介面越來越有最終介面的樣子了:
接下來就是最後的美化工作了!
三、視窗實現無邊框和圓角
到了上一步,通過QSS調整的樣式我們基本已經完成了,現在需要使用PyQt5中各個部件的其他內建屬性來完成這個圖形介面的最終美化工作。
設定視窗背景透明
透明的視窗背景會讓圖形介面有現代感和時尚感,我們來講圖形介面的視窗背景設為透明:
self.setWindowOpacity(0.9) # 設定視窗透明度 self.setAttribute(QtCore.Qt.WA_TranslucentBackground) # 設定視窗背景透明
執行程式程式碼,我們得到了一個觀感很不一樣的介面:
去除視窗邊框
視窗背景設定為透明後的體驗很不一樣,但是那個預設的邊框很不協調,那麼去除醜醜的預設邊框是必須要做的工作,通過視窗的setWindowFlag()屬性我們可以設定視窗的狀態從而把邊框給隱藏了:
self.setWindowFlag(QtCore.Qt.FramelessWindowHint) # 隱藏邊框
為了避免隱藏視窗邊框後,左側部件沒有背景顏色和邊框顯示,我們再對左側部件新增QSS屬性:
self.main_widget.setStyleSheet(''' QWidget#left_widget{ background:gray; border-top:1px solid white; border-bottom:1px solid white; border-left:1px solid white; border-top-left-radius:10px; border-bottom-left-radius:10px; } ''')
執行程式程式碼,一個完成度99%的圖形介面就出來了:
之所以說完成度99%,因為可以發現圖形介面中左側部件和右側部件中有一條縫隙,我們通過設定佈局內部件的間隙來把那條縫隙去除掉:
self.main_layout.setSpacing(0)
這樣出現的圖形介面中就沒有那條礙眼的縫隙了:
這樣,我們對圖形介面的美化工作就完成了。
到此本文介紹的PyQt5美化窗體與控制元件例項就講完了,更多關於使用python中的GUI庫圖形介面開發庫PyQt5來美化窗體與控制元件(異形窗體)例項請檢視下面的相關連結