提交 01b130f4 编写于 作者: 之一Yo's avatar 之一Yo

添加文件夹列表对话框和状态提示条

上级 506f4ef2
......@@ -85,7 +85,32 @@ A collection of commonly used widgets.
<img src="screenshot/dialog_with_mask.gif" />
</td>
</tr>
</tbody>
<tr>
<td>
Folder List Dialog
</td>
<td>
<code>FolderListDialog</code>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<img src="screenshot/folder_list_dialog.gif" />
</td>
</tr>
<tr>
<td>
State Tooltip
</td>
<td>
<code>StateTooltip</code>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<img src="screenshot/state_tooltip.gif" />
</td>
</tr>
<tr>
<td>
Smooth Scroll Area
......
......@@ -39,4 +39,9 @@ QPushButton:pressed:focus {
QPushButton:focus{
background-color: rgb(0, 154, 187);
}
QPushButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from dialog import MaskDialog
from mask_dialog import MaskDialog
class Window(QWidget):
......
......@@ -36,11 +36,7 @@ class MaskDialog(QDialog):
self.contentLabel.move(30, 70)
self.contentLabel.setText('\n'.join(textwrap.wrap(self.content, 36)))
# 设置层叠样式
self.windowMask.setObjectName('windowMask')
self.titleLabel.setObjectName('titleLabel')
self.contentLabel.setObjectName('contentLabel')
with open('resource/dialog.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
self.__setQss()
# 调节内部对话框大小并居中
self.__initLayout()
# 信号连接到槽
......@@ -101,3 +97,11 @@ class MaskDialog(QDialog):
def __onYesButtonClicked(self):
self.yesSignal.emit()
self.close()
def __setQss(self):
""" 设置层叠样式 """
self.windowMask.setObjectName('windowMask')
self.titleLabel.setObjectName('titleLabel')
self.contentLabel.setObjectName('contentLabel')
with open('resource/mask_dialog.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
......@@ -36,4 +36,9 @@ QPushButton:pressed:hover {
QPushButton:hover {
background-color: rgb(230, 230, 230);
}
QPushButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
# coding:utf-8
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from folder_list_dialog import FolderListDialog
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.resize(1000, 800)
self.btn = QPushButton('点我', parent=self)
self.btn.move(425, 375)
self.btn.clicked.connect(self.showDialog)
self.btn.setObjectName('btn')
with open('resource/style/demo.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
def showDialog(self):
folder_paths = ['D:/KuGou', 'C:/Users/shoko/Documents/音乐']
title = '从本地曲库创建个人"收藏"'
content = '现在我们正在查看这些文件夹:'
w = FolderListDialog(folder_paths, title, content, self)
w.folderChanged.connect(lambda x: print(x))
w.exec()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
# coding:utf-8
import textwrap
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QDialog, QLabel, QPushButton
class Dialog(QDialog):
yesSignal = pyqtSignal()
cancelSignal = pyqtSignal()
def __init__(self, title: str, content: str, parent=None):
super().__init__(parent, Qt.WindowTitleHint | Qt.CustomizeWindowHint)
self.resize(300, 200)
self.setWindowTitle(title)
self.content = content
self.titleLabel = QLabel(title, self)
self.contentLabel = QLabel(content, self)
self.yesButton = QPushButton('确定', self)
self.cancelButton = QPushButton('取消', self)
self.__initWidget()
def __initWidget(self):
""" 初始化小部件 """
self.yesButton.setFocus()
self.titleLabel.move(30, 22)
self.contentLabel.setMaximumWidth(900)
self.contentLabel.setText('\n'.join(textwrap.wrap(self.content, 51)))
self.contentLabel.move(30, self.titleLabel.y()+50)
# 设置层叠样式
self.__setQss()
# 调整窗口大小
self.yesButton.adjustSize()
self.cancelButton.adjustSize()
self.contentLabel.adjustSize()
rect = self.contentLabel.rect()
self.setFixedSize(60+rect.right()+self.cancelButton.width(),
self.contentLabel.y()+self.contentLabel.height()+self.yesButton.height()+60)
# 信号连接到槽
self.yesButton.clicked.connect(self.__onYesButtonClicked)
self.cancelButton.clicked.connect(self.__onCancelButtonClicked)
def resizeEvent(self, e):
self.cancelButton.move(self.width()-self.cancelButton.width()-30,
self.height()-self.cancelButton.height()-30)
self.yesButton.move(self.cancelButton.x() -
self.yesButton.width()-30, self.cancelButton.y())
def __onCancelButtonClicked(self):
self.cancelSignal.emit()
self.deleteLater()
def __onYesButtonClicked(self):
self.yesSignal.emit()
self.deleteLater()
def __setQss(self):
""" 设置层叠样式 """
self.titleLabel.setObjectName("titleLabel")
self.contentLabel.setObjectName("contentLabel")
with open('resource/style/dialog.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
# coding:utf-8
import os
from PyQt5.QtCore import QEasingCurve, QPropertyAnimation, Qt, pyqtSignal
from PyQt5.QtGui import (QBrush, QColor, QFont, QFontMetrics, QMouseEvent,
QPainter, QPen, QPixmap)
from PyQt5.QtWidgets import (QDialog, QGraphicsDropShadowEffect,
QGraphicsOpacityEffect, QLabel, QPushButton,
QWidget, QFileDialog, QHBoxLayout)
from dialog import Dialog
class FolderListDialog(QDialog):
""" 文件夹列表对话框 """
folderChanged = pyqtSignal(list)
def __init__(self, folderPaths: list, title: str, content: str, parent):
super().__init__(parent=parent)
self.title = title
self.content = content
self.__original_paths = folderPaths
self.folderPaths = folderPaths.copy()
self.hBox = QHBoxLayout(self)
self.windowMask = QWidget(self)
self.widget = QWidget(self)
self.titleLabel = QLabel(title, self.widget)
self.contentLabel = QLabel(content, self.widget)
self.completeButton = QPushButton('完成', self.widget)
self.addFolderCard = AddFolderCard(self.widget)
self.folderCards = [FolderCard(i, self.widget)
for i in folderPaths]
self.__initWidget()
def __initWidget(self):
""" 初始化小部件 """
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.widget.setFixedSize(440, 324 + 100*len(self.folderPaths))
self.setGeometry(0, 0, self.parent().width(), self.parent().height())
self.windowMask.resize(self.size())
self.__setQss()
self.__initLayout()
self.__setShadowEffect()
# 信号连接到槽
self.addFolderCard.clicked.connect(self.showFileDialog)
self.completeButton.clicked.connect(self.__onButtonClicked)
for card in self.folderCards:
card.clicked.connect(self.showDeleteFolderCardDialog)
def __initLayout(self):
""" 初始化布局 """
self.hBox.addWidget(self.widget)
self.titleLabel.move(30, 30)
self.contentLabel.move(30, 79)
self.addFolderCard.move(35, 120)
self.completeButton.move(223, self.widget.height() - 71)
for i, folderCard in enumerate(self.folderCards):
folderCard.move(36, 220 + i*100)
def __setShadowEffect(self):
""" 添加阴影 """
shadowEffect = QGraphicsDropShadowEffect(self.widget)
shadowEffect.setBlurRadius(50)
shadowEffect.setOffset(0, 5)
self.widget.setGraphicsEffect(shadowEffect)
def showFileDialog(self):
""" 显示文件对话框 """
path = QFileDialog.getExistingDirectory(self, "选择文件夹", "./")
if path and path not in self.folderPaths:
# 创建文件路径卡
self.widget.setFixedHeight(self.widget.height() + 100)
folderCard = FolderCard(path, self.widget)
folderCard.move(36, self.widget.height() - 206)
folderCard.clicked.connect(self.showDeleteFolderCardDialog)
folderCard.show()
self.folderPaths.append(path)
self.folderCards.append(folderCard)
self.completeButton.move(223, self.widget.height() - 71)
def showDeleteFolderCardDialog(self):
""" 显示删除文件夹卡片对话框 """
sender = self.sender()
title = '确认删除文件夹吗?'
content = f'如果将"{sender.folderName}"文件夹从列表中移除,则该文件夹不会再出现在列表中,但不会被删除。'
dialog = Dialog(title, content, self.window())
dialog.yesSignal.connect(lambda: self.deleteFolderCard(sender))
dialog.exec_()
def deleteFolderCard(self, folderCard):
""" 删除选中的文件卡 """
# 获取下标
index = self.folderCards.index(folderCard)
self.folderCards.pop(index)
self.folderPaths.pop(index)
folderCard.deleteLater()
# 将下面的卡片上移
for card in self.folderCards[index:]:
card.move(card.x(), card.y() - 100)
# 更新高度
self.widget.setFixedHeight(self.widget.height() - 100)
self.completeButton.move(223, self.widget.height() - 71)
def showEvent(self, e):
""" 淡入 """
opacityEffect = QGraphicsOpacityEffect(self)
self.setGraphicsEffect(opacityEffect)
opacityAni = QPropertyAnimation(opacityEffect, b'opacity', self)
opacityAni.setStartValue(0)
opacityAni.setEndValue(1)
opacityAni.setDuration(200)
opacityAni.setEasingCurve(QEasingCurve.InSine)
opacityAni.finished.connect(opacityEffect.deleteLater)
opacityAni.start()
super().showEvent(e)
def closeEvent(self, e):
""" 淡出 """
self.widget.setGraphicsEffect(None)
opacityEffect = QGraphicsOpacityEffect(self)
self.setGraphicsEffect(opacityEffect)
opacityAni = QPropertyAnimation(opacityEffect, b'opacity', self)
opacityAni.setStartValue(1)
opacityAni.setEndValue(0)
opacityAni.setDuration(100)
opacityAni.setEasingCurve(QEasingCurve.OutCubic)
opacityAni.finished.connect(self.deleteLater)
opacityAni.start()
e.ignore()
def __setQss(self):
""" 设置层叠样式 """
self.windowMask.setObjectName('windowMask')
self.titleLabel.setObjectName('titleLabel')
self.contentLabel.setObjectName('contentLabel')
self.completeButton.setObjectName('completeButton')
with open('resource/style/folder_list_dialog.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
def __onButtonClicked(self):
""" 完成按钮点击槽函数 """
if sorted(self.__original_paths) != sorted(self.folderPaths):
self.folderChanged.emit(self.folderPaths)
self.close()
class ClickableWindow(QWidget):
""" 可点击窗口 """
clicked = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setWindowFlags(Qt.FramelessWindowHint)
self.resize(365, 90)
# 设置标志位
self._isPressed = None
self._isEnter = False
def enterEvent(self, e):
""" 鼠标进入界面就置位进入标志位 """
self._isEnter = True
self.update()
def leaveEvent(self, e):
""" 鼠标离开就清零置位标志位 """
self._isEnter = False
self.update()
def mouseReleaseEvent(self, e):
""" 鼠标松开时更新界面 """
self._isPressed = False
self.update()
if e.button() == Qt.LeftButton:
self.clicked.emit()
def mousePressEvent(self, e: QMouseEvent):
self._isPressed = True
self.update()
def paintEvent(self, e):
""" 绘制背景 """
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
brush = QBrush(QColor(204, 204, 204))
painter.setPen(Qt.NoPen)
if not self._isEnter:
painter.setBrush(brush)
painter.drawRoundedRect(self.rect(), 5, 5)
else:
painter.setPen(QPen(QColor(204, 204, 204), 2))
painter.drawRect(1, 1, self.width() - 2, self.height() - 2)
painter.setPen(Qt.NoPen)
if not self._isPressed:
brush.setColor(QColor(230, 230, 230))
painter.setBrush(brush)
painter.drawRect(2, 2, self.width() - 4, self.height() - 4)
else:
brush.setColor(QColor(153, 153, 153))
painter.setBrush(brush)
painter.drawRoundedRect(
6, 1, self.width() - 12, self.height() - 2, 3, 3)
class FolderCard(ClickableWindow):
""" 文件夹卡片 """
def __init__(self, folderPath: str, parent=None):
super().__init__(parent)
self.folderPath = folderPath
self.folderName = os.path.basename(folderPath)
self.__closeIcon = QPixmap("resource/images/黑色叉号.png")
def paintEvent(self, e):
""" 绘制背景 """
super().paintEvent(e)
painter = QPainter(self)
painter.setRenderHints(
QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform
)
# 绘制文字和图标
if self._isPressed:
self.__drawText(painter, 15, 10, 15, 9)
painter.drawPixmap(
self.width() - 33, 23, self.__closeIcon.width(), self.__closeIcon.height(), self.__closeIcon)
else:
self.__drawText(painter, 12, 11, 12, 10)
painter.drawPixmap(
self.width() - 30, 25, self.__closeIcon.width(), self.__closeIcon.height(), self.__closeIcon)
def __drawText(self, painter, x1, fontSize1, x2, fontSize2):
""" 绘制文字 """
# 绘制文件夹名字
font = QFont("Microsoft YaHei", fontSize1, 75)
painter.setFont(font)
name = QFontMetrics(font).elidedText(
self.folderName, Qt.ElideRight, self.width()-60)
painter.drawText(x1, 37, name)
# 绘制路径
font = QFont("Microsoft YaHei", fontSize2)
painter.setFont(font)
path = QFontMetrics(font).elidedText(
self.folderPath, Qt.ElideRight, self.width()-30)
painter.drawText(x2, 46, self.width() - 20, 23, Qt.AlignLeft, path)
class AddFolderCard(ClickableWindow):
""" 点击选择模型 """
def __init__(self, parent=None):
super().__init__(parent)
self.__iconPix = QPixmap("resource/images/黑色加号.png")
def paintEvent(self, e):
""" 绘制背景 """
super().paintEvent(e)
painter = QPainter(self)
if not self._isPressed:
painter.drawPixmap(
int(self.width() / 2 - self.__iconPix.width() / 2),
int(self.height() / 2 - self.__iconPix.height() / 2),
self.__iconPix.width(),
self.__iconPix.height(),
self.__iconPix,
)
else:
painter.drawPixmap(
int(self.width() / 2 - (self.__iconPix.width() - 4) / 2),
int(self.height() / 2 - (self.__iconPix.height() - 4) / 2),
self.__iconPix.width() - 4,
self.__iconPix.height() - 4,
self.__iconPix,
)
QWidget {
background-color: white;
}
QPushButton#btn {
background-color: rgb(204, 204, 204);
padding: 10px 64px 10px 64px;
font: 19px 'Microsoft YaHei';
border: transparent;
border-radius: 4px;
/* height: 40px; */
}
QPushButton#btn:pressed:hover {
background-color: rgb(153, 153, 153);
}
QPushButton#btn:hover {
background-color: rgb(230, 230, 230);
}
QPushButton#btn:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
QDialog {
background-color: rgb(0, 126, 153);
}
QLabel {
background-color: transparent;
}
QLabel#titleLabel {
color: white;
font: 33px 'Microsoft YaHei Light';
font-weight: bold;
}
QLabel#contentLabel {
color: white;
font: 18px 'Microsoft YaHei';
font-weight: 400;
}
QPushButton {
color: white;
border: 3px solid white;
padding: 5px 35px 5px 35px;
background: rgb(0, 126, 153);
font: 18px 'Microsoft YaHei';
font-weight: bold;
}
QPushButton:hover {
background: rgb(14, 179, 214);
}
QPushButton:pressed:focus {
color: black;
background-color: white;
}
QPushButton:focus {
background-color: rgb(0, 154, 187);
}
QPushButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
QWidget {
background-color: white;
border: 1px solid rgb(200, 200, 200);
}
QWidget#windowMask {
background-color: rgba(255, 255, 255, 0.6);
border: none;
}
QLabel {
border: none;
}
QLabel#titleLabel {
font: 25px 'Microsoft YaHei';
}
QLabel#contentLabel {
font: 18px 'Microsoft YaHei';
}
QPushButton#completeButton {
background-color: rgb(204, 204, 204);
padding: 11px 64px 11px 64px;
font: 19px 'Microsoft YaHei';
border: none;
height: 20px;
width: 55px;
}
QPushButton#completeButton:pressed:hover {
background-color: rgb(153, 153, 153);
}
QPushButton#completeButton:hover {
background-color: rgb(230, 230, 230);
}
QPushButton#completeButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
......@@ -36,7 +36,7 @@ QMenu::right-arrow {
width: 16px;
height: 16px;
right: 16px;
border-image: url(resource/images/子菜单右箭头.png);
border-border-image: url(resource/images/子菜单右箭头.png);
}
......@@ -69,4 +69,3 @@ QMenu::icon {
position: absolute;
left: 16px;
}
# coding:utf-8
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from state_tooltip import StateTooltip
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.resize(800, 300)
self.btn = QPushButton('点我', parent=self)
self.btn.move(310, 225)
self.btn.clicked.connect(self.onButtonClicked)
self.stateTooltip = None
with open('resource/style/demo.qss', encoding='utf-8') as f:
self.setStyleSheet(f.read())
def onButtonClicked(self):
if self.stateTooltip:
self.stateTooltip.setContent('模型训练完成啦 😆')
self.stateTooltip.setState(True)
self.stateTooltip = None
else:
self.stateTooltip = StateTooltip('正在训练模型', '客官请耐心等待哦~~', self)
self.stateTooltip.move(520, 30)
self.stateTooltip.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
QWidget {
background-color: white;
}
QPushButton {
background-color: rgb(204, 204, 204);
padding: 10px 64px 10px 64px;
font: 19px 'Microsoft YaHei';
border: transparent;
border-radius: 4px;
/* height: 40px; */
}
QPushButton:pressed:hover {
background-color: rgb(153, 153, 153);
}
QPushButton:hover {
background-color: rgb(230, 230, 230);
}
QPushButton:disabled {
background-color: rgb(204, 204, 204);
color: rgb(122, 122, 122);
}
\ No newline at end of file
QWidget {
background-color: rgb(0, 107, 131);
}
QLabel#titleLabel {
color: white;
font: 17px 'Microsoft YaHei';
}
QLabel#contentLabel {
color: rgba(255, 255, 255, 210);
font: 16px 'Microsoft YaHei';
}
QToolButton{
border: none;
margin: 0px;
width: 14px;
height: 14px;
background: url(resource/images/close_normal.png) top center no-repeat;
}
QToolButton:hover{
background: url(resource/images/close_hover.png) top center no-repeat;
}
QToolButton:pressed{
background: url(resource/images/close_hover.png) top center no-repeat;
}
\ No newline at end of file
# coding:utf-8
from PyQt5.QtCore import QEasingCurve, QPropertyAnimation, Qt, QTimer
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtWidgets import QLabel, QWidget, QToolButton
class StateTooltip(QWidget):
""" 进度提示框 """
def __init__(self, title="", content="", parent=None):
"""
Parameters
----------
title: str
状态气泡标题
content: str
状态气泡内容
parant:
父级窗口
"""
super().__init__(parent)
self.title = title
self.content = content
# 实例化小部件
self.titleLabel = QLabel(self.title, self)
self.contentLabel = QLabel(self.content, self)
self.rotateTimer = QTimer(self)
self.closeTimer = QTimer(self)
self.animation = QPropertyAnimation(self, b"windowOpacity")
self.busyImage = QPixmap("resource/images/running.png")
self.doneImage = QPixmap("resource/images/complete.png")
self.closeButton = QToolButton(self)
# 初始化参数
self.isDone = False
self.rotateAngle = 0
self.deltaAngle = 20
# 初始化
self.__initWidget()
def __initWidget(self):
""" 初始化小部件 """
self.setAttribute(Qt.WA_StyledBackground)
self.rotateTimer.setInterval(50)
self.closeTimer.setInterval(1000)
self.contentLabel.setMinimumWidth(200)
# 将信号连接到槽函数
self.closeButton.clicked.connect(self.hide) # 点击关闭按钮只是隐藏了提示条
self.rotateTimer.timeout.connect(self.__rotateTimerFlowSlot)
self.closeTimer.timeout.connect(self.__slowlyClose)
self.__setQss()
self.__initLayout()
# 打开定时器
self.rotateTimer.start()
def __initLayout(self):
""" 初始化布局 """
self.titleLabel.adjustSize()
self.contentLabel.adjustSize()
self.setFixedSize(max(self.titleLabel.width(),
self.contentLabel.width()) + 40, 64)
self.titleLabel.move(40, 11)
self.contentLabel.move(15, 34)
self.closeButton.move(self.width() - 30, 23)
def __setQss(self):
""" 设置层叠样式 """
self.titleLabel.setObjectName("titleLabel")
self.contentLabel.setObjectName("contentLabel")
with open("resource/style/state_tooltip.qss", encoding="utf-8") as f:
self.setStyleSheet(f.read())
def setTitle(self, title: str):
""" 设置提示框的标题 """
self.title = title
self.titleLabel.setText(title)
self.titleLabel.adjustSize()
def setContent(self, content: str):
""" 设置提示框内容 """
self.content = content
self.contentLabel.setText(content)
self.contentLabel.adjustSize()
def setState(self, isDone=False):
""" 设置运行状态 """
self.isDone = isDone
self.update()
# 运行完成后主动关闭窗口
if self.isDone:
self.closeTimer.start()
def __slowlyClose(self):
""" 缓慢关闭窗口 """
self.rotateTimer.stop()
self.animation.setEasingCurve(QEasingCurve.Linear)
self.animation.setDuration(500)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.finished.connect(self.deleteLater)
self.animation.start()
def __rotateTimerFlowSlot(self):
""" 定时器溢出时旋转箭头 """
self.rotateAngle = (self.rotateAngle + self.deltaAngle) % 360
self.update()
def paintEvent(self, e):
""" 绘制背景 """
super().paintEvent(e)
# 绘制旋转箭头
painter = QPainter(self)
painter.setRenderHints(QPainter.SmoothPixmapTransform)
painter.setPen(Qt.NoPen)
if not self.isDone:
painter.translate(25, 22) # 原点平移到旋转中心
painter.rotate(self.rotateAngle) # 坐标系旋转
painter.drawPixmap(
-int(self.busyImage.width() / 2),
-int(self.busyImage.height() / 2),
self.busyImage,
)
else:
painter.drawPixmap(
14, 13, self.doneImage.width(), self.doneImage.height(), self.doneImage
)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册