Funktionen automatisch erzeugen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Daggett
User
Beiträge: 9
Registriert: Donnerstag 5. April 2018, 22:39

Moin.
Ich habe ein Dictionary mit Namen und zugehörigen Polygonen (tkinter, canvas). Mit tag_bind kann ich über die Maus mit den Polygonen interagieren. Allerdings kann ich nur eine Aktion für alle Elemente festlegen. Ich will aber, dass ich für jedes Polygon eine andere Aktion habe. Also eigentlich die Gleiche, nur mit anderer Ausgabe.
Zu Verdeutlichung:
Ich kann per Mausklick in jedes Feld ein Event aufrufen.
Ich will mit Mausklick in ein spezielles Feld, den entsprechenden Namen asugeben.
Ich kann das für ein Feld programmieren, will das aber nicht für jedes Feld einzeln programmieren, daher die Frage, ob man die event-Funktionen automatisch erzeugen kann.
Ich habe gelesen, aus Listen Funktionen zu erzeugen, sei keine gute Idee. Hat auch nicht funktioniert. Er gibt dann bei jedem Feld den Namen des letzten Eintrages wieder...
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte zeig mal den dazugehörigen Code.

Nach der Beschreibung klingt es, als ob functions.partial dir helfen kann.
Benutzeravatar
Daggett
User
Beiträge: 9
Registriert: Donnerstag 5. April 2018, 22:39

Code: Alles auswählen

from tkinter import *

root = Tk()

riskGame = Canvas(root, width=1200, height=640)

colourNorthAmerica = "yellow"
colourOutline = "black"
widthOutline = 2

locationOf = {
"Alaska"                : riskGame.create_polygon(40,55,70,45,110,55,105,95,125,145,90,110,60,110,25,130,10,100, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Northwest Territory"   : riskGame.create_polygon(110,55,170,50,245,70,285,30,300,75,255,115,225,100,105,95, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Greenland"             : riskGame.create_polygon(320,40,415,5,480,15,470,75,410,125,370,105, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Alberta"               : riskGame.create_polygon(105,95,225,100,220,170,140,170,125,145, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Ontario"               : riskGame.create_polygon(225,100,255,115,300,150,310,195,260,170,220,170, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Quebec"                : riskGame.create_polygon(325,100,360,115,390,155,355,190,310,195,300,150, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Western United States" : riskGame.create_polygon(140,170,245,170,245,220,200,260,180,240,135,240,125,215, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Eastern United States" : riskGame.create_polygon(245,170,260,170,310,195,355,190,290,270,220,280,200,260,245,220, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica),
"Central America"       : riskGame.create_polygon(135,240,180,240,240,300,235,350,165,300, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)
}
Für alle Felder funktioniert Folgendes zwar, allerdings wird in jedem Feld dann "rechter Maus-Button" ausgegeben.

Code: Alles auswählen

def clickRight(event):
    print("rechter Maus-Button")

for location in locationOf.values():
    riskGame.tag_bind(location, "<Button-3>", clickRight)
Jetzt möchte ich aber, dass bei klick in irgendein Feld nicht immer das Gleiche, sondern jeweils der Name des zugehörigen Feldes ausgegeben wird. Hierbei kommt aber immer "Central America" raus.

Code: Alles auswählen

for name in locationOf.keys():
    def clickLeft(event):
        print(name)
    riskGame.tag_bind(locationOf[name], "<Button-1>", clickLeft)
Alternativ kann ich auch das machen, dann muss ich aber für jedes Land (und es gibt noch mehr als die hier) eine einzelne Funktion definieren. Genau das will ich aber umgehen. Ich will am liebsten die Funktionen für alle Länder automatisch generieren.

Code: Alles auswählen

def alaska(event):
    print("This is Alaska")
riskGame.tag_bind(locationOf["Alaska"], "<Button-1>", alaska)

for name in locationOf.keys():
    def territory(event):
        print("This is:", name)
Kann man vielleicht ein Argument an eine event-Funktion übergeben?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja. Mit functools.partial. Schon mal angeschaut?
Benutzeravatar
Daggett
User
Beiträge: 9
Registriert: Donnerstag 5. April 2018, 22:39

HEUREKA!

Es hat mich einen halben Tag gekostet, aber jetzt funktioniert es! Ich musste mein Dictionary etwas umbauen, aber jetzt läuft es!!!

Code: Alles auswählen

rom tkinter import *

root = Tk()

riskGame = Canvas(root, width=1200, height=640)

textOutput = ""
textWindow1 =  Text(root, width=32, height=1)
textWindow1.pack(side=BOTTOM)

colourNorthAmerica = "yellow"
colourOutline = "black"
widthOutline = 2

locationOf = {
0   : ["Alaska", riskGame.create_polygon(40,55,70,45,110,55,105,95,125,145,90,110,60,110,25,130,10,100, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
1   : ["Northwest Territory", riskGame.create_polygon(110,55,170,50,245,70,285,30,300,75,255,115,225,100,105,95, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
2   : ["Greenland", riskGame.create_polygon(320,40,415,5,480,15,470,75,410,125,370,105, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
3   : ["Alberta", riskGame.create_polygon(105,95,225,100,220,170,140,170,125,145, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
4   : ["Ontario", riskGame.create_polygon(225,100,255,115,300,150,310,195,260,170,220,170, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
5   : ["Quebec", riskGame.create_polygon(325,100,360,115,390,155,355,190,310,195,300,150, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
6   : ["Western United States", riskGame.create_polygon(140,170,245,170,245,220,200,260,180,240,135,240,125,215, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
7   : ["Eastern United States", riskGame.create_polygon(245,170,260,170,310,195,355,190,290,270,220,280,200,260,245,220, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
8   : ["Central America", riskGame.create_polygon(135,240,180,240,240,300,235,350,165,300, outline=colourOutline, width=widthOutline, fill=colourNorthAmerica)],
}
UND JETZT KOMMT'S:

Code: Alles auswählen

import functools

def giveName(name, event):
    textWindow1.delete(1.0, END)
    textOutput = "Territory: " + name
    textWindow1.insert(END, textOutput)

listOfGivenNames = []
for i in locationOf:
    f = functools.partial(giveName, locationOf[i][0])
    listOfGivenNames.append(f)

for i in locationOf:
    riskGame.tag_bind(locationOf[i][1], "<Button-1>", listOfGivenNames[i])

riskGame.pack()
riskGame.mainloop()
Whoop! Whoop!

Geiler Typ, deets! Danke für die Hilfe zur Selbsthilfe!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Daggett: Der Umbau war unnötig.

Hier die Anpassung Deines ursprünglichen Programms:

Code: Alles auswählen

def click_right(name, event):
    print("klick auf {}".format(name))

for name, location in locationOf.items():
    riskGame.tag_bind(location, "<Button-3>", functools.partial(click_right, name))
Antworten