2 votes

Tkinter - Comment passer une variable d'instance à une autre classe ?

J'ai beaucoup cherché sur Google mais ça n'a pas marché. J'ai posté une question la semaine dernière, mais je n'ai pas reçu de réponse car il semble qu'elle ait été trop longue...

Espérons que la nouvelle question soit beaucoup plus claire.

Il s'agit juste d'un petit morceau de code et si vous l'exécutez, vous serez en mesure de reproduire le problème. Ce que j'ai besoin de faire, c'est de récupérer l'entrée de l'utilisateur (E1 de la classe mainGUI) et de la passer à la fonction insert() de la classe Database. L'erreur que j'obtiens lorsque j'essaie d'ajouter une entrée est la suivante :

"self.curs.execute("INSERT INTO diary VALUES ( ?)", (date)) sqlite3.ProgrammingError : Nombre incorrect de liaisons fournies. L'instruction actuelle en utilise 1, et il y en a 0 de fournis."

Je peux lire la base de données sans problème.

Toute aide serait très appréciée.

from tkinter import *
import sqlite3

    class mainGUI(object):

    def __init__(self,window):

        self.window=window 

        self.E1 = Entry(window)                           
        self.E1.grid(row=1, column=0)
        self.EG1 = self.E1.get()

        global E4
        E4 = Listbox(window)                           
        E4.grid(row=2)

        B1 = Button(window, text="Add entry", command=lambda: database.insert(self.EG1)) 

        B1.grid(row=1, column=4)

        B2 = Button(window, text="View all", command=database.view_all)  
        B2.grid(row=2, column=4, sticky="WN")

        window.mainloop()

class Database(mainGUI):

    def __init__(self, db):
        self.conn = sqlite3.connect(db)
        self.curs = self.conn.cursor() 
        self.curs.execute("CREATE TABLE IF NOT EXISTS diary (date TEXT)")   
        self.conn.commit()

    def insert(self,date): 
        database.add_entry(date) 
        E4.delete(0, END)
        E4.insert(END,(date))

    def add_entry(self,date):     
        self.curs.execute("INSERT INTO diary VALUES (?)", (date))
        self.conn.commit()

    def view_all(self): 
        E4.delete(0, END)    
        self.curs.execute("SELECT * FROM diary")
        data = self.curs.fetchall()
        for row in data:
           E4.insert(END,row)                           

if __name__ == "__main__":   
    database = Database("dbase.db")
    window=Tk()
    gui = mainGUI(window)

2voto

Bryan Oakley Points 63365

Si vous utilisez des classes, vous ne devriez pas utiliser de variables globales. Au lieu de cela, vous devez accéder aux attributs et aux méthodes de vos instances d'objets. Cela signifie qu'il faut créer des E4 comme une variable d'instance, et y accéder via l'instance de la classe GUI.

En outre, votre base de données doit no hériter de mainGUI . Ce n'est pas ainsi qu'il faut utiliser l'héritage.

Votre base de données est codée de telle sorte qu'il faut modifier l'interface graphique, ce qui est inhabituel. Au contraire, votre interface graphique devrait être la seule chose qui peut modifier l'interface graphique, et votre base de données devrait être la seule chose qui modifie la base de données. Lorsque l'interface graphique a besoin d'envoyer des informations à la base de données ou d'en obtenir, elle peut appeler des méthodes sur la base de données.

Donc, la première étape est de passer l'objet de la base de données à votre mainGUI (qui devrait être nommée MainGUI selon le PEP8) :

class MainGUI(object):
    def __init__(self,window, db):
        self.window = window
        self.db = db
        ...

Ensuite, passez l'objet base de données lorsque vous créez l'interface graphique :

if __name__ == "__main__":   
    database = Database("dbase.db")
    window=Tk()
    gui = MainGUI(window, database)

Avec cela, vous pouvez maintenant utiliser la base de données pour obtenir et récupérer des données, et utiliser l'interface graphique pour afficher les données.

Par exemple, votre interface graphique devrait avoir la méthode "view_all", puisqu'elle traite de la modification de la vue. Elle doit appeler la méthode "get_all" de la base de données. Par no en utilisant lambda votre code devient beaucoup plus facile à lire, à écrire et à déboguer.

class mainGUI(object):
    def __init__(self,window, db):
        ...
        self.E4 = Listbox(...)
        ...
        B2 = Button(..., command=self.view_all) 

    def view_all(self):
        data = self.db.get_all()
        self.E4.delete(0, END)    
        for row in data:
           self.E4.insert(END,row)

Enfin, créez un get_all dans votre Database qui ne fait rien d'autre que de récupérer et de renvoyer les données :

class MainGUI(object):
    def get_all(self):   
        self.curs.execute("SELECT * FROM diary")
        data = self.curs.fetchall()
        return data

Avec tout ce qui précède, et après avoir appliqué les mêmes concepts aux autres méthodes (c'est-à-dire la méthode Database ne doit que définir ou obtenir des données), vous disposez d'une classe réutilisable. Database qui est complètement indépendante de l'interface graphique qui l'utilise.

0voto

v.coder Points 931

Une chose que j'ai remarqué, c'est que tu n'as pas associé de textvariable au widget Entry, ce qui fait qu'il transmet une valeur nulle à l'autre classe. Veuillez essayer de faire self.EG1 a textvariable et le passe ensuite à la fonction.

    self.EG1 = StringVar()
    self.E1 = Entry(window,textvariable=self.EG1)                           
    self.E1.grid(row=1, column=0)

    B1 = Button(window, text="Add entry", command=lambda: database.insert(self.EG1.get()))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X