Zwei Befehle für Button

Fragen zu Tkinter.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Philipp68 hat geschrieben:Hallo,
ich habe einen Button, der die Aktivität einer LED darstellen soll.
Anfangs ist die Farbe des Buttons grün (LED an), nachdem ich einmal den Button geklickt habe, soll er rot werden (LED rot). Beim zweiten Mal, soll dieser wieder grün werden (um wieder LED anzuschalten)
Hier etwas zum herumspielen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
from math import sin, cos, radians

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "LED-Rosette"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 500
APP_HEIGHT = 500

LEDS = 24
LED_GEOMETRY = 20
LED_ON = 'red'
LED_OFF = 'green'
LED_ANGLE_GAP = 360 / LEDS
RADIUS = 200


class LedRosette(tk.Canvas):
    def __init__(self, master=None):
        tk.Canvas.__init__(self, master)
        
        self.angle = 0 

        self.x_center = (APP_WIDTH / 2)
        self.y_center = (APP_HEIGHT / 2)

        self.leinwand = tk.Canvas(self, width=APP_WIDTH, height=APP_HEIGHT)
        self.leinwand.pack()

        for led_nr in range(LEDS):
            xpos, ypos = self.zeigerBewegung()
            button = tk.Button(self, bg=LED_OFF, activebackground=LED_OFF)
            button.place(x=0, y=0, width=LED_GEOMETRY, height=LED_GEOMETRY)
            button.bind('<Button-1>', partial(self.callback, led_nr))
            self.create_window(xpos, ypos, window=button)
            
    def zeigerBewegung(self):
        x = RADIUS * sin(radians(self.angle)) + self.x_center
        y = RADIUS * cos(radians(180 + self.angle)) + self.y_center
        self.angle += LED_ANGLE_GAP
        return x, y

    def callback(self, led_nr, event):
        print('LED-{}'.format(led_nr))
        widget = event.widget
        if widget['bg'] == LED_ON:
            widget['bg'] = LED_OFF
            widget['activebackground'] = LED_OFF
        else:
            widget['bg'] = LED_ON
            widget['activebackground'] = LED_ON
           
 
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.option_add('*highlightThickness', 0)
    LedRosette(app_win).pack()
    app_win.mainloop()


if __name__ == '__main__':
    main()  
Gruss wuf :wink:
Take it easy Mates!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Doch der hat verschiedene Farben für an und aus.
Ja, wo hat der die denn?

- background - ist es wohl nicht
- activebackground - ist es auch nicht
- disabledforeground erst recht nicht
- highlightcolor auch nicht
- highlightbackground auch nicht
- selectcolor ist es auch nicht

mit off sehe ich nur ein offrelief
aber eine Reaktion darauf ist auch nicht zu erkennen - zumindest nicht unter Linux

Der Unterschied zu einem Button ist, dass man da mit selectcolor auch noch die Farbe des Feldes wählen kann, in dem man sein Häkchen setzt, aber das ist auch nicht davon abhängig, ob ein Häkchen gesetzt ist oder nicht!!!
BlackJack

@Alfons Mittelmeyer: `selectcolor` ist es. Und ein Häkchen gibt es nicht mehr wenn man sich das als Schaltfläche anzeigen lässt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: `selectcolor` ist es. Und ein Häkchen gibt es nicht mehr wenn man sich das als Schaltfläche anzeigen lässt.
Ja stimmt, mit indicatoron auf 0 läßt sich das machen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hier noch die Variante mit Checkbuttons:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
from math import sin, cos, radians

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "LED-Rosette"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 500
APP_HEIGHT = 500

LEDS = 24
LED_GEOMETRY = 20
LED_ON = 'red'
LED_OFF = 'green'
LED_ANGLE_GAP = 360 / LEDS
RADIUS = 200

class CbLedRosette(tk.Canvas):
    def __init__(self, master=None):
        tk.Canvas.__init__(self, master)
        
        self.angle = 0 

        self.x_center = (APP_WIDTH / 2)
        self.y_center = (APP_HEIGHT / 2)

        self.canvas = tk.Canvas(self, width=APP_WIDTH, height=APP_HEIGHT)
        self.canvas.pack()
        
        self.dummy_img = tk.PhotoImage(width=1, height=1)
        self.button_states = [False]*LEDS
        
        for led_nr in range(LEDS):
            xpos, ypos = self.place_coords()
            button = tk.Checkbutton(self, bg=LED_OFF, #activebackground=LED_OFF,
                selectcolor='red', indicatoron=0, image=self.dummy_img,
                width=LED_GEOMETRY, height=LED_GEOMETRY, onvalue=1, offvalue=0)
            button.place(x=0, y=0)
            button.bind('<Button-1>', partial(self.callback, led_nr))
            self.create_window(xpos, ypos, window=button)
            
    def place_coords(self):
        x = RADIUS * sin(radians(self.angle)) + self.x_center
        y = RADIUS * cos(radians(180 + self.angle)) + self.y_center
        self.angle += LED_ANGLE_GAP
        return x, y

    def callback(self, led_nr, event):
        print('LED-{}'.format(led_nr))
        
        widget = event.widget
        if widget['bg'] == LED_ON:
            self.button_states[led_nr] = False
            widget['bg'] = LED_OFF
        else:
            self.button_states[led_nr] = True
            widget['bg'] = LED_ON
        print(self.button_states)
           
 
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.option_add('*highlightThickness', 0)
    CbLedRosette(app_win).pack()
    app_win.mainloop()


if __name__ == '__main__':
    main()  
BEMERKUNG: Die Handhabung der Button-Farbe für die verschiedenen Zustände ist schwieriger als bei einem normalen Button. Auch die Festlegung der Checkbutton-Dimension benötigt eine Sonderbehandlung.

Hier nochmals die leicht abgeänderte Variante mit normalen Buttons:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
from math import sin, cos, radians

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "LED-Rosette"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 500
APP_HEIGHT = 500

LEDS = 24
LED_GEOMETRY = 20
LED_ON = 'red'
LED_OFF = 'green'
LED_ANGLE_GAP = 360 / LEDS
RADIUS = 200


class LedRosette(tk.Canvas):
    def __init__(self, master=None):
        tk.Canvas.__init__(self, master)
        
        self.angle = 0 

        self.x_center = (APP_WIDTH / 2)
        self.y_center = (APP_HEIGHT / 2)

        self.canvas = tk.Canvas(self, width=APP_WIDTH, height=APP_HEIGHT)
        self.canvas.pack()
        self.button_states = [False]*LEDS
        
        for led_nr in range(LEDS):
            xpos, ypos = self.place_coords()
            button = tk.Button(self, bg=LED_OFF, activebackground=LED_OFF)
            button.place(x=0, y=0, width=LED_GEOMETRY, height=LED_GEOMETRY)
            button.bind('<Button-1>', partial(self.callback, led_nr))
            self.create_window(xpos, ypos, window=button)
            
    def place_coords(self):
        x = RADIUS * sin(radians(self.angle)) + self.x_center
        y = RADIUS * cos(radians(180 + self.angle)) + self.y_center
        self.angle += LED_ANGLE_GAP
        return x, y

    def callback(self, led_nr, event):
        print('LED-{}'.format(led_nr))
        widget = event.widget
        if widget['bg'] == LED_ON:
            self.button_states[led_nr] = False
            widget['bg'] = LED_OFF
            widget['activebackground'] = LED_OFF
        else:
            self.button_states[led_nr] = True
            widget['bg'] = LED_ON
            widget['activebackground'] = LED_ON
        print(self.button_states)    
           
 
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.option_add('*highlightThickness', 0)
    LedRosette(app_win).pack()
    app_win.mainloop()


if __name__ == '__main__':
    main()  
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hier die Variante mit normalen Buttons von Redundanzen bereinigt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
from math import sin, cos, radians

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "LED-Rosette"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 500
APP_HEIGHT = 500

LEDS = 24
LED_GEOMETRY = 20
LED_ON = 'red'
LED_OFF = 'green'
LED_ANGLE_GAP = 360 / LEDS
RADIUS = 200


class LedRosette(tk.Canvas):
    def __init__(self, master=None, **kwargs):
        tk.Canvas.__init__(self, master, **kwargs)
        
        self.angle = 0 

        self.x_center = (APP_WIDTH / 2)
        self.y_center = (APP_HEIGHT / 2)

        self.button_states = [False]*LEDS
        
        for led_nr in range(LEDS):
            xpos, ypos = self.place_coords()
            button = tk.Button(self, bg=LED_OFF, activebackground=LED_OFF)
            button.place(x=0, y=0, width=LED_GEOMETRY, height=LED_GEOMETRY)
            button.bind('<Button-1>', partial(self.callback, led_nr))
            self.create_window(xpos, ypos, window=button)
            
    def place_coords(self):
        x = RADIUS * sin(radians(self.angle)) + self.x_center
        y = RADIUS * cos(radians(180 + self.angle)) + self.y_center
        self.angle += LED_ANGLE_GAP
        return x, y

    def callback(self, led_nr, event):
        print('LED-{}'.format(led_nr))
        widget = event.widget
        if widget['bg'] == LED_ON:
            self.button_states[led_nr] = False
            widget['bg'] = LED_OFF
            widget['activebackground'] = LED_OFF
        else:
            self.button_states[led_nr] = True
            widget['bg'] = LED_ON
            widget['activebackground'] = LED_ON
        print(self.button_states)    
           
 
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.option_add('*highlightThickness', 0)
    LedRosette(app_win, width=APP_WIDTH, height=APP_HEIGHT).pack()
    app_win.mainloop()


if __name__ == '__main__':
    main()  
Gruss wuf :wink:
Take it easy Mates!
Antworten