赞
踩
你将获取以下知识:
圆角,简约,暗夜模式
- 窗口标题栏被替换
- 内容区由搜索框和快捷栏组成
先将默认的标题栏去掉
self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint) # 设置无边框 self.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明
- 1
- 2
其次通过Qss实现圆角需要paintEvent的支持
def paintEvent(self, event): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PrimitiveElement.PE_Widget,opt,p,self) super().paintEvent(event)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
接着我们开始重实现标题栏
右边由:QLabel构成 左边由:QPushButton构成值得留意的是Qss背景不支持?
self.setAttribute(Qt.WA_StyledBackground, True) # 支持qss设置背景
- 1
重实现 标题栏拖拽窗口移动
def mousePressEvent(self, event): super().mousePressEvent(event) if event.button() == Qt.MouseButton.LeftButton: self._press = True self.mouseStartPos = event.globalPos() # 获取点击屏幕坐标 self.windowTopLeftPos = self.mapToGlobal(self.frameGeometry().topLeft()) # 获取窗口左上角屏幕坐标 def mouseMoveEvent(self, event): super().mouseMoveEvent(event) if self._press: distance = event.globalPos() - self.mouseStartPos # 计算移动距离 self.window().move(distance + self.windowTopLeftPos) # 移动窗口 def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) if self._press: self._press = False # 注意坐标系应相当于屏幕坐标系
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
主要是对QLineEidt的样式设置和PaintEvent的重写
def paintEvent(self, event): super().paintEvent(event) painter = QPainter(self) img = QPixmap('./img/find.png').scaled(34,34,Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.SmoothTransformation) painter.drawPixmap( 600-25-18,2, img) # Qss QLineEdit{ color: white; padding-left: 12px; padding-right: 40px; border: 2px solid gray; border-radius: 20px; background-color: #282c35; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
至于QLineEdit的搜索按钮点击事件,通过重写mousePressEvent实现,详解源代码
它由QTableWidet构成,单元格由两个QLabel构成
值得注意点是:QTableWidget设置样式(stylesheet)后,单元格行高列宽会失效,解决方法如下:
self.horizontalHeader().setDefaultSectionSize(int) self.verticalHeader().setDefaultSectionSize(int)
- 1
- 2
标题和图标,通过爬虫获取
from PIL import Image from urllib.parse import urlsplit import requests as rq def getIcon(url:str): # 知识点:网址通常开放 主机名 + “/favicon.ico” 为图标api parser_url = urlsplit(url) netloc = parser_url.netloc # 获取主机名 icon_url = parser_url.scheme + '://' + netloc + "/favicon.ico" savePath = f'./img/{netloc.replace(".","_")}.ico' if not os.path.exists(savePath): img = Image.open(BytesIO(rq.get(icon_url,headers=HEADERS,verify=False).content)) if img.width < 64 or img.height < 64: img = img.resize((64,64)) img.save(savePath,sizes=[(64,64)]) return netloc.replace(".","_") # 获取标题部分详见源代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
由于爬虫会阻塞主线程,所以使用多线程加载是个好方法
from threading import Thread currentThreading = Thread(target=self.cellInit, args=(row,index,DEFAULTURLS[key],key,)) currentThreading.start() class shortcutsBar(QTableWidget): addCell = Signal(int,int,str,str) def __init__(self, parent=None): super().__init__(parent) self.bind() self.initSetup() def bind(self): self.addCell.connect(self.setCellEvent) def initSetup(self): # 详解源代码 ....... DEFAULTURLS ={'SteamWorkShop': 'https://steamcommunity.com/', 'Watt Toolkit': 'https://steampp.net/'} for index,key in enumerate(DEFAULTURLS.keys()): row = 0 if index > 5: index -= 5 row = 1 currentThreading = Thread(target=self.cellInit, args=(row,index,DEFAULTURLS[key],key,)) currentThreading.start() def cellInit(self,row:int,col:int,url:str,text:str): img = getIcon(url) self.addCell.emit(row,col,img,text) @Slot(int,int,str,str) def setCellEvent(self,row:int,col:int,img:str,text:str): cell = QWidget() cellLayout = QVBoxLayout(cell) cellText = QLabel(text) cellText.setFont(QFont('微软雅黑',12)) cellText.setStyleSheet('color: #ffffff') cellIcon = iconLabel(f'./img/{img}.ico',text) cellLayout.addWidget(cellIcon,alignment=Qt.AlignmentFlag.AlignCenter) cellLayout.addWidget(cellText,alignment=Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignBottom) self.setCellWidget(row,col,cell)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
这里采用原生多线程 + Signal 的原因是:在多线程中操作任何UI容易造成软件崩溃
如果是连续往UI添加东西要给界面留绘制时间 (sleep)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。