Tabelle filtern

Fragen zu Tkinter.
Antworten
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Hallo,

ich habe seit heute mal die grafische Oberfläche in Python ausprobiert. Nun möchte ich in ein Entry Feld Text eingeben, der dann in der darunter liegenden Tabelle gesucht und gefiltert wird.Dafür habe ich einen extra Button...

Hier mein bisheriger Code:

Code: Alles auswählen

#!/usr/bin/python

from Tkinter import *
import random

root = Tk()
root.minsize(500, 500)

# Funktionen
def hinzufuegen():
        if entSuche.get() != "":
                Lb1.insert(END, entSuche.get())

def filtern():
        filtered = filter(int(entSuche.get()), Lb1.content)

# Textfeld und Button fuer die Suche
entSuche = Entry(root)
entSuche.pack()
btnHinzufuegen = Button(root, text='Hinzufuegen', command = hinzufuegen).pack()
btnFilter = Button(root, text='Filter', command = filtern).pack()

# Tabelle
lblTabelle = Label(root, text='Tabelle')
Lb1 = Listbox(root)
Lb1.content = [str(random.randint(10000000,99999999)) for k in xrange(8)]
Lb1.insert(END, *Lb1.content)
Lb1.insert(1, "Python")
Lb1.insert(2, "Perl")
Lb1.insert(3, "C")
Lb1.insert(4, "PHP")
Lb1.insert(5, "JSP")
Lb1.insert(6, "Ruby")
Lb1.pack()

root.mainloop()
Ich habe es irgendwie mit filter(x, y) versucht, aber irgendwie mag das bei mir nicht so (x und y habe ich natürlich angepasst). Kann mir da jemand behilflich sein?

Mfg
BlackJack

@DiiiDiii: Die `filter()`-Funktion erwartet als erstes Argument eine *Funktion* die für jedes Element des zweiten Arguments aufgrufen wird und einen Wahrheitswert zurück liefern muss der sagt ob das Element übernommen wird, oder nicht.

Das mit dem `content`-Attribut ist ein wenig komisch. `Listbox` hat kein solches Attribut und das enthält dann natürlich auch nicht den tatsächlichen Inhalt von der `Listbox`. An sich sollte man aber auch keine Werte in der GUI speichern, sondern die nur zum anzeigen verwenden. Ich würde die Daten dann aber trotzdem nicht einfach an das GUI-Objekt binden.

Wie sieht es denn mit objektorientierter Programmierung (OOP) aus? Ohne sollte man GUI-Programmierung IMHO gar nicht erst anfangen. Das wird nur ein unübersichtliches durcheinander.

Ein Blick in den Style Guide for Python Code könnte übrigens nicht schaden.
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Alles klar, danke... jetzt habe ich zwei Klassen. Die eine Klasse ist das Menü oben (mit Datei usw.). Die andere Klasse ist der Inhalt, also darunter. Das Menü mache ich in eine extra Klasse, da später noch mehr Klassen erstellt werden müssen und das gleiche Menü benötigen. Nun möchte ich mit

Code: Alles auswählen

spielemenu.add_command(label='Wer ist naeher?', command=hauptmenue.weristnaeher)

die Funktion "weristnaeher" aus der Klasse "hauptmenue" aufrufen. Da ich mich in der zweiten Klasse befinde, kann ich ja nicht self.weristnaeher machen... wenn ich es so habe wie oben, kommt bei mir allerdings folgende Meldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "./spielesammlung.py", line 60, in <module>
    hauptmenue = Hauptmenue()
  File "./spielesammlung.py", line 15, in __init__
    topmenue = TopMenue(root)
  File "./spielesammlung.py", line 37, in __init__
    spielemenu.add_command(label='Wer ist naeher?', command=hauptmenue.weristnaeher)
AttributeError: Menu instance has no attribute 'weristnaeher
Woran liegt das?
BlackJack

@DiiiDiii: Ganz offensichlich hat das Objekt was an den Namen `hauptmenue` gebunden ist, kein solches Attribut. Das sagt die Fehlermeldung ziemlich unmissverständlich. Warum das Objekt so ein Attribut nicht hat, kann man ohne den Quelltext zu kennen nicht sagen. Vertippt? Gibt es so eine Methode in der `Hauptmenue`-Klasse (vorausgesetzt so ein Exemplar ist an den Namen `hauptmenue` gebunden)?
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Eigentlich hat es dies:

Code: Alles auswählen

#!/usr/bin/python

import time
from Tkinter import *


class Hauptmenue:
        def __init__(self):
               [...]

        def weristnaeher(self):
                global root
                root.destroy()
                werIstNaeher = WerIstNaeher()

class TopMenue:
        def __init__(self, x):
                menu = Menu(x)
                x.config(menu=menu)

                # Spielemenue
                spielemenu = Menu(menu)
                menu.add_cascade(label='Spiele', menu = spielemenu)
                spielemenu.add_command(label='Wer ist naeher?', command=hauptmenue.weristnaeher)
                spielemenu.add_separator()

class WerIstNaeher:
        def __init__(self):
                 [...]
hauptmenue = Hauptmenue()
BlackJack

@DiiiDiii: Wenn das Objekt was zum Zeitpunkt zu dem `TopMenue.__init__()` ausgeführt wird an den globalen Namen `hauptmenue` gebunden ist, dieses Attribut *hätte*, würde es nicht zu dieser Ausnahme kommen.

Letztendlich sollte in Methoden (und auch Funktionen) aber sowieso nicht einfach so auf etwas zugegriffen werden was nicht entweder an das Objekt gebunden ist, oder als Argument übergeben wurde. Ausnahme sind Konstanten. Denn jetzt kann man den Fehler *irgendwo* im *gesamten* Quelltext vermuten. Wenn `hauptmenue` dagegen als Argument übergeben würde, dann bräuchte man nur die Stellen im Programm suchen an denen `TopMenue` aufgerufen wird, um dem Problem näher zu kommen. In dem Zusammenhang: ``global`` solltest Du erst einmal aus Deinem Wortschatz streichen. Das hat in 99% der Fälle in einem sauberen Programm nichts zu suchen. Globaler Zustand macht Programme undurchsichtig, fehleranfällig, und schwerer nachvollziehbar.

Ein ähnliches Argument gilt für Sternchenimporte. Gerade im Fall von `Tkinter` holt man sich damit an die 200 Namen in das Modul, von denen man nur einen Bruchteil tatsächlich verwendet. Bei `Tkinter` ist ein ``import Tkinter as tk`` üblich. Dann kann man die Objekte aus dem Modul als Attribute von `tk` ansprechen.

Bei Python 2 würde ich grundsätzlich von `object` erben, wenn es keine andere Basisklasse gibt. Nur dann bekommt man „new style”-Klassen. Bei „old style”-Klassen funktioniert nicht alles was in der Dokumentation beschrieben steht. Zum Beispiel `property()` nicht.
DiiiDiii
User
Beiträge: 24
Registriert: Donnerstag 10. Oktober 2013, 10:30

Ok, danke... dann werde ich mal mein Programm etwas umstruckturieren... evtl geht es dann... nochmals danke :)
Antworten