127 lines
3.6 KiB
Python
127 lines
3.6 KiB
Python
from PySide6.QtWidgets import (
|
||
QAbstractButton,
|
||
QApplication,
|
||
QSizePolicy,
|
||
QWidget,
|
||
QVBoxLayout,
|
||
)
|
||
from PySide6.QtCore import Qt, QRect, Signal
|
||
from PySide6.QtGui import QPainter, QBrush
|
||
|
||
|
||
class SwitchButton(QAbstractButton):
|
||
# 开关切换信号
|
||
# 开: True, 关: False
|
||
switched = Signal(bool)
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
self._checked = False
|
||
|
||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||
|
||
# 颜色映射
|
||
self.color_keymap = {
|
||
"slider": "#16ffff",
|
||
"text": Qt.GlobalColor.white,
|
||
"on_bg": "#008ee8", # 开的时候的背景颜色
|
||
"off_bg": "#001c83", # 关的时候的背景颜色
|
||
}
|
||
|
||
self.clicked.connect(self.onClicked)
|
||
self._init_style() # 新尺寸的样式表
|
||
self._init_size_policy()
|
||
|
||
def _init_style(self):
|
||
self.setStyleSheet(
|
||
"""
|
||
SwitchButton {
|
||
font-family: "Microsoft YaHei";
|
||
font-size: 11px;
|
||
color: white;
|
||
border-radius: 9px;
|
||
margin: 2px;
|
||
min-width: 39px;
|
||
max-width: 39px;
|
||
min-height: 18px;
|
||
max-height: 18px;
|
||
}
|
||
"""
|
||
)
|
||
|
||
def _init_size_policy(self):
|
||
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||
|
||
def paintEvent(self, event):
|
||
# 1. 调整滑块间距
|
||
slider_space = 1 # 滑块与背景的间距(上下左右各1px)
|
||
painter = QPainter(self)
|
||
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
||
|
||
try:
|
||
# 2. 绘制背景
|
||
background_rect = self.rect()
|
||
painter.setPen(Qt.PenStyle.NoPen)
|
||
bg_color = (
|
||
self.color_keymap["on_bg"]
|
||
if self._checked
|
||
else self.color_keymap["off_bg"]
|
||
)
|
||
painter.setBrush(QBrush(bg_color))
|
||
painter.drawRoundedRect(
|
||
background_rect, self.height() / 2, self.height() / 2
|
||
)
|
||
|
||
# 3. 计算新滑块尺寸
|
||
slider_width = self.height() - slider_space * 2
|
||
|
||
# 4. 计算新滑块位置
|
||
if self._checked:
|
||
slider_x = self.width() - slider_width - slider_space
|
||
else:
|
||
slider_x = slider_space
|
||
slider_y = slider_space
|
||
|
||
# 5. 绘制滑块
|
||
slider_rect = QRect(slider_x, slider_y, slider_width, slider_width)
|
||
painter.setBrush(QBrush(self.color_keymap["slider"]))
|
||
painter.drawEllipse(slider_rect)
|
||
finally:
|
||
painter.end()
|
||
|
||
def onClicked(self):
|
||
self._checked = not self._checked
|
||
self.update()
|
||
self.switched.emit(self._checked)
|
||
|
||
def setChecked(self, checked: bool):
|
||
self._checked = checked
|
||
self.update()
|
||
self.switched.emit(self._checked)
|
||
|
||
def isChecked(self) -> bool:
|
||
return self._checked
|
||
|
||
|
||
# 测试示例
|
||
if __name__ == "__main__":
|
||
import sys
|
||
|
||
app = QApplication(sys.argv)
|
||
|
||
test_window = QWidget()
|
||
test_window.setWindowTitle("开关测试")
|
||
test_window.resize(200, 100)
|
||
|
||
layout = QVBoxLayout(test_window)
|
||
layout.setContentsMargins(50, 30, 50, 30)
|
||
|
||
switch = SwitchButton()
|
||
switch.switched.connect(
|
||
lambda state: print(f"开关状态:{'选中' if state else '未选中'}")
|
||
)
|
||
layout.addWidget(switch)
|
||
|
||
test_window.show()
|
||
sys.exit(app.exec())
|