From 5ba0fd3556f6f4feb4d57d2fb46735c8a9521136 Mon Sep 17 00:00:00 2001 From: zhiyiYo <1319158137@qq.com> Date: Sun, 15 Jan 2023 11:22:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=97=A0=E8=BE=B9=E6=A1=86?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E6=A1=86=E6=8B=96=E6=8B=BD=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=E8=BF=87=E5=B0=8F=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/demo.py | 27 +++++++++++++++--- qframelesswindow/titlebar/__init__.py | 27 ++++++++++++++---- .../titlebar/title_bar_buttons.py | 12 +++++--- screenshot/logo.png | Bin 0 -> 5847 bytes setup.py | 6 ++-- 5 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 screenshot/logo.png diff --git a/examples/demo.py b/examples/demo.py index a75ec55..323b297 100644 --- a/examples/demo.py +++ b/examples/demo.py @@ -2,8 +2,8 @@ import sys from PyQt5.QtCore import Qt -from PyQt5.QtGui import QColor, QPixmap -from PyQt5.QtWidgets import QApplication, QLabel +from PyQt5.QtGui import QColor, QPixmap, QIcon +from PyQt5.QtWidgets import QApplication, QLabel, QHBoxLayout from qframelesswindow import FramelessWindow, TitleBar @@ -13,9 +13,23 @@ class CustomTitleBar(TitleBar): def __init__(self, parent): super().__init__(parent) + # add window icon + self.iconLabel = QLabel(self) + self.iconLabel.setFixedSize(20, 20) + self.hBoxLayout.insertSpacing(0, 10) + self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft) + self.window().windowIconChanged.connect(self.setIcon) + # add title label self.titleLabel = QLabel(self) - self.titleLabel.setStyleSheet("QLabel{font: 13px 'Segoe UI'; margin: 9px}") + self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft) + self.titleLabel.setStyleSheet(""" + QLabel{ + background: transparent; + font: 13px 'Segoe UI'; + padding: 0 4px + } + """) self.window().windowTitleChanged.connect(self.setTitle) # customize the style of title bar button @@ -38,6 +52,9 @@ def setTitle(self, title): self.titleLabel.setText(title) self.titleLabel.adjustSize() + def setIcon(self, icon): + self.iconLabel.setPixmap(icon.pixmap(20, 20)) + class Window(FramelessWindow): @@ -49,7 +66,9 @@ def __init__(self, parent=None): self.label = QLabel(self) self.label.setScaledContents(True) self.label.setPixmap(QPixmap("screenshot/shoko.png")) - self.setWindowTitle("PyQt Frameless Window") + + self.setWindowIcon(QIcon("screenshot/logo.png")) + self.setWindowTitle("PyQt-Frameless-Window") self.setStyleSheet("background:white") self.titleBar.raise_() diff --git a/qframelesswindow/titlebar/__init__.py b/qframelesswindow/titlebar/__init__.py index 0065a66..105ccf1 100644 --- a/qframelesswindow/titlebar/__init__.py +++ b/qframelesswindow/titlebar/__init__.py @@ -5,7 +5,8 @@ from PyQt5.QtWidgets import QHBoxLayout, QWidget from ..utils import startSystemMove -from .title_bar_buttons import CloseButton, MaximizeButton, MinimizeButton, SvgTitleBarButton +from .title_bar_buttons import (CloseButton, MaximizeButton, MinimizeButton, + SvgTitleBarButton, TitleBarButton) class TitleBar(QWidget): @@ -25,10 +26,11 @@ def __init__(self, parent): # add buttons to layout self.hBoxLayout.setSpacing(0) self.hBoxLayout.setContentsMargins(0, 0, 0, 0) + self.hBoxLayout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft) + self.hBoxLayout.addStretch(1) self.hBoxLayout.addWidget(self.minBtn, 0, Qt.AlignRight) self.hBoxLayout.addWidget(self.maxBtn, 0, Qt.AlignRight) self.hBoxLayout.addWidget(self.closeBtn, 0, Qt.AlignRight) - self.hBoxLayout.setAlignment(Qt.AlignRight) # connect signal to slot self.minBtn.clicked.connect(self.window().showMinimized) @@ -53,13 +55,13 @@ def mouseDoubleClickEvent(self, event): self.__toggleMaxState() def mouseMoveEvent(self, e): - if sys.platform != "win32" or not self._isDragRegion(e.pos()): + if sys.platform != "win32" or not self.canDrag(e.pos()): return startSystemMove(self.window(), e.globalPos()) def mousePressEvent(self, e): - if sys.platform == "win32" or e.button() != Qt.LeftButton or not self._isDragRegion(e.pos()): + if sys.platform == "win32" or not self.canDrag(e.pos()): return startSystemMove(self.window(), e.globalPos()) @@ -72,8 +74,21 @@ def __toggleMaxState(self): self.window().showMaximized() def _isDragRegion(self, pos): - """ Check whether the pressed point belongs to the area where dragging is allowed """ - return 0 < pos.x() < self.width() - 46 * 3 + """ Check whether the position belongs to the area where dragging is allowed """ + width = 0 + for button in self.findChildren(TitleBarButton): + if button.isVisible(): + width += button.width() + + return 0 < pos.x() < self.width() - width + + def _hasButtonPressed(self): + """ whether any button is pressed """ + return any(btn.isPressed() for btn in self.findChildren(TitleBarButton)) + + def canDrag(self, pos): + """ whether the position is draggable """ + return self._isDragRegion(pos) and not self._hasButtonPressed() def setDoubleClickEnabled(self, isEnabled): """ whether to switch window maximization status when double clicked diff --git a/qframelesswindow/titlebar/title_bar_buttons.py b/qframelesswindow/titlebar/title_bar_buttons.py index 6706a67..f14a0bd 100644 --- a/qframelesswindow/titlebar/title_bar_buttons.py +++ b/qframelesswindow/titlebar/title_bar_buttons.py @@ -1,9 +1,9 @@ # coding:utf-8 from enum import Enum -from PyQt5.QtCore import QFile, QPointF, QRectF, QSize, Qt, pyqtProperty -from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPen -from PyQt5.QtWidgets import QToolButton, QAbstractButton +from PyQt5.QtCore import QFile, QPointF, QRectF, Qt, pyqtProperty +from PyQt5.QtGui import QColor, QPainter, QPainterPath, QPen +from PyQt5.QtWidgets import QAbstractButton from PyQt5.QtSvg import QSvgRenderer from PyQt5.QtXml import QDomDocument @@ -48,6 +48,10 @@ def setState(self, state): self._state = state self.update() + def isPressed(self): + """ whether the button is pressed """ + return self._state == TitleBarButtonState.PRESSED + @deprecated def updateStyle(self, style): """ update the style of button """ @@ -304,4 +308,4 @@ def __init__(self, parent=None): self.setHoverColor(Qt.white) self.setPressedColor(Qt.white) self.setHoverBackgroundColor(QColor(232, 17, 35)) - self.setPressedBackgroundColor(QColor(241, 112, 122)) \ No newline at end of file + self.setPressedBackgroundColor(QColor(241, 112, 122)) diff --git a/screenshot/logo.png b/screenshot/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..14ff4eb3edcbd0809a8b27bfbbcc6e959a2af7f3 GIT binary patch literal 5847 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