Button event auslösen solange linke Maustaste gedrückt ist

Fragen zu Tkinter.
loggod
User
Beiträge: 6
Registriert: Mittwoch 12. November 2008, 23:38

hi Zusammen.

ich bin Anfänger was Python Programmierung angeht. Ich hoffe Ihr könnt mir ein wenig unter die Arme greifen.

Ich versuche eine Art 'Steuerkreuz' zu programmieren, bei dem solange etwas passiert solange, man mit dem Mauszeiger auf dem entsprechenden Button klickt und die linke Maustaste dabei gedrückt hält.

ein grober Rumpf wäre etwas in der Art:

Code: Alles auswählen

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

import Tkinter as tk

class navpad(object):
    def __init__(self):
        self.mainForm = tk.Tk()
	self.mainFrame = tk.Frame (self.mainForm)
        self.mainFrame.grid(row=1,column=1)
	self.buttonNameHL = tk.Button(self.mainFrame,text='HL',command=lambda:self.send('hoch links'))
	self.buttonNameHL.grid(row=1,column=1,sticky='W')
        self.buttonNameHO = tk.Button(self.mainFrame,text='HO',command=lambda:self.send('hoch'))
        self.buttonNameHO.grid(row=1,column=2,sticky='N')
	self.buttonNameHR = tk.Button(self.mainFrame,text='HR',command=lambda:self.send('hoch rechts'))
	self.buttonNameHR.grid(row=1,column=3,sticky='E')
	self.buttonNameLI = tk.Button(self.mainFrame,text='LI',command=lambda:self.send('links'))	
	self.buttonNameLI.grid(row=2,column=1,sticky='W')
       	self.buttonNameRE = tk.Button(self.mainFrame,text='RE',command=lambda:self.send('rechts'))			
	self.buttonNameRE.grid(row=2,column=3,sticky='E')
        self.buttonNameRL = tk.Button(self.mainFrame,text='RL',command=lambda:self.send('runter links'))			
	self.buttonNameRL.grid(row=3,column=1,sticky='W')
        self.buttonNameRU = tk.Button(self.mainFrame,text='RU',command=lambda:self.send('runter'))        		
	self.buttonNameRU.grid(row=3,column=2,sticky='S')
	self.buttonNameRR = tk.Button(self.mainFrame,text='RR',command=lambda:self.send('runter rechts'))			
	self.buttonNameRR.grid(row=3,column=3,sticky='E')

	self.mainForm.mainloop()
   
    def send(self,name):
    	print name


navpad() 
... nur halt eben mit der angesprochenen Funktionalität. Könnt Ihr mir dabei helfen ?


Ich bin für alle Tips und Anregungen dankbar.

Gruß,
loggod
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ich schlage vor, dass du dir das Kapitel "Event-handling in Tkinter" einmal zu Gemüte führst. Eine gute Übersicht findest du hier:

http://infohost.nmt.edu/tcc/help/pubs/t ... vents.html

Ich denke, dann wirst du die Lösung selbst entwickeln können. :wink:
loggod
User
Beiträge: 6
Registriert: Mittwoch 12. November 2008, 23:38

Hi Numerix,

vielen Dank erst mal für den guten Link...Ist auf jedenfall in meinen Favoriten gelandet :wink:

...aber folgendes Problem: wenn ich von der Auflistung in http://infohost.nmt.edu/tcc/help/pubs/t ... types.html ausgehe sehe ich nicht wie ich z.B ein
"<Button-1 _ is _ currently_Klicked_oder_irgendwas_in_der_Art>" event abfragen kann, weil es anscheinend nicht existiert. Es gibt ja nur "<Button>" und "<ButtonRelease>".
"<ButtonRelease>" könnte ich für eine Abbruch Bedingung nutzen um einen
Thread zu stoppen der angestoßen wird, nachdem man die Maustaste gedrückt gehalten hatte. Fehlt mir nur noch die entsprechende 'Bedingung' um den Thread anzustoßen.
"<Button>" implementiert ja nur das 'klicken' und anschließende 'loslassen' der Maustaste. Ich bräuchte aber halt eben nur das 'klicken'.

Einen eigenen event definieren? evtl. mit .char ?
Ausgehend von http://infohost.nmt.edu/tcc/help/pubs/t ... dlers.html
...Kann mann einen Mausklick als regulären ASCII Code darstellen ?


Was ich schon im ersten post geschrieben habe bleibt....Ich bin für jeden Tip dankbar :wink:

Gruß,
loggod
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod
ch versuche eine Art 'Steuerkreuz' zu programmieren, bei dem solange etwas passiert solange, man mit dem Mauszeiger auf dem entsprechenden Button klickt und die linke Maustaste dabei gedrückt hält.
Ich verstehe dein Funktionsbeschrieb leider nicht so richtig.

a) Ich nehme an du aktivierst die gewünschte Schaltfläche auch mit der linken Maustaste.

b) 'solange etwas passiert' ? Was meinst du mit passiert. Ich nehme an das etwas passiert solange die Schaltfläche aktiviert ist.

c) Beim loslassen der linken Maustaste (bzw. deaktivieren der Schaltfläche) passiert nichts mehr bzw. ist der Prozess beendet.

Könntest du den Funktionsablauf besser beschreiben.

Gruss wuf :wink:
Take it easy Mates!
loggod
User
Beiträge: 6
Registriert: Mittwoch 12. November 2008, 23:38

Hi wuf,

es soll in etwa wie der cursor block auf der Tastatur funktionieren. Also:

z.B 4 Buttons: Hoch, Runter, Rechts, Links ... und es soll sollange 'Runter' mit print ausgegeben werden, sollange mann die Cursortaste ' Runter' gedrückt hält. Erst wenn mann sie wieder loslässt soll die Ausgabe aufhören.

Denkbar wäre auch ähnlich wie bei einem gamepad oder Joystick z.B einen Punkt o.ä. über ein Canvas zu 'lenken' etc.

Gruß,
loggod
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod

Da könntest du zum Beispiel den '<Button-1>' und 'ButtonRelease-1>' Event an jede eingesetzte Schaltfläche binden. Angenommen die Schaltflache 'HL':

Code: Alles auswählen

self.buttonNameHL.bind('<Button-1>', self.button1_press)
self.buttonNameHL.bind('<ButtonRelease-1>', self.button1_release)
mit der Methode:

Code: Alles auswählen

def button1_press(self, event):
Kannst du eine Flag-Variable auf 'True' setzen und mit der Methode:

Code: Alles auswählen

def button1_release(self, event):
diese Flag-Variable wieder auf 'False' setzen.

Für die Auswertung musst du dann nur die Flag-Variable auf ihren Zustand prüfen.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod

Hier noch eine andere Variante.

Ereignisse der linken Maustaste an die Schaltfläche binden mit lambda:

Code: Alles auswählen

self.buttonNameHL.bind('<Button-1>',
    lambda event, name='hoch': self.button1_press(event, name))

self.buttonNameHL.bind('<ButtonRelease-1>',
    lambda event, name='hoch': self.button1_release(event, name))

Methode für Schalfläche 'drücken':

Code: Alles auswählen

def button1_press(self, event, name):
    """Schaltflaeche mit linker Maustaste gedruekt"""

    self.flag = True
    print 'Schaltfläche:', name, self.flag
Methode für Schalfläche 'loslassen':

Code: Alles auswählen

def button1_release(self, event, name):
    """Schaltflaeche mit linker Maustaste losgelassen"""

    self.flag = False
    print 'Schaltfläche:', name, self.flag
Die Button-Option 'command' braucht es nicht mehr.

Gruss wuf :wink:
Take it easy Mates!
loggod
User
Beiträge: 6
Registriert: Mittwoch 12. November 2008, 23:38

Hi wuf,

danke für den Ansatz. Ich werde das mal so implementieren :wink:

Gruß,
loggod
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hi loggod,
das was du möchtest ist ein Zustand, kein Event. Ein Event signalisiert dir lediglich das sich zb ein Zustand geändert hat. In diesem Fall zb MouseButtonClicked und MouseButtonReleased.

Aus diesen beiden Events musst du den Zustand des Mousebuttons sozusagen selbst ermitteln indem du eine Variable, zb MouseButtonHold, bei dem Event MouseButtonClicked auf TRUE setzt und beim Event MouseButtonReleased wieder auf False.

Vielleicht bietet Tkinter so eine Variable auch schon von sich aus.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Hallo loggod,
bin auch der Meinung, dass man sich den
Zustand des 'Gedrückthaltens' aus den Events
'Button-Pressed' und 'Button-Release'
zusammenbasteln muss.
Das ist aber gar nicht so schwer.

Hab' hier mal 2 Demos für dich gemacht,
zwar mit einem etwas anderen Thema, aber
hoffentlich mit der von Dir gewünschten Funktionalität.

1) http://paste.pocoo.org/show/91140/

Hier wird mit der after() Methode eine Schleife für
den Zustand 'Pressed' initiiert.
(s.a. http://infohost.nmt.edu/tcc/help/pubs/t ... ersal.html)

2) http://paste.pocoo.org/show/91141/

Hier wird die mainloop() explizit durch eine Schleife ersetzt.
Das ist wohl eher unüblich, aber falls man mal
einen Flugsimulator oder Ego-Shooter mit Tkinter schreiben will...

:wink:
yipyip
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod

Ich möchte mich den Super-Demos von 'yipyip' anschliessen. Habe die Erstellung deines Navigations-Widget noch ein bisschen automatisiert und folgendes zusammengeschmiedet.

[Code ausgelagert]

Hier noch das dir vertraute Bildchen:

Bild

Das ganze soll dich nicht verwirren vielleicht kannst du etwas avon gebrauchen. Projekte können auf 100 verschiedene Arten gelöst werden. Eventuell haben auch noch andere Forummitglieder welche Ideen.

Gruss aus der Tk-Komponentenschmiede wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Ups, bei der 2. Demo war ein
"self.canvas.delete('all')" zuviel,
bitte bei

Paste Details -> show paste tree

die neueste Version nehmen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod

Hier noch die grafische Variante des des Navigations-Widgets:

[Code ausgelagert]

Bild

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

@wuf: Wie hast du die Buttons so schick hinbekommen?
Waren das Fertigprodukte oder hast du die selbst erstellt? Durch die Beschränkung auf das gif-Format ist es ja nicht so einfach, wirklich gut aussehende Buttons zu basteln.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo numerix

Nein die Bildchen habe ich nicht selber konstruiert Habe sie im Internet gefunden beim suchen nach frei verfügbare Icons. Aber GIMP hat noch einige Zusätze (Plugin's) die es einem ermöglichen eigene Kunstwerke zu erstellen und als .gif's zu exportieren.

OK. Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo loggod

Noch eine Frage zum Code-Snippet, welches du in deinem ersten Post vorgestellt hast. Ist dies dein Original Skript? Weil da hat es Einrück-Fehler drin. Ist dies eventuell beim transverieren ins Forum passiert?

Noch ein Tipp:
Bei der Konfiguration der Grid-Layout-Manager Anweisungen würde ich die 'sticky'-Option mit dem Wert 'nesw' belegen damit das betreffende Button-Widget das ganze Grid-Feld ausfüllt.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

wuf hat geschrieben:Aber GIMP hat noch einige Zusätze (Plugin's) die es einem ermöglichen eigene Kunstwerke zu erstellen und als .gif's zu exportieren.
Das Problem ist auch weniger das Erstellen optisch ansprechender Buttons/Icons, sondern der Export in das GIF-Format mit seiner Beschränkung auf 256 Farben. Ich habe schon manches schöne Icon als png gehabt und nach der Konvertierung nach gif konnte man es wegschmeißen, weil z.B. sanfte Kantenübergänge und Farbverläufe nicht mehr so fein dargestellt werden konnten.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo numerix

Hast du schon eimal versucht das PIL-Packet für die Darstellung von Bilder einzusetzen. Zum Beispiel für ein Icon im .png-Format. Das PIL-Packet enthält ein Modul 'ImageTk' die sich hierfür eignet.

Hier ein kleines Testprogramm:

Code: Alles auswählen

import Tkinter as tk
import Image
import ImageTk


test_window = tk.Tk()

pil_icon = Image.open("archive.png")

pil_icon_1 = pil_icon.rotate(45)
pil_icon_2 = pil_icon.resize((70,70))

tk_icon = ImageTk.PhotoImage(pil_icon)
tk_icon_1 = ImageTk.PhotoImage(pil_icon_1)
tk_icon_2 = ImageTk.PhotoImage(pil_icon_2)

button = tk.Button(test_window, image=tk_icon)
button.pack(side='left')

button = tk.Button(test_window, image=tk_icon_1)
button.pack(side='left')

button = tk.Button(test_window, image=tk_icon_2)
button.pack(side='left')

test_window.mainloop()

Der Output für mein Bildchen 'archive.png':

Bild

Gruss wuf :wink:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

numerix hat geschrieben:Export in das GIF-Format mit seiner Beschränkung auf 256 Farben.
True-Color GIFs anyone? (Infos dazu)

Aber gut, davon abgesehen ist GIF sowieso am besten durch PNG zu ersetzen und damit hat es sich.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@Leonidas

Danke für den interessanten Link

In letzter Zeit häufen sich Post's die im gleichen Zeitfenster eintreffen. :lol: Muss etwas mit der momentanen Planeten-Konstellation zu tun haben.

Gruss wuf :wink:
Take it easy Mates!
Antworten