bind und Mausklicks

Fragen zu Tkinter.
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

Mein Problem ist: Ich mache einen Abakus(von vielen als rechenbrett bezeichnet) und ich will, das wenn man auf eine perle(im programm als newp bezeichnet) klickt, die perle ein stückchen nach oben verschoben wird.theoretisch alles klar, jedoch praktisch wills nicht.es hakt an dem bind, das ich der bezüglichen perle zuordne.ich hoffe ihr helft mir weiter.
p.s.:das auskommentierte macht probleme.
niko

der code:

Code: Alles auswählen

from Tkinter import *
root = Tk()
root.title("Abakus")
cv = Canvas(root,height=450,width=650)
cv.pack()
perle = {}
usingIDLE = 0

r = 30
for x in range(10):
	for y in range(10):
                newp= "p"+str(x)+str(y)+" = cv.create_oval(32+"+str(x)+"*"+str(r)+"+"+str(x)+"*"+str(r)+", 32+"+str(y)+"*"+str(r)+", 32+("+str(x)+"+1)*"+str(r)+"+"+str(x)+"*"+str(r)+", 32+("+str(y)+"+1)*"+str(r)+",fill='green',outline='grey',)"
                print newp
                exec newp
                #newb="p"+str(x)+str(y)+".bind('<Button-1>',schieb("+str(x)+","+str(y)+"))"
                #print newb
                #exec newb
                cv.create_line(47+x*r+x*r, 2, 47+x*r+x*r, 332, width=3,)
		cv.create_text(47+x*r+x*r,352,text = "0")

quit = Button(root, text="Beenden", width=6, command=root.destroy)
quit.pack(side="right")

### Aktion:Kugel nach oben schieben.
def schieb(xc,yc):
	cv.coords(perle[(xc,yc)],32+xc*r+xc*r, 32+yc*r, 32+(xc+1)*r+xc*r, 32+(yc-1)*r)


root.focus_force()
if not usingIDLE:
	root.mainloop()
Es gibt diejenigen, die angeln, und diejenigen, die nur das Wasser trüben.
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

bitte bitte helft mir, das ist echt wichtig.Das Programm ist für meine Facharbeit und in einer Woche ist Abgabetermin.
:(
Ich wäre euch echt sehr dankbar.
niko
p.s.:wenn ihr aus der problembeschreibung nicht schlau werdet, dann schreibt bitte.
oenone
User
Beiträge: 75
Registriert: Mittwoch 27. August 2003, 14:39
Wohnort: 49°17'28N, 8°15'57E
Kontaktdaten:

niko hat geschrieben:bitte bitte helft mir, das ist echt wichtig.Das Programm ist für meine Facharbeit und in einer Woche ist Abgabetermin.
tipp von mir:
fang naechstes mal frueher an und informiere dich genauer darueber was du machen willst.

aber hier zu fragen, wer deine hausaufgaben macht ist ein wenig realitaetsfern.

auf bald
oenone

ps: nimm es nicht zu persoehnlich.
if you don't remember something, it never happened.
if you aren't remembered, you never existed.
i don't quite understand what love is like... but if there was someone who liked me, i'd be happy.
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

hi oenone,
also es ist ja nicht so, dass ich nicht früh genug angefangen hab.ich hab schon im Oktober angefangen.Ich musste erst Python lernen und hab sämtiche Bücher durchgearbeitet.Der theoretische Teil der Facharbeit ist ja auch längst gemacht.
Es soll ja keiner für mich die Hausaufgaben machen, aber wenn ich einfach nicht weiterkomme und in keiner einzigen Dokumentation steht etwas darüber, was soll ich dann machen?Es soll ja keiner das Programm für mich schreiben. Es geht lediglich um ein kleines Problem, das mich aber daran hindert weiterzuprogrammieren. Ic hoffe ich habe das klargestellt.
p.s.:ich versteh deine sicht und nehme es nicht zu persönlich.
mfg
niko
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi niko,

ich wollte gerade das script testen, aber leider kommt da gleich eine Fehlermeldung:

Code: Alles auswählen

fritz@seneca:~/Python/Beispiele$ python abakus.py
  File "abakus.py", line 33
    cv.create_text(47+x*r+x*r,352,text = "0")
                                            ^
IndentationError: unindent does not match any outer indentation level
also ich hab jetzt echt keine Lust Deine Einrückungen zu bearbeiten. Bring erstmal Deinen Code in Ordnung dann sehen wir weiter.


Gruß

Dookie

P.S.: Bei Python hat es sich eingebürgert, daß Einrückungen aus 4 Spaces bestehen. keine Tabs und eine Zeile hat nicht mehr als 79 Zeichen.
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

Danke dookie, dass du dich überhaupt der sache angenommen hast.
also es ist folgendermaßen:
erst hatte ich es so, dass ich alle perlen in einem dictionary hatte.ich habe also jeder perle einen namen zugewiesen, z.B. perle(0,1) usw... Jedoch glaube ich nicht,dass ein dictionary hier richtig ist. Denn jetzt muss ich ja jedem perle(x,y) bei einem mausklick auf perle(x,y) die Funktion "schieb" zuweisen. Und genau da hängts. Also habe ich mir gedacht ich mache es folgendermaßen:

newp= "p"+str(x)+str(y)+" = cv.create_oval(32+"+str(x)+"*"+str(r)+"+"+str(x)+"*"+str(r)+", 32+"+str(y)+"*"+str(r)+", 32+("+str(x)+"+1)*"+str(r)+"+"+str(x)+"*"+str(r)+", 32+("+str(y)+"+1)*"+str(r)+")"

exec newp

das ergebnis ist das gleiche wie beim dictionary; es läuft zwar, aber es ist zum einen viel länger als 79 Zeichen und zum anderen weiß ich auch hier nicht, wie ich "schieb" anbinden soll.

also ist es wohl ein grundlegendes Problem.

ich habe alles nochmal verbessert(alle Zeilen weniger als 79 Zeichen, keine Tabs usw. und ich hoffe es läuft jetzt bei dir dookie.

das ist die dictionary-Variante, die sollte 100% laufen:

Code: Alles auswählen

from Tkinter import *
root = Tk()
root.title("Abakus")
cv = Canvas(root,height=450,width=650)
cv.pack()
perle = {}
usingIDLE = 0

r = 30   # Durchmesser der Perle
s = 32   # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen 
for x in range(10):
	for y in range(10):
		q = x*r  # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen
		perle[(x,y)]=cv.create_oval(s+q+q,s+y*r,s+(x+1)*r+q,s+(y+1)*r)
		cv.create_line(47+x*r+x*r,2,47+x*r+x*r,332,width=3)
		cv.create_text(47+x*r+x*r,352,text = "0")
		
### Aktion:Kugel nach oben schieben.
def schieb(xc,yc):
	cv.coords(perle[(xc,yc)],32+xc*r+xc*r,32+yc*r,32+(xc+1)*r+xc*r,32+(yc-1)*r)
#perle[(x,y)].bind("<Button-1>", lambda:schieb(x,y))
quit = Button(root, text="Beenden", width=6, command=root.destroy)
quit.pack(side="right")

root.focus_force()
if not usingIDLE:
	root.mainloop()

Mfg
Niko
Es gibt diejenigen, die angeln, und diejenigen, die nur das Wasser trüben.
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi niko,

das schaut schon besser aus.
Über die Fehlermeldung bin ich dann auch schnell auf das Problem gestossen.
create_oval(..) vom Canvaswidget gibt nur eine ID(Integer) auf das Oval zurück. Dem kannst Du natürlich keine Action zuweisen. Du musst also an das Canvaswidget die action mittels Bind zuweisen und in dieser anhand der Mausposition die Perle bestimmen die verschoben werden soll.


Gruß

Dookie
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
Dookie hat geschrieben:Dem kannst Du natürlich keine Action zuweisen. Du musst also an das Canvaswidget die action mittels Bind zuweisen und in dieser anhand der Mausposition die Perle bestimmen die verschoben werden soll.
Ganz so aufwändig ist das nicht. Man kann mit der Canvas-Methode tag_bind() den Canvas-Items auch direkt Events zuweisen.
Jan
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

Vielen Dank Dookie und Voges.
Also ich habe nach dem letzten Posting auch so ungefähr die Idee gehabt wie Dookie es vorgeschlagen hat.
Aber das was Voges sagt sollte,wenn es geht,leichter sein.

Meinst du, wenn die Perle z.B. perle(2,1) ist, dann kann ich ihr einfach mittels
perle(2,1)_bind()
das zuweisen oder wie sieht das konkret aus, wenn die Funktion für's Verschieben schieb() ist?

so etwa?

perle(2,1)_bind("<Button1>", schieb)

Auf jeden Fall vielen Dank an euch beide.
Mfg
Niko
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

wenn dann müsste das
canvas.tag_bind(perle(2,1),"<Button1>", schieb) heissen

Dookie
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

also ich bin enttäuscht das sagen zu müssen, aber es geht immer noch nicht. ich hab das mit tag_bind in allen Variationen ausprobiert. doch nichts zu machen. ich werde wohl doch die kompliziertere lösung machen müssen. oder weiß jemand weiter?
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
niko hat geschrieben:also ich bin enttäuscht das sagen zu müssen, aber es geht immer noch nicht.
Was geht nicht? Konkrete Infos brauchen wir schon. Egal, das Folgende sollte in etwa das tun, was Du wohl wolltest:

Code: Alles auswählen

from Tkinter import *
root = Tk()
root.title("Abakus")
cv = Canvas(root,height=450,width=650)
cv.pack()
perle = {}
usingIDLE = 0

### Aktion:Kugel nach oben schieben.
def schieb(xc,yc):
   cv.coords(perle[(xc,yc)],32+xc*r+xc*r,32+yc*r,32+(xc+1)*r+xc*r,32+(yc-1)*r)

r = 30   # Durchmesser der Perle
s = 32   # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen
for x in range(10):
    for y in range(10):
        q = x*r  # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen
        perle[(x,y)]=cv.create_oval(s+q+q,s+y*r,s+(x+1)*r+q,s+(y+1)*r,fill='green',outline='grey',)
        cv.tag_bind(perle[(x,y)],"<Button-1>", lambda e,X=x,Y=y:schieb(X,Y))
            
quit = Button(root, text="Beenden", width=6, command=root.destroy)
quit.pack(side="right")

root.focus_force()
if not usingIDLE:
   root.mainloop()
hth
Jan

BTW: Zumindest für mich gilt: Je weniger ein Beitrag sich an den Regeln der dt. Schriftsprache orientiert, desto weniger bin ich zur Hilfe bereit.
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

Danke Voges!!
Die Perlen lassen sich verschieben.Dafür vielen dank. Jedoch lassen sie sich nur einmal verschieben. entweder liegt das an der Funktion schieb selbst oder daran, dass er die Koordinaten nicht richtig speichert. Außerdem bewegt sich die Perle beim Klick auf das Stäbchen auch nicht. Kann man die Stäbchen irgendwie in den Hintergrund verbannen?

Mfg
Niko
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
niko hat geschrieben:Jedoch lassen sie sich nur einmal verschieben.
Wenn Du z.B. die Perle perle[(2,5)] anklickst, verschiebst Du sie ja relativ zu 5*r nach oben, und zwar um 32 Pixel. Aber die Perle heißt dann immer noch perle[(2,5)], obwohl sie sich ja jetzt auf der Position (2,4) befindet. Wenn Du jetzt nochmal auf die selbe Perle klickst, rechnest Du wieder 5*r + 32, aber da ist sie ja schon und tritt somit auf der Stelle.

Ich hätte das ganze nicht als 10 x 10 Perlen realisiert, sondern als 11 x 10 mögliche Perlenplätze, wovon die unteren 10 Zeilen am Anfang gefüllt sind und die obere eben leer. Beim Klick auf einen Perlenplatz müsste man dann nur gucken, ob da eine Perle ist und ob dadrüber keine ist. Dann kann man "verschieben".
niko hat geschrieben:Außerdem bewegt sich die Perle beim Klick auf das Stäbchen auch nicht. Kann man die Stäbchen irgendwie in den Hintergrund verbannen?
Die Stangen zuerst zeichnen, damit sie von den Perlen verdeckt werden. Entspricht ja auch der 'Natur'.
Jan
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Niko

Hier eine mögliche Lösung für dein Abakus!
Diese muss sicher noch optimiert werden, aber
die Animationsmechanik lässt sich einbauen.

Linke Maustaste = Aufwärts
Rechte Maustaste = Abwärts

Slogan:
"TKINTER and PYTHON ist just a FANTASTIC combination!!"

Code: Alles auswählen

from Tkinter import *

def MoveUp(perle):
	#~~ Schiebt Objekt nach oben
	cv.move(perle,0,-32)

def MoveDown(perle):
	#~~ Schiebt Objekt nach unten
	cv.move(perle,0,+32)

#  ->>----THE-ABAKUS----<<-
if __name__ == '__main__':

	root = Tk()
	root.title("Abakus")
	cv = Canvas(root,height=450,width=85,bd=6,relief=RAISED,bg='khaki2')
	cv.pack()

	usingIDLE = 0

	r = 30   # Durchmesser der Perle
	s = 32   # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen
	breite = 4
	xpos = s+r/2+breite/2-1
	stange = cv.create_line(xpos,8,xpos,380,fill='darkolivegreen4',width=breite)

	for x in range(1):
		for y in range(10):
			q = x*r

			x0 = s+q+q
			y0 = s+y*r
			x1 = s+(x+1)*r+q
			y1 = s+(y+1)*r

			object = cv.create_oval(x0,y0,x1,y1,fill='green',outline='red')
			cv.tag_bind(object,"<Button-1>",lambda e,Object=object:MoveUp(Object))
			cv.tag_bind(object,"<Button-3>",lambda e,Object=object:MoveDown(Object))

	quit = Button(root, text="Beenden", width=6, command=root.destroy)
	quit.pack(side="right")

	if not usingIDLE:
  		root.mainloop()
All the best wuf
Take it easy Mates!
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
Ich hab auch noch mal rumgespielt. Ich muss sagen, die Idee, das Ganze mit einem Dictionary zu managen, gefällt mir immer besser. Ich denke einfach immer noch zuviel in Arrays.

Code: Alles auswählen

from Tkinter import *
root = Tk()
root.title("Abakus")
cv = Canvas(root,height=450,width=650)
cv.pack()
perle = {}
usingIDLE = 0


r = 30   # Durchmesser der Perle
ax = 40   # Perlen-Offset in x-Richtung
ay = 35   # Perlen-Offset in y-Richtung
originx = 10 # Ursprung ...
originy = 50 # ... des Ganzen


### Aktion:Kugel nach oben schieben.
def schieb(xc,yc):
    ycNeu = yc-1   # einen hochrücken
    if ycNeu == -2 or perle.has_key((xc,ycNeu)):  # wenn wir schon ganz oben waren oder dort eine Perle ist ...
        ycNeu = yc+1 # einen runterrücken
        if ycNeu == 10 or perle.has_key((xc,ycNeu)): # wenn wir schon ganz unten waren oder da auch schon eine Perle ist, ...
            return  # ... dann gibt es nichts zu tun
    xx = originx + xc*ax;  yy = originy + ycNeu*ay
    cv.coords(perle[(xc,yc)],xx,yy,xx+r,yy+r)
    perle[(xc,ycNeu)] = perle[(xc,yc)] # Die Perle bekommt einen neuen Dict-Eintrag entspr. der neuen Position
    cv.tag_bind(perle[(xc,ycNeu)],"<Button-1>", lambda e,X=xc,Y=ycNeu:schieb(X,Y))  # nötig, da sich ja y verändert hat
    del perle[(xc,yc)] # alten Dict-Eintrag löschen


for x in range(10):
    for y in range(10):
        xx = originx + x*ax;  yy = originy + y*ay
        perle[(x,y)]=cv.create_oval(xx,yy,xx+r,yy+r,fill='green',outline='black',)
        cv.tag_bind(perle[(x,y)],"<Button-1>", lambda e,X=x,Y=y:schieb(X,Y))
           
quit = Button(root, text="Beenden", width=6, command=root.destroy)
quit.pack(side="right")

root.focus_force()
if not usingIDLE:
   root.mainloop()
Sicherlich noch optimierbar. Irgendwie werde ich das Gefühl nicht los, dass da was redundant ist.
Jan
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

Voges wirklich vielen Dank.Sehr interessante Ideen!
Ich habe jetzt fast den ganzen Abend hin und herprogrammiert. So siehts aus.Die Perlen bewegen sich halbwegs so wie ich es will.

zuerstmal wird unterschieden ob die perle die 9te oder sonst eine aus der jeweiligen Reihe ist(der fall es sei die erste mach ich morgen). Danach werden, abhängig davon ob sie in der Liste "verschoben" drin ist oder nicht, die betroffenen Perlen verschoben.

irgendwie will

del verschoben[(xc,yc)] (In der Zeile 16)

nicht so ganz gehen. Es kommt die Fehlermeldung "sequence index must be integer".

gute nacht
Niko

p.s.:im folgenden der neueste code.

Code: Alles auswählen

from Tkinter import * 
root = Tk() 
root.title("Abakus") 
cv = Canvas(root,height=450,width=650) 
cv.pack() 
perle = {} 
usingIDLE = 0 
verschoben = []
 
def schieb(xc,yc):
    print perle[(xc,yc)]
    print verschoben
    if yc == 9:
        if perle[(xc,yc)] in verschoben:
            cv.coords(perle[(xc,yc)],s+xc*r+xc*r,s+yc*r,s+(xc+1)*r+xc*r,s+(yc+1)*r)
            del verschoben[(xc,yc)] ### Löschen aus verschoben
        elif perle[(xc,yc)] not in verschoben:
            for o in range(yc+1):
                print verschoben
                verschoben.append(perle[(xc,o)]) ### Der WERT vom Schlüssel
                cv.coords(perle[(xc,o)],s+xc*r+xc*r,s+o*r,s+(xc+1)*r+xc*r,s+(o-1)*r)
    else:
        if perle[(xc,yc+1)] not in verschoben:
            #print xc,yc+1,"nicht in verschoben vorhanden"
            for t in range(yc+1):
                #print xc,t
                verschoben.append(perle[(xc,t)]) ### Der WERT vom Schlüssel
                cv.coords(perle[(xc,t)],s+xc*r+xc*r,s+t*r,s+(xc+1)*r+xc*r,s+(t-1)*r)
        elif perle[(xc,yc-1)] in verschoben:
            for z in range(yc,10):
                cv.coords(perle[(xc,z)],s+xc*r+xc*r,s+z*r,s+(xc+1)*r+xc*r,s+(z+1)*r)
                del verschoben[(xc,z)]

r = 30   # Durchmesser der Perle 
s = 32   # Nur um in Zeile 14 nicht über 79 Zeichen zu kommen 
for x in range(10): 
    cv.create_line(47+x*r+x*r,2,47+x*r+x*r,332,width=1)
for x in range(10): 
    for y in range(10):
        q = x*r  # Nur um in Zeile 43 nicht über 79 Zeichen zu kommen 
        perle[(x,y)] = cv.create_oval(s+q+q,s+y*r,s+(x+1)*r+q,s+(y+1)*r,fill='green')
        #perle[(x,y)] = [str(x*10+y)]
        cv.tag_bind(perle[(x,y)],"<Button-1>", lambda e,X=x,Y=y:schieb(X,Y))
        cv.create_text(47+x*r+x*r,352,text = "0")
print perle
quit = Button(root, text="Beenden", width=6, command=root.destroy) 
quit.pack(side="right") 

root.focus_force() 
if not usingIDLE: 
   root.mainloop()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Niko

Ich habe dir auf der ersten Seite (letzter Eintrag)
noch ein bischen Code zu diesem Thema beigelegt.

Gruss wuf
Take it easy Mates!
niko
User
Beiträge: 24
Registriert: Freitag 23. Januar 2004, 20:53

wuf vielen dank!
hab das irgendwie noch übersehen.aber auch keine schlechte Idee.Naja aber nun is spät und Schlaf is Mangelware.In dem Sinne gute Nacht.
Niko
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi niko,

verschoben ist ja auch eine liste, nimm statt del verschoben[(xc,yc)] einfach verschoben.remove(perle[(xc,yc)])


Gruß

Dookie
Antworten