Click Event eines Objektes

Fragen zu Tkinter.
Antworten
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

Hallo, beim Erstellen einer GUI zeichne ich auf ein CANVAS einen Kreis mit kreis1=c.create_oval('2c','2c','3c','3c', fill='', outline='#B6EEEB', activeoutline='blue', activefill ='red', width='2'), den ich jetzt als Button verwenden möchte. Bisher habe ich aber noch keine Idee, wie ich ein click-event dazufügen kann. Geht das überhaupt?
BlackJack

@yellowman: Das geht mit der `tag_bind()`-Methode auf dem `Canvas`-Exemplar.

Was soll die 1 bei `kreis1` bedeuten? Namen zu nummerieren ist ein „code smell“.
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

BlackJack hat geschrieben:@yellowman: Das geht mit der `tag_bind()`-Methode auf dem `Canvas`-Exemplar.

Was soll die 1 bei `kreis1` bedeuten? Namen zu nummerieren ist ein „code smell“.
Ich möchte einen Taschenrechner programmieren. Mit Button sieht das nicht so gut aus, daher zeichne ich 3x4 Kreise für die Buttons 0-9 und "+" und "-"
Wenn ich mit der Maus über einem Button(Kreis) bin, verändert sich dessen Farbe. Jetzt brauche ich nur noch ein click-event. Wenn ich das haben, kann ich auch kreis1 in eins umbenennen. Hast du da eine Idee?
BlackJack

@yellowman: Idee wofür? `tag_bind()` habe ich ja schon erwähnt. Erst schlechte Namen verwenden um die später noch mal richtig zu benennen ist eine komische Vorgehensweise. Was spricht dagegen gleich gute Namen zu wählen? Das macht weniger Arbeit.

Falls man Schwierigkeiten hat einen guten, passenden Namen für einen Wert zu wählen, dann deutet das oft darauf hin, dass man das zu lösende Problem noch nicht komplett verstanden hat, oder die Lösung nicht genug durchdacht hat, oder Daten zu einer Struktur zusammengefasst hat, die so nicht sinnvoll zusammen gehört. Das sind alles Sachen die man eher sofort als später angehen möchte, weil sie einen aufhalten oder gar eine sinnvolle Lösung komplett blockieren und man sich irgendwie verzettelt.

Wobei die Frage ist, ob man für diese ”Buttons” tatsächlich Namen braucht, beziehungsweise ob die tatsächlich unterschiedlich sein müssen. Denn Du kapselst das ja hoffentlich in einer Klasse damit Du nicht zwölf mal gleichen/ähnlichen Code für jede runde Schaltfläche schreiben musst. Falls Du tatsächlich das Verhalten von `Button` nachprogrammieren möchtest, dann ist das vielleicht auch aufwändiger als Du denkst. Denn normalerweise löst eine Schaltfläche nicht aus wenn man die Maustaste drückt, sondern wenn man sie los lässt. Und das auch nur falls man sich beim loslassen noch mit der Maus auf der Schaltfläche befindet.
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

BlackJack hat geschrieben:@yellowman: Idee wofür? `tag_bind()` habe ich ja schon erwähnt. Erst schlechte Namen verwenden um die später noch mal richtig zu benennen ist eine komische Vorgehensweise. Was spricht dagegen gleich gute Namen zu wählen? Das macht weniger Arbeit.

Falls man Schwierigkeiten hat einen guten, passenden Namen für einen Wert zu wählen, dann deutet das oft darauf hin, dass man das zu lösende Problem noch nicht komplett verstanden hat, oder die Lösung nicht genug durchdacht hat, oder Daten zu einer Struktur zusammengefasst hat, die so nicht sinnvoll zusammen gehört. Das sind alles Sachen die man eher sofort als später angehen möchte, weil sie einen aufhalten oder gar eine sinnvolle Lösung komplett blockieren und man sich irgendwie verzettelt.

Du hast Recht, ich habe tatsächlich ohne große Überlegung losprogrammiert und die Sache nicht bis zum Ende durchdacht. Es sind halt meine ersten Gehversuche mit Python, welches ich nach dem Tod von Flash, dann Silverlight und dem sich nicht durchsetzenden WPF, jetzt beruflich Python erlernen soll. Das ist eine rieeesige Umstellung, besonders im Zusammenhang mit den mir jetzt fehlenden guten IDE's von Adobe (Flex/Flash) und, (bitte mich jetzt nicht lynchen), VS.

Wobei die Frage ist, ob man für diese ”Buttons” tatsächlich Namen braucht, beziehungsweise ob die tatsächlich unterschiedlich sein müssen. Denn Du kapselst das ja hoffentlich in einer Klasse damit Du nicht zwölf mal gleichen/ähnlichen Code für jede runde Schaltfläche schreiben musst. Falls Du tatsächlich das Verhalten von `Button` nachprogrammieren möchtest, dann ist das vielleicht auch aufwändiger als Du denkst. Denn normalerweise löst eine Schaltfläche nicht aus wenn man die Maustaste drückt, sondern wenn man sie los lässt. Und das auch nur falls man sich beim loslassen noch mit der Maus auf der Schaltfläche befindet.
Klassen habe ich zum Erstellen der Buttons noch nicht verwendet, aber eine doppelte Schleife. Das Klassenkapitel wird doch durchgearbeitet. Dazu werde ich bestimmt noch Fragen haben. Bis dann
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi yellowman

Hier noch ein bisschen Code zum experimentieren:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]


class CanvasButton(object):
    DISPLACEMENT = 1
    FONT_NAME = ('Helvetica', 20, 'normal')
    COLOR_TEXT = 'brown'
    
    def __init__(self, panel, xpos, ypos, diameter, name, callback=None, **opt):
        self.panel = panel
        self.xpos = xpos
        self.ypos = ypos
        self.diameter = diameter
        self.name = name
        self.callback = callback
        
        self.tag = 'Button-{}'.format(name)
        radius = diameter / 2
        coords = (xpos-radius, ypos-radius, xpos+radius, ypos+radius)
        self.panel.create_oval(coords, tags=self.tag, **opt)
        self.panel.create_text(xpos, ypos, text=name, font=self.FONT_NAME,
            fill=self.COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', partial(
            self.press_button))
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', partial(
            self.release_button))
        self.panel.tag_bind(self.tag, '<Enter>', partial(self.cursor_on))
        self.panel.tag_bind(self.tag, '<Leave>', partial(self.cursor_off))

    def press_button(self, event):
        self.panel.move(self.tag, self.DISPLACEMENT, self.DISPLACEMENT)
        self.button_callback()
        
    def release_button(self, event):
        self.panel.move(self.tag, -self.DISPLACEMENT, -self.DISPLACEMENT)
    
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self)
        self.canvas.pack(fill='both', expand=True)

        # Button-Options
        opt = dict(fill='khaki3', outline='blue', activeoutline='red',
            activefill ='khaki1', width=1)    
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        diameter = 60
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, diameter, name,
                    self.button_callback, **opt)
                xpos += xgap
            xpos = xorg
            ypos += ygap


    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Wenn du nicht alles verstehst musst du vielleicht noch einmal in die Bücher gucken! Noch viel Spass!

Gruss wuf :wink:
Take it easy Mates!
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

wuf hat geschrieben:Hi yellowman

Hier noch ein bisschen Code zum experimentieren:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]


class CanvasButton(object):
    DISPLACEMENT = 1
    FONT_NAME = ('Helvetica', 20, 'normal')
    COLOR_TEXT = 'brown'
    
    def __init__(self, panel, xpos, ypos, diameter, name, callback=None, **opt):
        self.panel = panel
        self.xpos = xpos
        self.ypos = ypos
        self.diameter = diameter
        self.name = name
        self.callback = callback
        
        self.tag = 'Button-{}'.format(name)
        radius = diameter / 2
        coords = (xpos-radius, ypos-radius, xpos+radius, ypos+radius)
        self.panel.create_oval(coords, tags=self.tag, **opt)
        self.panel.create_text(xpos, ypos, text=name, font=self.FONT_NAME,
            fill=self.COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', partial(
            self.press_button))
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', partial(
            self.release_button))
        self.panel.tag_bind(self.tag, '<Enter>', partial(self.cursor_on))
        self.panel.tag_bind(self.tag, '<Leave>', partial(self.cursor_off))

    def press_button(self, event):
        self.panel.move(self.tag, self.DISPLACEMENT, self.DISPLACEMENT)
        self.button_callback()
        
    def release_button(self, event):
        self.panel.move(self.tag, -self.DISPLACEMENT, -self.DISPLACEMENT)
    
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self)
        self.canvas.pack(fill='both', expand=True)

        # Button-Options
        opt = dict(fill='khaki3', outline='blue', activeoutline='red',
            activefill ='khaki1', width=1)    
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        diameter = 60
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, diameter, name,
                    self.button_callback, **opt)
                xpos += xgap
            xpos = xorg
            ypos += ygap


    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Wenn du nicht alles verstehst musst du vielleicht noch einmal in die Bücher gucken! Noch viel Spass!

Gruss wuf :wink:
Vielen Dank, das sieht schon sehr vielversprechend aus. Natürlich lese ich mich da noch rein. Der Code gibt mir wichtige Infos und Anregungen, (noch) nicht verstandenes nachzulesen. Aber nicht heute. Meine Daumen hier in München brauche ich für Bayern :D
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@wuf: ein paar Anmerkungen zu Deinem Code:

Zeile 4, 248ff: partial wird nicht wirklich gebraucht. Ein partial-Aufruf, bei dem kein Argument mitgegeben wird, kann man genausogut weglassen.
Zeile 9: ein nacktes except sollte man nie benutzen, hier brauchst Du nur ImportError abfangen.
Zeile 33: eine Instanz mit callback=None produziert einen Fehler beim Mausclick, der Defaultwert ist also nicht sinnvoll. Weg damit.
Zeile 35ff: die Attribute xpos, ypos und diameter werden nicht gebraucht.
Zeiel 57: wie BlackJack schon geschrieben hat, ist das erwartete Verhalten, dass erst beim Loslassen der Maus über dem Kreis der Callback ausgelöst wird.
Zeile 82: Wenn Du die Variable gleich button_options nennst, sparst Du Dir einen Kommentar.
Zeile 87, 91f: wann Du Konstanten am Anfang des Programms definierst und wann mittendrin, ist mir unklar.
Zeile 88, 99: Variablen sollten dann Initalisiert werden, wenn sie gebraucht werden, bei xpos also einmal vor der inneren for-Schleife.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@ Sirius3: Besten Dank für deine wertvollen Anmerkungen. Habe diese in mein Skript einfliessen lassen.

Hier mein aktualisiertes Skript:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]

DISPLACEMENT = 1
FONT_NAME = ('Helvetica', 20, 'normal')
COLOR_TEXT = 'brown'

class CanvasButton(object):
    
    def __init__(self, panel, xpos, ypos, diameter, name, callback=None, **opt):
        self.panel = panel
        self.name = name
        self.callback = callback
        
        self.tag = 'Button-{}'.format(name)
        radius = diameter / 2
        coords = (xpos-radius, ypos-radius, xpos+radius, ypos+radius)
        self.panel.create_oval(coords, tags=self.tag, **opt)
        self.panel.create_text(xpos, ypos, text=name, font=FONT_NAME,
            fill=COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', self.press_button)
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', self.release_button)
        self.panel.tag_bind(self.tag, '<Enter>', self.cursor_on)
        self.panel.tag_bind(self.tag, '<Leave>', self.cursor_off)

    def press_button(self, event):
        self.panel.move(self.tag, DISPLACEMENT, DISPLACEMENT)
        
    def release_button(self, event):
        self.panel.move(self.tag, -DISPLACEMENT, -DISPLACEMENT)
        self.button_callback()
        
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        if self.callback != None:
            self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self)
        self.canvas.pack(fill='both', expand=True)

        button_options = dict(fill='khaki3', outline='blue', activeoutline='red',
            activefill ='khaki1', width=1)    
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        diameter = 60
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            xpos = xorg
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, diameter, name,
                    self.button_callback, **button_options)
                xpos += xgap
            ypos += ygap


    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

Hallo, Python zu lernen ist ganz bestimmt kein Fehler. Wie ich in obigen Postings gesehen habe -vielen Dank dafür- muss ich noch einiges lernen. Angenommen, ich bin etwas sicherer in der Programmierung, dann stellt sich für mich die Frage, was wird in der Praxis häufiger verlangt Kleiner GUI’s mit tkinter oder eher mit PyQt/PySide? Im Zusammenhang mit C++ wurde vor Jahren in unsere Firma über den Einsatz von Qt diskutiert, aber aufgrund der Linzenspolitik von Qt wurde dieses Framework nicht genommen. Hier ist zwar nicht das Qt-Forum, daher ganz kurz: Daumen hoch oder eher nicht?
BlackJack

@yellowman: Ich denke so ganz allgemein kann man da nichts zu sagen, da fehlen die (öffentlich zugänglichen) Daten zu. Tk hat den Vorteil zur Python-Standardbibliothek zu gehören. Es ist allerdings was die Auswahl der Widgets angeht, eher beschränkt. Man sollte sich IMHO vorher überlegen ob Tk für die konkrete Anwendung ausreicht und dann entscheiden.
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

wuf hat geschrieben:@ Sirius3: Besten Dank für deine wertvollen Anmerkungen. Habe diese in mein Skript einfliessen lassen.

Hier mein aktualisiertes Skript:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]

DISPLACEMENT = 1
FONT_NAME = ('Helvetica', 20, 'normal')
COLOR_TEXT = 'brown'

class CanvasButton(object):
    
    def __init__(self, panel, xpos, ypos, diameter, name, callback=None, **opt):
        self.panel = panel
        self.name = name
        self.callback = callback
        
        self.tag = 'Button-{}'.format(name)
        radius = diameter / 2
        coords = (xpos-radius, ypos-radius, xpos+radius, ypos+radius)
        self.panel.create_oval(coords, tags=self.tag, **opt)
        self.panel.create_text(xpos, ypos, text=name, font=FONT_NAME,
            fill=COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', self.press_button)
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', self.release_button)
        self.panel.tag_bind(self.tag, '<Enter>', self.cursor_on)
        self.panel.tag_bind(self.tag, '<Leave>', self.cursor_off)

    def press_button(self, event):
        self.panel.move(self.tag, DISPLACEMENT, DISPLACEMENT)
        
    def release_button(self, event):
        self.panel.move(self.tag, -DISPLACEMENT, -DISPLACEMENT)
        self.button_callback()
        
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        if self.callback != None:
            self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self)
        self.canvas.pack(fill='both', expand=True)

        button_options = dict(fill='khaki3', outline='blue', activeoutline='red',
            activefill ='khaki1', width=1)    
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        diameter = 60
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            xpos = xorg
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, diameter, name,
                    self.button_callback, **button_options)
                xpos += xgap
            ypos += ygap


    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
yellowman
User
Beiträge: 9
Registriert: Montag 11. April 2016, 07:16

yellowman hat geschrieben:
wuf hat geschrieben:@ Sirius3: Besten Dank für deine wertvollen Anmerkungen. Habe diese in mein Skript einfliessen lassen.

Hier mein aktualisiertes Skript:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]

DISPLACEMENT = 1
FONT_NAME = ('Helvetica', 20, 'normal')
COLOR_TEXT = 'brown'

class CanvasButton(object):
    
    def __init__(self, panel, xpos, ypos, diameter, name, callback=None, **opt):
        self.panel = panel
        self.name = name
        self.callback = callback
        
        self.tag = 'Button-{}'.format(name)
        radius = diameter / 2
        coords = (xpos-radius, ypos-radius, xpos+radius, ypos+radius)
        self.panel.create_oval(coords, tags=self.tag, **opt)
        self.panel.create_text(xpos, ypos, text=name, font=FONT_NAME,
            fill=COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', self.press_button)
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', self.release_button)
        self.panel.tag_bind(self.tag, '<Enter>', self.cursor_on)
        self.panel.tag_bind(self.tag, '<Leave>', self.cursor_off)

    def press_button(self, event):
        self.panel.move(self.tag, DISPLACEMENT, DISPLACEMENT)
        
    def release_button(self, event):
        self.panel.move(self.tag, -DISPLACEMENT, -DISPLACEMENT)
        self.button_callback()
        
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        if self.callback != None:
            self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self)
        self.canvas.pack(fill='both', expand=True)

        button_options = dict(fill='khaki3', outline='blue', activeoutline='red',
            activefill ='khaki1', width=1)    
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        diameter = 60
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            xpos = xorg
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, diameter, name,
                    self.button_callback, **button_options)
                xpos += xgap
            ypos += ygap


    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Hallo, der Rechner sieht wirklich schön aus. Auch das mit dem Mauszeiger ist sehr lehrreich. Jetzt muss ich nur den Code noch verstehen lernen. Vielen Dank auch an die anderen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi yellowman

Um das Ganze noch ein wenig aufzupeppen kannst du natürlich die 'oval'-Canvas-Objekte für die grafische Darstellung der Schaltfächen durch eigene 'image'-Canvas-Objekte ersetzen. Im folgenden modifizierten Skript habe ich 60x60 pixel 'gif'-Bilddaten im Base64-Format für die grafische Schaltflächen verwende. (Sorry betreffs meiner verrückten Farbenwahl)

Hier mein angepasstes Skript:

Code: Alles auswählen

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

from functools import partial

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

APP_TITLE = "Canvas Button"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 230
APP_HEIGHT = 360

BUTTON_NAMES = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
    ['0', '+', '-'],
    ['x', '/', '.']
    ]

DISPLACEMENT = 1
FONT_NAME = ('Helvetica', 20, 'normal')
COLOR_TEXT = 'brown'
BUTTON_IMAGE = 'ButtonImage_01.gif'
ACTIVE_BUTTON_IMAGE = 'ActiveButtonImage_01.gif'

# Base64 Bildkonstanten
button_image_b64 =\
'''
R0lGODlhPAA8AKUgAEaRPUiVPkmWP0qZQEycQUydQk2fQk6gQ0+hRE+jRFCk
RVGnRlKoR1OrSFStSFWvSlaxSleyS1izTFm0TVy1UGC3VGG3VmS5WGW5Wma6
W2m7Xmq8X2u8YW29Ym69ZG++Zf//////////////////////////////////
////////////////////////////////////////////////////////////
/////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBHSU1Q
ACH5BAEKACAALAAAAAA8ADwAAAb+QJBwSCwaix6OkrNpHp/QqFToqSY3mmw2
w+1mpuCwtcPZei9oSxqdDruRVmwGQ79Y7pW8Xn/vv8VVZVwYdngUh4iJiol/
UYEag30VixQTlJeNRx8ecoQWeYmWExMSEqOjl4yZVFWQGYahoxIRtLWnp6kT
mVVyhYqns7XCtKa3uKgUEX+8kHaTocHD0rQQxcaHlg9uvFyw2BPT4cPGxhEO
YhvdFrHR4u7W5dpTSeqxEO74wvCjEQ/yUK0y2EF0Kp9BYQVrPWgAZYOHZuu+
gTtIkZiwhQyecJrzieDEiiAVLjyyoQyGjt9CqlToQIERQXc8rlzpz0FGIhrS
DSR4b2b+SH8LExARdOFZpXY+KQJt4HIIpJMyk6qs2RTElpjYpNJ80BKBkCwn
n5HSOpUrA6FWBUasRLaszaaQ1vJrCxIoA7hQsSGlm68mUxBcdrLlW/ftgW5i
9xLG5++ugQuvxC4uzLTAhbyDJx9srICAmohjNW9+cNezXMWipflrsCDBAKxH
U/dduODAa6NzZYszW3sAiFi63ZlVcEAIu+DTat4t/tvjR+Qi7yIwYFwidNUN
pBMQYknic+RcsxMXMERUwuv9SLemXr4c+tXLtw+pdgu1ZuVnDZAn8sC+7Mbx
GeFPBN/pBp8CCRywXxEOoJfeW8TJZ4QDDjxwnVnLGRAAFAzUAGXhfzbdlaBv
UXQ4YGoYIniAhCVW6CFh+LW2YhgKMODii2TFmCABG4aRAAMNcOXhhzP5xYCI
Ky4YxgELHEnhkFs5kB2SBCjpxgE12vgkUHVxFaICxK3Y4yoJZNlAkDeeGI6H
Zx4powEkrjLEAWUeCWQDaVr4oZ5GMrAAmAckKacRBNCZpZ14blkThXbepeIB
cI45aBGFlvlno2dmaieYYCa44gCSTnoEAQYEyimnTZ6aAAKBGsBjqKJGMQCp
gdZqq6sEDCAAALEOKkAAwAYAwLC9BgEAOw==
'''
active_button_image_b64 =\
'''
R0lGODlhPAA8AIQdAPXVNvXWPPXXPvXYQvXYRvXZSPbZSfbaS/baT/bbUfbb
U/bcVfbdW/fdXvfeYPfeYvffZPffZvffaPfgavfhcPjidfjjd/jje/jkffjk
f/jlgfjlg/jlhf///////////yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEK
AB8ALAAAAAA8ADwAAAX+4CeOZGmWW6au2em+cCxudJph+HVZfG/JwGBNc9v5
KkhKEpkMOlG1jJFXoViv2Kz1KaRJe9XrZEwum8tcmHeKPU8i7nj6xEkZw5Ry
RBKJQCB9fRIScWNzIzUYPGJ6fRAPkJGBgXF8c2sWYWaBj5GekICTlH1jD1yY
mmR8nZ+tkA6hooN7DU5ei1aqfa68n6KiDwxCGbiNrL3IscC1MinFZH0OyNOe
yrsNzC80O1XQu9Tgkt+QDcIuGRvceWOB4e6Rx+ULLs4WuewR7/qf2OYlKjvu
vcm3ryA5BglM3LC3bqBBg/3mkcBArNsYPtIe7sNWDgGJLxZXaSzIEeHERd7+
RkIsl1DEBUUCCarcyPKACAwB1/mZSVKexw/qoPHsyWBBy4Aph+rjaNSlvYs7
lb7rZ5JKQ5lS3clLcOBZ1KxaGxg1UIEhO7BLGSAsUPYq2qliExBQovPY22nY
jM69avcur34KEAyI2ddvK8AHBl/FatiVPAWJPzRqjGyrTclQv1L2FJGriEaM
Nz/Iy9XAZ3yhRVsmIAIOoUmiI5UrylXACDiwY5MTG9j0bWC6Ox9gPQLWpMJ3
Iy5AYMA2iQbIG+c1OtwEtgep/XZGcMB5CQa6R2/lStyE2gax5VFv/mIBR/SG
1SfgPiCG++vaixrlXh7GAgbvwaeUcoFVB0QC/wWlKKBKBPLnnQwIJAjgeyNR
tcB+wz0IxAEKXHgehUTpN1+GcxyA4H8f4heWWhcmwBWJh3yAwInnTchRZSXp
V6AB9cU4wgEzXoiijdfBh16OFyrg4gEw+jgCAUCeKKRaKc6mX4sjHsBjAE6e
AOWMSgo5JItYusjdcANo2GUJBBjApItwJtBhnGdqSYAAaq7pwgBtMunnnwYQ
QECaAOgZI56IAqConiEAADs=
'''

class CanvasButton(object):
    
    def __init__(self, panel, xpos, ypos, name, callback=None):
        self.panel = panel
        self.name = name
        self.callback = callback
        
        # Als Dateidaten einlesen
        #self.button_image = tk.PhotoImage(file=BUTTON_IMAGE)
        #self.active_button_image = tk.PhotoImage(file=ACTIVE_BUTTON_IMAGE)
        
        # Als Base64-Daten aus Konstante einlesen
        self.button_image = tk.PhotoImage(data=button_image_b64)
        self.active_button_image = tk.PhotoImage(data=active_button_image_b64)
        
        self.tag = 'Button-{}'.format(name)

        self.panel.create_image(xpos, ypos, image=self.button_image,
            activeimage=self.active_button_image, tags=self.tag)
        self.panel.create_text(xpos, ypos, text=name, font=FONT_NAME,
            fill=COLOR_TEXT, state='disabled', tag=self.tag)
        
        self.panel.tag_bind(self.tag, '<Button-1>', self.press_button)
        self.panel.tag_bind(self.tag, '<ButtonRelease-1>', self.release_button)
        self.panel.tag_bind(self.tag, '<Enter>', self.cursor_on)
        self.panel.tag_bind(self.tag, '<Leave>', self.cursor_off)

    def press_button(self, event):
        self.panel.move(self.tag, DISPLACEMENT, DISPLACEMENT)
        
    def release_button(self, event):
        self.panel.move(self.tag, -DISPLACEMENT, -DISPLACEMENT)
        self.button_callback()
        
    def cursor_on(self, event):
        self.panel.config(cursor='hand1')
    
    def cursor_off(self, event):
        self.panel.config(cursor='arrow')

    def button_callback(self):
        if self.callback != None:
            self.callback(self.name)
        
        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
 
        # Button panel
        self.canvas = tk.Canvas(self, bd=4, relief='raised',
            highlightthickness=0)
        self.canvas.pack(fill='both', expand=True)
        
        # Create the buttons and place them as array
        xorg, yorg = 50, 50
        xpos = xorg
        ypos = yorg
        xgap = 65
        ygap = 65
        
        for row in BUTTON_NAMES:
            xpos = xorg
            for name in row:
                CanvasButton(self.canvas, xpos, ypos, name,
                    self.button_callback)
                xpos += xgap
            ypos += ygap

    def button_callback(self, name):
        print(name)

        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Antworten