【PyQt6】【サンプル】トグルボタン(toggle button)

f:id:touch-sp:20220416075955j:plain:w600

はじめに

前回丸いボタンを作りました。
touch-sp.hatenablog.com
今回はそれを応用してトグルボタン(toggle button)を作ってみました。

Pythonスクリプト

from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtWidgets import QPushButton, QGridLayout, QFrame, QSizePolicy

class ToggleButton(QFrame):

    clicked = pyqtSignal(bool)

    def __init__(self, width = 80, height = 140):
        super().__init__()
        self.width = width
        self.height = height
        if self.width < self.height * 2 -20:
            self.width = self.height * 2 -20
        self.setFixedSize(self.width, self.height)
        self.toggle_on = False
        self.initUI()

    def initUI(self):
        
        self.button_1 = QPushButton()
        self.button_1.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Ignored)

        self.button_2 = QPushButton()
        self.button_3 = QPushButton()

        self.button_2.setFixedSize(self.height - 30, self.height - 30)
        self.button_3.setFixedSize(self.height - 30, self.height - 30)

        self.button_1.setStyleSheet(
            "border-radius : %d; border : 2px solid black; background-color: rgb(255, 255, 255)"%((self.height - 20)//2))

        self.button_2.setStyleSheet(
            "border-radius : %d; background-color: rgb(0, 0, 0)"%((self.height - 30)//2))
        
        self.button_3.setStyleSheet(
            "border-radius : %d; background-color: rgb(255, 255, 255)"%((self.height - 30)//2))
        self.button_3.setVisible(False)
        
        self.button_1.clicked.connect(self.pushToggle)
        self.button_2.clicked.connect(self.pushToggle)
        self.button_3.clicked.connect(self.pushToggle)

        layout = QGridLayout()
        layout.addWidget(self.button_1, 0, 0, 1, 2)
        layout.addWidget(self.button_2, 0, 0, 1, 1, alignment = Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(self.button_3, 0, 1, 1, 1, alignment = Qt.AlignmentFlag.AlignCenter)
        
        self.setLayout(layout)

    def pushToggle(self):

        self.toggle_on = not self.toggle_on

        match self.toggle_on:
            case True:
                self.button_1.setStyleSheet("border-radius : %s; border : 2px solid black; background-color: rgb(60, 156, 253)"%((self.height - 20)//2))
                self.button_2.setVisible(False)
                self.button_3.setVisible(True)
            case False:
                self.button_1.setStyleSheet("border-radius : %s; border : 2px solid black; background-color: rgb(255, 255, 255)"%((self.height - 20)//2))
                self.button_2.setVisible(True)
                self.button_3.setVisible(False)
        
        self.clicked.emit(self.toggle_on)

使用例

上記スクリプトを「toggle.py」という名前で保存して以下のスクリプトを実行してみて下さい。

from PyQt6.QtCore import pyqtSlot
from PyQt6.QtWidgets import QWidget, QApplication, QLabel, QHBoxLayout
from PyQt6.QtGui import QFont

from toggle import ToggleButton

class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('toggle button sample')

        font = QFont()
        font.setPointSize(72)
        font.setBold(True)
                    
        self.on_off_label = QLabel('off')
        self.on_off_label.setFont(font)

        self.toggle_button = ToggleButton()
        self.toggle_button.clicked.connect(self.handle_clicked)
        
        mainFrame = QHBoxLayout()
        mainFrame.addWidget(self.on_off_label)
        mainFrame.addWidget(self.toggle_button)
        
        self.setLayout(mainFrame)

    @pyqtSlot(bool)
    def handle_clicked(self, on_off):
        match on_off:
            case True:
                self.on_off_label.setText('on')
            case False:
                self.on_off_label.setText('off')
 
if __name__ == "__main__":
    app = QApplication([])
    ex =Window()
    ex.show()
    app.exec()

これで冒頭のようなトグルボタンが使用可能になります。

ポイント

3つのボタンを重ねて作っています。それらをQFrameにまとめました。

すべてのボタンに同じクリックイベントを設定しています。

「pyqtSlot」「pyqtSignal」でクリックを検知しています。

注意点

Pythonに新たに導入された「match」を使用しているためPython 3.10以降でないと動かないと思います。3.9以下のPythonを使う場合にはmatchの部分をif、elseを使って書き換えて下さい。