Button Hintergrundfarbe

Fragen zu Tkinter.
LIFE-CUBES
User
Beiträge: 14
Registriert: Freitag 17. Februar 2012, 17:38

Hallo erstmal!

Habe ein kleines Problem! Also: Will die Farbe von Buttons in einer Unterfunktion ändern, aber irgendwie funktioniert das nicht! Zwei kurze Programme dazu:
Da gehts:

Code: Alles auswählen

from Tkinter import *
from tkColorChooser import *
def setBgColor( ):
        push.config(bg='blue')
        push2.config(bg='yellow')

def setBgColor2():
        push.config(bg='red')
        push2.config(bg='grey')
root = Tk( )
push = Button(root, text='Set Background Color', command=setBgColor)
push.pack()
push2 = Button(root, text='Set Background Color2', command= setBgColor2)
push2.pack()
root.mainloop()
da nicht:

Code: Alles auswählen

from Tkinter import *
from tkColorChooser import *
def setBgColor( ):
        push.config(bg='blue')
        push2.config(bg='yellow')

def setBgColor2():
        push.config(bg='red')
        push2.config(bg='grey')
    
def bla():
    root = Tk( )
    push = Button(root, text='Set Background Color', command=setBgColor)
    push.pack()
    push2 = Button(root, text='Set Background Color2', command= setBgColor2)
    push2.pack()
    root.mainloop()
    
main=Tk()
main=Button(None, text='BgChange', command=bla)
main.pack()
main.mainloop()
ABER WARUM??
BITTE HILFE!!!!
Danke!
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

LIFE-CUBES hat geschrieben:ABER WARUM??
BITTE HILFE!!!!
Das schreckt eher ab ;)

Es liegt daran, dass du keine Variablen aus einer anderen Funktion ändern kannst. Wenn du sowas tun willst, dann musst du Objektorientierung erlernen: Damit kannst du dann Instanzattribute erstellen, die z. B. Buttons sind …

Code: Alles auswählen

import Tkinter as tk

class Example(tk.Frame):

    def __init__(self, master=None):
        self.master = master
        self.push = tk.Button(master, text='Set Background Color',
                              command=self.setBgColor)
        self.push.pack()
        self.push2 = tk.Button(master, text='Set Background Color2',
                               command=self.setBgColor2)
        self.push2.pack()

    def setBgColor(self):
        self.push.config(bg='blue')
        self.push2.config(bg='yellow')

    def setBgColor2(self):
        self.push.config(bg='red')
        self.push2.config(bg='grey')

def main():
    toplevel = tk.Tk()
    window = Example(toplevel)
    toplevel.mainloop()

if __name__ == '__main__':
    main()
deets

Alternativ zu OO kann man natuerlich auch mit einem closure arbeiten (ungetestet):

Code: Alles auswählen


def make_color_setter(button, color):
      def set_color():
            button.config(bg=color)
      return set_color


def bla():
      a = Button(root, text=...) # kein command!
      a.config(command=make_color_setter(a, "yellow")


LIFE-CUBES
User
Beiträge: 14
Registriert: Freitag 17. Februar 2012, 17:38

Danke für die prompten Antworten!
Also das closure haut irgendwie nicht hin... (habs in mein Testprogramm integriert)
und zu der objektorientierten programmierung... Kann ich das class dann aufrufen wie eine funktion oder ist dann die programmierung ganz anders?
(zur erklärung: hab mir das python programmieren vor 3 tagen selbst beigebracht, also bitte nicht zu streng sein!)

danke im voraus!
deets

was heisst "habe eingebaut" - ohne code kann man das ja wohl kaum beurteilen.
LIFE-CUBES
User
Beiträge: 14
Registriert: Freitag 17. Februar 2012, 17:38

Code: Alles auswählen

def make_color_setter(button, color):
      def set_color():
            button.config(bg=color)
      return set_color


def bla():
      a = Button(root, text='...') # kein command!
      a.config(command=make_color_setter(a, "yellow"))
      a.pack()
      a.mainloop()

main=Tk()
main=Button(None, text='BgChange', command=bla)
main.pack()
main.mainloop()      
problembär

LIFE-CUBES hat geschrieben:und zu der objektorientierten programmierung... Kann ich das class dann aufrufen wie eine funktion
Sagen wir mal, so ähnlich (s.u.).
LIFE-CUBES hat geschrieben:oder ist dann die programmierung ganz anders?
Eigentlich schon. Aber Du verwendest OOP sowieso schon, weil die Tkinter-Widgets auch solche Objekte sind. Es ist also sinnvoll für Dich als GUI-Programmierer, das zu lernen.
LIFE-CUBES hat geschrieben:und zu der objektorientierten programmierung... Kann ich das class dann aufrufen wie eine funktion
Mal die OOP-Philosophie außer acht lassend, kann man Klassen auch als Behälter (Container) für Variablen und Funktionen verstehen, die man dann auch aufrufen kann (das ist der OOP-Ansatz von Perl):
Man definiert eine Klasse. Dann erzeugt man ein Objekt dieser Klasse. Dabei wird automatisch die "__init__"-Funktion innerhalb der Klasse aufgerufen. Dann kann man mit dem "."-Operator auf die in der Klasse enthaltenen Variablen und Funktionen zugreifen. Damit diese als Klassenvariablen und Klassenfunktionen erkannt werden, muß ihnen in der Klassendefinition der Ausdruck "self." vorangestellt werden. Ein kleines Beispiel zum Ganzen:

Code: Alles auswählen

#!/usr/bin/env python
# coding: iso-8859-1

class MyClass(object):

    def __init__(self):
        self.classvalue = 1

    def printHallo(self):
        print "Hallo"

# Objekt der Klasse erzeugen:
myobject = MyClass()

# Auf Klassenvariable zugreifen:
print myobject.classvalue

# Klassenfunktion aufrufen:
myobject.printHallo()
Näher dazu (und natürlich viel ausführlicher):

http://abop-german.berlios.de/read/oops.html
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

problembär hat geschrieben:Damit diese als Klassenvariablen und Klassenfunktionen erkannt werden, muß ihnen in der Klassendefinition der Ausdruck "self." vorangestellt werden.
Nein. Beispiel:

Code: Alles auswählen

In [2]: class FooBar(object):
   ...:     def __init__(foo, name):
   ...:         foo.name = name
   ...:     def print_hello(bar):
   ...:         print "Hello {}".format(bar.name)
   ...:         
   ...:         

In [3]: FooBar('Problembaer').print_hello()
Hello Problembaer
problembär

nomnom hat geschrieben:
problembär hat geschrieben:Damit diese als Klassenvariablen und Klassenfunktionen erkannt werden, muß ihnen in der Klassendefinition der Ausdruck "self." vorangestellt werden.
Nein. Beispiel:

Code: Alles auswählen

In [2]: class FooBar(object):
   ...:     def __init__(foo):
   ...:         foo.classvalue = 1
   ...:     def print_hello(bar):
   ...:         print "Hello"
   ...:         
   ...:         

In [3]: FooBar().classvalue
Out[3]: 1

In [4]: FooBar().print_hello()
Hello
Super, verwirr' ihn doch noch ein bißchen mehr!

@LIFE-CUBES: Es stimmt, daß man theoretisch statt "self" auch andere Wörter dafür definieren könnte. "self" ist aber der gebräuchliche Ausdruck. Das siehst Du etwa auch in dem Tkinter-Beispiel von nomnom oben. Da verwendet er selbst auch "self".
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Ich wollte doch nur auch mal klugscheißen. :roll: @Life-Cubes: Ja, vergiss was ich gesagt habe.
deets

@LIFE-CUBES


du musst schon versuchen zu verstehen, was ich da gemacht habe... dein Bla steigt aus, weil "root" nicht existiert. Ich das musst du schon deinen existierenden Dingen anpassen - nicht einfach nur wild copy & paste betreiben & hoffen, dass es geht...

Das hier geht bei mir wunderbar

Code: Alles auswählen


from Tkinter import *

def make_color_setter(button, color):
      def set_color():
          print "hallo"
          button.config(bg=color)
      return set_color

main=Tk()
a=Button(None, text='BgChange')
a.pack()
a.config(command=make_color_setter(a, "yellow"))
main.mainloop()
Allerdings aendert sich keine Farbe - warum auch immer, aber das ist ja schon dein Code gewesen, kA ob das ueberhaupt so geht oder nicht. Kann aber auch an OSX liegen.
deets

problembär hat geschrieben:Damit diese als Klassenvariablen und Klassenfunktionen erkannt werden, muß ihnen in der Klassendefinition der Ausdruck "self."
Diese Begriffe sind falsch. Es handelt sich nicht um eine Klassenfunktion, sondern man nennt das "Methode". Und der Begriff "Klassenvariable" ist anderweitig besetzt - die gibt es naemlich auch:

Code: Alles auswählen

class Foo(object):

    ICH_BIN_EINE_KLASSENVARIABLE = 10

    @classmethod
    def test(cls):
          print cls.ICH_BIN_EINE_KLASSENVARIABLE

Foo.test()
Das was du meinst ist eine Instanzvariable, oder besser noch ein Instanzattribut. Der Unterschied ist *sehr* relevant!
problembär

Ok, ich wollte das etwas vereinfachen und dabei möglichst die Begriffe "Attribut", "Methode" und auch "Instanz" vermeiden. Ist ja so schon schwer genug, das zu verstehen. Also:

Außerhalb der Klasse: Variable.
Innerhalb der Klasse: Attribut.

Außerhalb der Klasse: Funktion.
Innerhalb der Klasse: Methode.

Wenn die Begriffe, die ich dabei gewählt hatte, schon belegt sind und etwas anderes bedeuten, ist das natürlich schlecht. Dafür entschuldige ich mich.
Trotzdem hoffe ich, daß das Prinzip erstmal einigermaßen veständlich gezeigt wurde.
Ich selbst nutze übrigens nie echte Klassenvariablen und denke, auch LIFE-CUBES kann vorerst auf diese verzichten.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

deets hat geschrieben:Allerdings aendert sich keine Farbe - warum auch immer, aber das ist ja schon dein Code gewesen, kA ob das ueberhaupt so geht oder nicht. Kann aber auch an OSX liegen.
Es ist nur die Option-activebackground welche das sofortige sichtbar werden der neuen Farbe verhindert. Sobald du aber die Maus vom Button wegziehst wird sie sichbar.

Hier noch etwas zum ausprobieren:

Code: Alles auswählen

from Tkinter import *

def make_color_setter(button, color):
      def set_color():
          print "hallo"
          button.config(bg=color, activebackground=color)
      return set_color

main=Tk()
a=Button(None, text='BgChange')
a.pack()
a.config(command=make_color_setter(a, "yellow"))

main.mainloop()
Gruß wuf :wink:
Take it easy Mates!
deets

problembär hat geschrieben:Ok, ich wollte das etwas vereinfachen und dabei möglichst die Begriffe "Attribut", "Methode" und auch "Instanz" vermeiden. Ist ja so schon schwer genug, das zu verstehen.
Du fuehrst im Namen leichterer Verstaendlichkeit unbekannte, missverstaendliche und sogar ausgewiesen falsche Begriffe ein. Und das soll dem OP das Verstaendnis eines so komplexen Gegenstandes wie der OOP *vereinfachen*? Masst du dir wirklich an zu glauben, deine Einlassung hier ist ausreichend, um das OO-Programmieren zu erlernen? Ich hoffe doch nicht. Denn mit deine Begrifflichkeiten im Gepaeck wird sich kein ein- und weiterfuehrendes Tutorial erschliessen. Die Lernleistung ist also einfach nochmal zu erbringen.

Und damit stellt sich mal wieder die Frage, wieso du so beharrlich darauf bestehst, Anfaengern solche Baerendienste zu erweisen.
LIFE-CUBES
User
Beiträge: 14
Registriert: Freitag 17. Februar 2012, 17:38

Dankeschön fur die zahlreichen Antworten! Haben mich ganz schön weitergebracht!
Aber eine Frage hätt ich da noch:
Kann man aus einer Funktion heraus bei Buttondruck und aufrufen einer Unterfunktion die Übergeordnete schließen und wieder ausführen? Wie ein refresh??

Danke Euch allen!

MfG
problembär

deets hat geschrieben:Du fuehrst im Namen leichterer Verstaendlichkeit unbekannte, missverstaendliche und sogar ausgewiesen falsche Begriffe ein.
Falsch. Ich habe durchgängig ausschließlich die Begriffe "Variable" und "Funktion" verwendet, Begriffe die der OP bereits kennt. Ich habe es gerade vermieden, neue Begriffe einzuführen.
deets hat geschrieben:Und das soll dem OP das Verstaendnis eines so komplexen Gegenstandes wie der OOP *vereinfachen*?
Allerdings. Wenn man OOP so auf lediglich einen Container reduziert, wie ich es getan habe, verliert das Thema seine Komplexität und man kann die einfachsten Grundlagen in einem Posting erklären, s.o..
deets hat geschrieben:Masst du dir wirklich an zu glauben, deine Einlassung hier ist ausreichend, um das OO-Programmieren zu erlernen?
Nein, dazu der weiterführende Link auf "A Byte of Python". Mir ging es nur um die allerersten Schritte, "Quickstart" sozusagen. Um einen Tkinter-Button zum Funktionieren zu bringen, könnten diese Schritte allerdings möglicherweise reichen.
deets hat geschrieben:Die Lernleistung ist also einfach nochmal zu erbringen.
Sicher, wenn man OOP wirklich verstehen will, reicht es nicht. Es ging nur um ein erstes Beispiel.
deets hat geschrieben:Und damit stellt sich mal wieder die Frage, wieso du so beharrlich darauf bestehst, Anfaengern solche Baerendienste zu erweisen.
Es macht mir halt Spaß, anderen Hilfestellungen zu geben. Wenn Du deren Qualität nicht zu schätzen weißt, ist das Dein Problem; nicht meins und nicht das der Hilfesuchenden.
Du hast allerdings das Recht, mich darauf hinzuweisen, wenn ich sachliche Fehler machen sollte. Ich werde mich dann bemühen, diese in den folgenden Postings zu verbessern.
So funktionieren Foren und Diskussionen in einer freien Gesellschaft nunmal: Jeder darf sagen, was er denkt. Selbst, wenn es falsch sein sollte. Und andere dürfen sich eine Meinung dazu bilden, was sie davon halten. Das nennt man Meinungsäußerungsfreiheit. Dieses Prinzip scheint Dir fremd zu sein, das mußt Du noch lernen, unbedingt.
LIFE-CUBES hat geschrieben:Kann man aus einer Funktion heraus bei Buttondruck und aufrufen einer Unterfunktion die Übergeordnete schließen und wieder ausführen? Wie ein refresh??
GUI-Anwendungen laufen anders ab als (fensterlose) Konsolenanwendungen. Wenn "rootwindow.mainloop()" aufgerufen wird, bleibt das Programm dort sozusagen "hängen" und wartet auf Benutzereingaben wie das Klicken eines Buttons. Erfolgt der Klick, wird die mit dem Button assoziierte Funktion aufgerufen. Danach kehrt das Programm in den Mainloop zurück.
Man braucht also keine Unterfunktionen oder so, um übergeordnete Funktionen zu beenden. Der Programmfluß ist immer so, wie gerade dargestellt: Mainloop -> Benutzereingabe -> Assoziierte Funktion -> Mainloop.
Bis das Root-Window (in einer der assoziierten Funktionen) mit "rootwindow.destroy()" geschlossen wird und die Anwendung beendet wird.
Zuletzt geändert von problembär am Samstag 18. Februar 2012, 23:20, insgesamt 3-mal geändert.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi LIFE-CUBES

Hier noch etwas zum experimentieren:

Code: Alles auswählen

import Tkinter as tk

COLOR_LIST = ['yellow', 'green', 'blue', 'red']

class ColorListBox(tk.Toplevel):
    
    def __init__(self, button):
        
        tk.Toplevel.__init__(self, button)
        
        self.button = button
        
        self.list_box = tk.Listbox(self, bd=0, highlightthickness=0,
            font=('Helvetica', 14))
        self.list_box.insert(0, *COLOR_LIST)
        self.list_box.pack()
        self.list_box.bind('<ButtonRelease-1>', self.selected_color)
    
    def selected_color(self, event):

        index = self.list_box.curselection()[0]
        color_name = self.list_box.get(index)
        self.button.config(bg=color_name)
        self.destroy()

def button_callback():
    ColorListBox(button)
    
main = tk.Tk()

button = tk.Button(main, text='BgChange', command=button_callback)
button.pack()

main.mainloop()
Gruß wuf :wink:
Take it easy Mates!
deets

problembär hat geschrieben:
deets hat geschrieben:Und damit stellt sich mal wieder die Frage, wieso du so beharrlich darauf bestehst, Anfaengern solche Baerendienste zu erweisen.
Es macht mir halt Spaß, anderen Hilfestellungen zu geben. Wenn Du deren Qualität nicht zu schätzen weißt, ist das Dein Problem; nicht meins und nicht das der Hilfesuchenden.
Du hast allerdings das Recht, mich darauf hinzuweisen, wenn ich sachliche Fehler machen sollte. Ich werde mich dann bemühen, diese in den folgenden Postings zu verbessern.
So funktionieren Foren und Diskussionen in einer freien Gesellschaft nunmal: Jeder darf sagen, was er denkt. Selbst, wenn es falsch sein sollte. Und andere dürfen sich eine Meinung dazu bilden, was sie davon halten. Das nennt man Meinungsäußerungsfreiheit. Dieses Prinzip scheint Dir fremd zu sein, das mußt Du noch lernen, unbedingt.
Was fuer ein Unfug. Niemand verbietet dir hier, deine Einlassungen vorzunehmen. Die Diskussion ueber Meinungsfreiheit ist also voellig fehl am Platz, und ich habe da auch keinen Lernbedarf.

Wo du aber irrst - und zwar gewaltig - ist, dass es kein Problem ist, wenn du mit deinen "Hilfestellungen" Schaden anrichtest. Und einzig und alleine darum geht es hier, wenn ich und andere dich deine kruden Ansichten korrigieren. Natuerlich waere es schoen zu sehen, wenn du selbst irgendwann auf den Trichter kommst, dass du daraus lernst. Aber ich halte das fuer eher unwahrscheinlich.

Doch unbedarfter Anfaenger wegen, die dank deiner einen schlechten Start hinlegen wuerden sind der Grund, deine Ansichten hier nicht unkorrigiert zu lassen.
BlackJack

@problembär: Natürlich ist die Qualität Deiner Hilfestellungen ein Problem des Hilfesuchenden. Und ganz offensichtlich haben auch andere ein Problem damit.

Deine Argumentation zur Meinungsfreiheit ist lustig. Die scheint ja nur für Dich zu gelten. Denn wir dürfen uns anscheinend nur eine Meinung zur Qualität Deiner Beiträge *bilden*. Aber wehe wir *äussern* sie auch. Dann wirfst Du uns vor *wir* hätten Meinungsfreiheit nicht verstanden. :-D

Zumal das sowieso nicht so funktioniert, wie Du Dir das zusammenfantasierst. Selbst wenn es richtig sein sollte, darfst Du hier nur sagen was die Moderatoren Dir durchgehen lassen. Das Grundgesetz verbietet weder das entfernen von Beiträgen in diesem Forum noch einen kompletten hinauswurf eines Mitglieds. Das muss man nicht einmal begründen.

Im Vergleich zu anderen Foren ist die Moderation in diesem Forum aber sogar sehr entspannt. Was ich persönlich gut finde! Artikel werden hier nur *sehr* selten inhaltlich verändert, zeitliche Sperren werden gar nicht verhängt, und Rauswürfe passieren eigentlich nur bei offensichtlich kommerziellen Spammern, die sonst nichts zum Thema Python beitragen.
Antworten