是否可以在 tkinter 中创建切换按钮?

Is it posible to create toggle switch button in tkinter?

我想做一个切换按钮来改变GUI中的主题,不知道是否可以实现类似于下图的东西?

除了使用像这样的“缩放”小部件之外,还有更好的方法吗?

from tkinter import *

window = Tk()
s1 = Scale(window, from_=0, to=1, orient=HORIZONTAL)
s1.pack()

mainloop()

您可以使用 Canvas 创建自定义小部件形状。如果您想重用它,您可能想通过继承 Canvas class 来创建一个单独的 class。

我创建了一个类似的拨动开关。您可以进一步改进。 (注意:您不能使用我创建的 class 的图像,但您可以更改颜色)

from tkinter import *

class ToggleButton(Canvas):
    def __init__(self, root, command=None, fg='black', bg='gray', *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.configure(width=100, height=50, borderwidth=0, highlightthickness=0)
        self.root = root
        
        self.back_ground = self.create_arc((0, 0, 0, 0), start=90, extent=180, fill=bg, outline='')
        self.back_ground1 = self.create_arc((0, 0, 0, 0), start=-90, extent=180, fill=bg, outline='')
        self.rect = self.create_rectangle(0, 0, 0, 0, fill=bg, outline='')
        
        self.btn = self.create_oval(0, 0, 0, 0, fill=fg, outline='')

        self.bind('<Configure>', self._resize)
        self.bind('<Button>', self._animate, add='+')  
        self.bind('<Button>', command, add='+')

        self.state = 0

    def _resize(self, event):
        

        self.coords(self.back_ground, 5, 5, event.height-5, event.height-5)
        self.coords(self.back_ground1, 5, 5, event.height, event.height-5)
       
        factor = event.width-(self.coords(self.back_ground1)[2]-self.coords(self.back_ground1)[0])-10
        self.move(self.back_ground1, factor, 0)

        self.coords(self.rect, self.bbox(self.back_ground)[2]-2, 5, self.bbox(self.back_ground1)[0]+2, event.height-5)

        
        self.coords(self.btn, 5, 5, event.height-5, event.height-5)

        if self.state:
            self.moveto(self.btn, self.coords(self.back_ground1)[0]+4, 4)
                
    
    def _animate(self, event):
        x, y, w, h = self.coords(self.btn)
        x = int(x-1)
        y = int(y-1)
        
        
        if x == self.coords(self.back_ground1)[0]+4:
            self.moveto(self.btn, 4, 4)
            self.state = 0
            
        else:
            self.moveto(self.btn, self.coords(self.back_ground1)[0]+4, 4)
            self.state = 1
    
    def get_state(self):
        return self.state

#Your own function
def hello(event='Nooo'):
    print(event)
    if bool(btn.get_state()):
        print('State is 1')

    elif not bool(btn.get_state()):
        print('State is 0')
    
root = Tk()


btn = ToggleButton(root, lambda _:hello('Hello'), 'red', 'green')
btn.pack()

btn2 = ToggleButton(root, command=hello)
btn2.pack(expand=True, fill='both')

Button(root, text='Text').pack(expand=True, fill='both')

root.mainloop() 

使用方法:

  • 使用此小部件就像使用任何其他小部件一样。
  • 要获取开关的状态,您可以使用 get_state() 方法
  • 当椭圆在右边时开关的状态为1,当椭圆在左边时开关的状态为0。

*(注意:您仍然可以使用 Canvas 小部件的方法。如果您不需要它们,请重写这些方法并提供 pass

FWIW,JacksonPro 的回答很好,尽管有一个差一错误——在 _animate 函数中,它应该是

if x == self.coords(self.back_ground1)[0]+3:
            self.moveto(self.btn, 4, 4)
            self.state = 0

谢谢!