PyQt5技術分享:製作一個美觀的Dock欄
一週一小步,一年一大步!歐!耶!
這周我完成了軟體專案的一個重要的部件--dock欄,閒話少說,先上成品!!!
1.建立透明視窗
要實現這樣一個小視窗當然需要先建立一個QWidget類,並對QWidget的背景,視窗大小,邊框等等做一些小設定,這裡的背景用QPinter動態描繪上邊框和背景色(具體的paintEvent程式碼的也是從某大師那裡抄的,具體哪個,我給忘了,,,)
class Dock_Win(QWidget):
def __init__(self, parent=None):
super(Dock_Win, self).__init__(parent)
self.bg_color = QColor(170, 248, 248, 230) # 設定背警色
self.fill_color = QColor(0,250,255,50) # 陰影顏色
self.initUI()
def initUI(self):
# 設定視窗透明,無邊框
self.setAttribute(Qt.WA_TranslucentBackground) # 透明背景
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog)
# 設定視窗的大小
self.resize(462, 110)
# 設定視窗圓角+邊框陰影
def paintEvent(self, event):
# 設定陰影
painter_path = QPainterPath()
painter_path.setFillRule(Qt.WindingFill)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillPath(painter_path, QBrush(Qt.white))
for i in range(10):
i_path = QPainterPath()
i_path.setFillRule(Qt.WindingFill)
ref = QRectF(10 - i, 10 - i, self.width() - (10 - i) * 2, self.height() - (10 - i) * 2)
i_path.addRoundedRect(ref, 20, 20)
self.fill_color.setAlpha(int(150 - i ** 0.5 * 50))
painter.setPen(self.fill_color)
painter.drawPath(i_path)
# 圓角
self.painter_rect = QPainter(self)
self.painter_rect.setRenderHint(QPainter.Antialiasing) # 抗鋸齒
self.painter_rect.setBrush(self.bg_color)
self.painter_rect.setPen(Qt.transparent)
self._rect = self.rect()
self._rect.setLeft(15)
self._rect.setTop(15)
self._rect.setWidth(self._rect.width() - 15)
self._rect.setHeight(self._rect.height() - 15)
self.painter_rect.begin(self)
self.painter_rect.drawRoundedRect(self._rect, 15, 15)
self.painter_rect.end()
這樣我們就得到了一個時尚而不失優雅的背景視窗
2.為視窗新增移動事件
無邊框的視窗在美觀的同時,也失去了邊框所帶來的移動便利,沒有了邊框的視窗,你左擊並移動滑鼠,跟在一個空白視窗上亂畫沒啥區別,所以要對主視窗的mouseMoveEvent()滑鼠移動事件進行重寫
# 設定視窗移動事件
# 當滑鼠左擊並且移動時觸發視窗移動事件
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.is_move = True
self.move_xy = event.globalPos() - self.pos() # 獲取滑鼠的移動事件
# self.parent_rect = self.parent().pos()
self.setCursor(QCursor(Qt.OpenHandCursor)) # 設定滑鼠為抓手
def mouseMoveEvent(self, event):
if self.is_move:
# 移動dock欄(dock欄的座標位置+滑鼠的偏移量-dock欄的邊框位置)
self.move(event.globalPos() - self.move_xy)
def mouseReleaseEvent(self, event):
self.is_move = False
self.setCursor(QCursor(Qt.ArrowCursor)) # 設定滑鼠為正常
這樣視窗就被你牢牢的把握在手心了
3.新增元件
光有視窗肯定是不夠的,肯定要有選項啊,這裡的選項我嘗試了很多種,有QPushButton,有QListWidget,但由於知識儲備量不夠,都一一失敗了(尬``),最後還不如QLabel來的痛快,這裡直接定製一個QLabel
# 重寫QLabel,讓其能夠支援點選事件
class QLabel_Item(QLabel):
cliecked = pyqtSignal()
def __init__(self,index,QIcon_no,QIcon_on,text=None,parent=None):
super(QLabel_Item, self).__init__(parent)
self.icon_no = QIcon_no # 關閉時的圖示
self.icon_on = QIcon_on # 開啟時的圖示
self.is_clieck = True # 預設滑鼠單擊為單擊事件
if index != 1:
self.is_open = False # 預設為關閉狀態
self.setScaledContents(True) # 設定圖示鋪滿
self.setPixmap(QPixmap(QIcon_no)) # 設定預設圖示
else:
self.is_open = True # 預設第一個圖示為開啟狀態
self.setScaledContents(True) # 設定圖示鋪滿
self.setPixmap(QPixmap(QIcon_on)) # 設定預設圖示
if index != 3:
if index > 3:
_plus = 26
else:
_plus = 0
self.setGeometry(36*index+46*(index-1)+_plus, 26, 46, 46)
self.bottom_text = QLabel(text, parent)
self.bottom_text.setFont(QFont('華文新魏', 10))
self.bottom_text.setAlignment(Qt.AlignCenter)
self.bottom_text.setGeometry(36*index+46*(index-1)+_plus, 74, 46, 16)
else:
self.setScaledContents(True) # 設定圖示鋪滿
self.setPixmap(QPixmap(QIcon_no)) # 設定預設圖示
self.setGeometry(200, 20, 72, 72)
self.setObjectName('play')
self.setToolTip('點選播放')
def set_no(self): # 設定關閉狀態
self.setPixmap(QPixmap(self.icon_no)) # 設定預設圖示
# self.setStyleSheet('background-color:blue')
self.bottom_text.setStyleSheet('text-decoration:normal;') # 設定正常
def set_on(self): # 設定開啟狀態
self.setPixmap(QPixmap(self.icon_on)) # 設定預設圖示
# self.setStyleSheet(f'background-color:red')
self.bottom_text.setStyleSheet('text-decoration:underline;') # 設定下滑線
# 正常情況下滑鼠單擊為觸發事件,點選並移動為移動事件
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.is_clieck = True
self.move_xy = event.globalPos() - self.pos() # 獲取滑鼠的移動事件
self.parent_rect = self.parent().pos()
def mouseMoveEvent(self, event):
self.is_clieck = False
# 移動dock欄(dock欄的座標位置+滑鼠的偏移量-控制元件本身座標)
self.parent().move(self.parent_rect + event.globalPos() - self.move_xy - self.pos())
self.setCursor(QCursor(Qt.OpenHandCursor)) # 設定滑鼠為抓手
self.moved = True
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.setCursor(QCursor(Qt.ArrowCursor)) # 設定滑鼠為正常
if self.is_clieck and not self.is_open:
self.is_open = True
self.cliecked.emit()
elif self.is_clieck:
self.is_open = False
self.cliecked.emit()
- 因為QLabel本身是不支援點選事件的,所以要建立一個clieck訊號
- 為了讓滑鼠移動到圖示上和點選圖示時有更好的反饋效果,QLabel_Item()建立需要傳入開啟時的圖示,關閉時的圖示,底部文字和父視窗(使用絕對佈局時需要)
- 另圖示的滑鼠事件也是很重要的啊,滑鼠的點選,移動,出入都需要圖示進行一個很好的反饋效果
- 因為中間的播放按鈕不是用來進行主介面口切換的,所以要進行特殊關照(你懂的<-.<-)
注:因為QLabel和QLabel是同一類的,所以建立底部文字時,不能將圖示的QLabel設為父類,QLabel只能作為圖片,文字的容器
4.視窗的右擊選單
視窗的右擊選單可以用來對dock欄進行一些設定,這就需要對contextMenuEvent()進行重寫
def contextMenuEvent(self, event): # 連線選單事件
# 設定右擊選單
right_menu = QMenu(self)
set_bg_color = QAction('背景色')
right_menu.addAction(set_bg_color)
# tkl_bg_color = QAction('天空藍')
# lyh_bg_color = QAction('烈焰紅')
# mmh_bg_color = QAction('檸檬黃')
# sll_bg_color = QAction('深林綠')
# jlz_bg_color = QAction('基佬紫')
# other_bg_color = QAction('自定義顏色')
# set_bg_color.addAction(tkl_bg_color)
# set_bg_color.addAction(lyh_bg_color)
# set_bg_color.addAction(mmh_bg_color)
# set_bg_color.addAction(sll_bg_color)
# set_bg_color.addAction(jlz_bg_color)
# set_bg_color.addSeparator() # 新增分隔線
# set_bg_color.addAction(set_bg_color)
# tkl_bg_color.triggered.connect(lambda: self.changeBgColor(tkl_bg_color.text()))
# lyh_bg_color.triggered.connect(lambda: self.changeBgColor(lyh_bg_color.text()))
# mmh_bg_color.triggered.connect(lambda: self.changeBgColor(mmh_bg_color.text()))
# jlz_bg_color.triggered.connect(lambda: self.changeBgColor(jlz_bg_color.text()))
# sll_bg_color.triggered.connect(lambda: self.changeBgColor(sll_bg_color.text()))
set_bg_color.triggered.connect(lambda: self.changeBgColor(''))
set_gh_color = QAction('光圈色')
right_menu.addAction(set_gh_color)
# right_menu.addMenu(set_gh_color)
# tkl_gh_color = QAction('天空藍')
# lyh_gh_color = QAction('烈焰紅')
# mmh_gh_color = QAction('檸檬黃')
# sll_gh_color = QAction('深林綠')
# jlz_gh_color = QAction('基佬紫')
# other_gh_color = QAction('自定義顏色')
# set_gh_color.addAction(tkl_gh_color)
# set_gh_color.addAction(lyh_gh_color)
# set_gh_color.addAction(mmh_gh_color)
# set_gh_color.addAction(sll_gh_color)
# set_gh_color.addAction(jlz_gh_color)
# set_gh_color.addSeparator() # 新增分隔線
# set_gh_color.addAction(other_gh_color)
#
# tkl_gh_color.triggered.connect(lambda: self.changeGhColor(tkl_gh_color.text()))
# lyh_gh_color.triggered.connect(lambda: self.changeGhColor(lyh_gh_color.text()))
# mmh_gh_color.triggered.connect(lambda: self.changeGhColor(mmh_gh_color.text()))
# jlz_gh_color.triggered.coonnect(lambda: self.changeGhColor(jlz_gh_color.text()))
# sll_gh_color.triggered.connect(lambda: self.changeGhColor(sll_gh_color.text()))
set_gh_color.triggered.connect(lambda: self.changeGhColor(''))
#
exit_menu = QAction('退 出',right_menu)
exit_menu.triggered.connect(right_menu.close)
auto_hide = QAction('自動隱藏')
right_menu.addAction(auto_hide)
right_menu.addSeparator() # 新增分割符
right_menu.addAction(exit_menu)
if not self.childAt(event.globalPos()-self.pos()): # 當滑鼠右擊不在圖示範圍內時
right_menu.exec_(event.globalPos()) # 傳入滑鼠的座標
可以看到我這裡原本預定了很多好看的顏色,嘗試過直接對self.bg_color()進行改變,重新整理介面,但不知道為什麼最後只有QColorDialog成功了,無奈,只能摸摸自己所剩無幾的頭髮,嘆了嘆氣,放棄了,如果有大神願為後輩指點一二,吾輩定當無比感謝!(拜託了,yyy)
因為專案的主視窗還在畫餅中,所以dock欄的些許功能尚未完善
最後原始碼獻上:https://github.com/MGod-monkey/ABAB_Book/blob/master/main_dock_UI.py
題外:
原本專案的登入介面已經做好的,而登入賬號用來桂電的VPN賬號,方便後續直接訪問校內資源,寫了篇關於呼叫桂電VPN介面的部落格,但奈何官方對這方面的部落格把控太嚴,無奈只能設為私密了(這裡沒有抱怨,而是稱讚審查大大的一絲不苟,兢兢業業···(此處省略一萬字))
這裡的UI還沒美化完全,後期會定製qss檔案專門美化的,而專案的程式不能因為部分而拖太久了
相關文章
- 如何製作實用美觀的設計文件
- win10怎麼設定像mac系統一樣的dock欄_Win10如何打造個性化的Dock欄Win10Mac
- 如何利用PyQT5製作一個資料圖表生成器QT
- 一個角色最終呈現在引擎裡,美術製作上的思考以及注意事項
- 來自Riot 的一份遊戲美術教程(五):技術美術遊戲
- 騰訊光子《黎明覺醒》技術美術負責人:如何製作超真實的開放世界?
- 探討大世界遊戲的製作流程及技術——大場景製作技術概況篇遊戲
- 技術美術TA是不是一個“越老越吃香”的職業?
- 蘋果Mac中Dock欄怎麼用?蘋果Mac中Dock欄的設定和使用技巧蘋果Mac
- 天美F1技術美術專家:技術美術的未來前景如何?
- Mac Dock欄實用技巧Mac
- Word製作屬於自己的DIY個性工具欄
- 一個優秀的程式設計師應有的產品觀和技術觀程式設計師
- 分享一個高顏值的技術社群 HackerTalk黑客說黑客
- 遊戲技術美術之<技術&美術>知識構成遊戲
- 技術寫作例項解析 | 簡潔即是美
- H5製作技術總結H5
- 『技術分享』—— 我的第一個微信小程式-趣聞微信小程式
- UI 製作使遊戲更具世界觀,UI動畫和UI製作之間的兩個區別UI遊戲動畫
- iPhone怎麼隱藏底部Dock欄桌布?iOS12隱藏Dock欄桌布設定教程iPhoneiOS
- Dock欄快速啟動工具:uDock for MacMac
- Dock欄快速啟動程式:uDock for MacMac
- 前端技術分享:一個超級好用的CSS樣式表前端CSS
- PyQt5 之工具欄QT
- 外掛製作--------過NP技術漸漸
- win10系統mac的dock欄怎麼設定_win10系統mac的dock欄如何設定Win10Mac
- Java技術分享:如何設計一個本地快取?Java快取
- [技術分析]探討大世界遊戲的製作流程及技術——前期流程篇遊戲
- 記一次旁觀他人的技術面試面試
- 一個開源、美觀的日期選擇器(bootstrap datepicker)boot
- 關於技術分享的一點感悟
- 技術分享 | MySQL:從庫複製半個事務會怎麼樣?MySql
- 使用Python庫pyqt5製作TXT閱讀器(一)-------UI設計PythonQTUI
- 異地技術團隊高效協作的經驗分享
- [重慶思莊每日技術分享]-重建LOB欄位上的IndexIndex
- 技術分享 | 基於windows作業系統的錦行蜜罐新節點技術Windows作業系統
- Unity製作一個小星球Unity
- 實用的Dock欄快速啟動工具:uDock for MacMac