relief="sunken" immer nur bei einem Button

Fragen zu Tkinter.
Antworten
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Wieder einmal steh ich vor einem Problemchen:

Ich hab mehrere Buttons erstellt, es soll aber immer nur der Button, der als letztet gedrückt wurde relief="sunken" aktiviert haben, damit man weiß, in welchem Menü man sich gerade befindet.

Wie kann ich bei allen Buttons die relief="sunken" deaktivieren??

Danke, lG

dh233
BlackJack

Das Gegenteil von `Tkinter.SUNKEN` ist `Tkinter.RAISED`.
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Ok, ich hab jetzt einfach eine Methode geschrieben, die alle Buttons zuerst auf relief="raised" setzt.

Das einzige, was mir jetzt noch fehlt ist, wie man den Namen des aufrufenden Objekts verwendet, denn da ergibt sich ein Problem bei folgender Methode:

Code: Alles auswählen

def clearButtons():
            self.BBanners.configure(relief="raised")
            self.BMetasploit.configure(relief="raised")
            self.BNessus.configure(relief="raised")
            self.BOSfinger.configure(relief="raised")
            self.BPorts.configure(relief="raised")
            self.BReports.configure(relief="raised")
            self.DNS.configure(relief="raised")
            
def setRelief():
           clearButtons()
           self.BPorts.configure(relief="sunken")
Beim Aufruf von

self.BPorts=Button(self.nav, text="Ports", width=15, command=setRelief

gibt es einen Fehler. Das hat sicher was damit zu tun, dass die ganzen Aufrufe im Konstruktor __init__ stehen, oder??
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Ich hab jetzt mal für jeden Button seine eigene Methode definiert. Das Problem liegt anscheinend daran, dem Parameter "command" beim Aufruf keinen Parameter mitgeben kann:

Code: Alles auswählen

self.BReports=Button(self.nav, text="Reports", width=15, command=setBReportsRelief)
Ich müsste allerdings "command=setBReportsRelief" mit einem Parameter aufrufen. Z.B.:

"command=setBReportsRelief(BReports)"
BlackJack

dh233 hat geschrieben:

Code: Alles auswählen

def clearButtons():
            self.BBanners.configure(relief="raised")
            self.BMetasploit.configure(relief="raised")
            self.BNessus.configure(relief="raised")
            self.BOSfinger.configure(relief="raised")
            self.BPorts.configure(relief="raised")
            self.BReports.configure(relief="raised")
            self.DNS.configure(relief="raised")
Das sieht nach einer Methode aus, dann fehlt der Parameter `self`. Man kann das auch ohne soviel copy'n'paste schreiben:

Code: Alles auswählen

    def clearButtons(self):
        for button_name in ('BBanners', 'BMetasploit', 'BNessus', 'BOSfinger',
                            'BPorts', 'BReports', 'DNS'):
            getattr(self, button_name).configure(relief=Tkinter.RAISED)

Code: Alles auswählen

def setRelief():
           clearButtons()
           self.BPorts.configure(relief="sunken")
Auch hier fehlt wieder der `self` Parameter. Und auch vor `clearButtons()` muss eins, da es sich um eine Methode handelt und nicht um eine Funktion im Modul.
Beim Aufruf von

self.BPorts=Button(self.nav, text="Ports", width=15, command=setRelief

gibt es einen Fehler. Das hat sicher was damit zu tun, dass die ganzen Aufrufe im Konstruktor __init__ stehen, oder??
Sozusagen. Es gibt keine Funktion `setRelief` sondern eine Methode auf dem Objekt das gerade initialisiert wird. Also auch hier fehlt wieder ein `self`.
BlackJack

dh233 hat geschrieben:Ich hab jetzt mal für jeden Button seine eigene Methode definiert. Das Problem liegt anscheinend daran, dem Parameter "command" beim Aufruf keinen Parameter mitgeben kann:

Code: Alles auswählen

self.BReports=Button(self.nav, text="Reports", width=15, command=setBReportsRelief)
Ich müsste allerdings "command=setBReportsRelief" mit einem Parameter aufrufen. Z.B.:

"command=setBReportsRelief(BReports)"
Letzteres funktioniert natürlich nicht, weil Du damit die Funktion aufrufst und deren Rückgabewert dann als Kommando für den Button benutzt wird. Also kann man eine Funktion schreiben, die eine Funktion zurück gibt, die das gewünschte tut:

Code: Alles auswählen

def make_set_relief(button):
    def set_relief():
        button.configure(relief=Tkinter.SUNKEN)
    return set_relief
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Das dürfte doch mit einer lambda-Funktion einfacher gehen, z.B.:

Code: Alles auswählen

    def setRelief(self, button): 
        self.clearButtons() 
        button.configure(relief="sunken") 
    
    self.BPorts=Button(self.nav, text="Ports", width=15,
    	command=lambda arg=self.BPorts: self.setRelief(arg))
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Alles klar, Danke!

Werds mal ausprobieren.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Ich habe leider übersehen, dass self.BPorts in der Buttonerstellung nicht als Argument übergeben werden kann, weil es noch nicht bekannt ist. Ich habe deshalb die Buttonerstellung in zwei Schritte aufgeteilt. Vorsichtshalber habe ich es in einem Beispielscript einmal ausprobiert. Es funktioniert:

Code: Alles auswählen

from Tkinter import *


class MyClass:
    def __init__(self, master):
        self.button_list = ('Banners', 'Metasploit', 'Nessus', 'Osfinger',
                            'Ports', 'Reports', 'DNS')
        for name in self.button_list:
            bname = 'B%s' % name
            setattr(self, bname, Button(master, text=name, width=15))
            getattr(self, bname).config(command=lambda arg=getattr(self, bname):
                                        self.set_relief(arg))
            getattr(self, bname).pack()

    def set_relief(self, button):
        for name in self.button_list:
            getattr(self, 'B%s' % name).config(relief="raised")
        button.config(relief="sunken")


root=Tk()
MyClass(root)
root.mainloop()
MfG
HWK
dh233
User
Beiträge: 37
Registriert: Samstag 8. Juli 2006, 08:26

Danke HWK, das funkt einwandfrei!

Hab noch was anderes gefunden: Man könnte das Ganze auch mit Radiobuttons machen und "indicatoron=0" verwenden.

Code: Alles auswählen

from Tkinter import *

master = Tk()

v = IntVar()

Radiobutton(master, text="One", variable=v, value=1, indicatoron=0).pack(anchor=W)
Radiobutton(master, text="Two", variable=v, value=2, indicatoron=0).pack(anchor=W)

mainloop()
Das funktioniert mal an einem einfachen Beispiel, aber ob es später damit Probleme gibt und Buttons besser wären, kann ich noch nicht sagen.

lG

dh233
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Das sieht gut aus und ist ja noch einfacher!
Antworten