Seite 1 von 1

Funktionen automatisch erzeugen

Verfasst: Dienstag 17. April 2018, 08:09
von Daggett
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...

Re: Funktionen automatisch erzeugen

Verfasst: Dienstag 17. April 2018, 08:16
von __deets__
Bitte zeig mal den dazugehörigen Code.

Nach der Beschreibung klingt es, als ob functions.partial dir helfen kann.

Re: Funktionen automatisch erzeugen

Verfasst: Mittwoch 18. April 2018, 06:24
von Daggett

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?

Re: Funktionen automatisch erzeugen

Verfasst: Mittwoch 18. April 2018, 08:11
von __deets__
Ja. Mit functools.partial. Schon mal angeschaut?

Re: Funktionen automatisch erzeugen

Verfasst: Mittwoch 18. April 2018, 14:09
von Daggett
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!

Re: Funktionen automatisch erzeugen

Verfasst: Mittwoch 18. April 2018, 14:34
von Sirius3
@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))