Tkinter: Falsche Anordnung in my_tree nach Schließung der Anwendung

Fragen zu Tkinter.
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

Hallo, ich hab eine GUI in Tkinter mit DB, ich füge Daten in die my_tree Tabelle hinzu und dabei sind die richtig zu den Spalten zugeordnet. Wenn ich die Anwendung schließe und wieder öffne dann steht in der Spalte "lastname" nur noch ein Komma mit einfachen Anführungszeichen links und bei den anderen Spalten jeweils links von dem eingegeben Wort ebenfalls ein einfaches Anführungszeichen.

#build the create table query
if not table_exists:
query = f"CREATE TABLE {schema}.{table_name} ("
for column in columns:
column_name, data_type, constraints = column
query += f"{column_name} {data_type} {constraints}, "
query = query.rstrip(', ') + ")"
cursor.execute(query)
conn.commit()
print(f"Table '{table_name}' created succesfully.")
else:
print(f"Table '{table_name}' already exists.")


def add_data():
studid = studId_textbox.get()
fname = firstname_textbox.get()
lname = lastname_textbox.get()
adress = address_textbox.get()

if studid.strip() == "" or fname.strip() == "" or lname.strip() == "" or adress.strip() == "":
messagebox.showinfo("Error", "Please fill up all the fields!")

else:
try:
studid = int(studid)
query = f"INSERT INTO {table_name} (stud_id, firstname, lastname, adress) VALUES ( ?, ? ,? ,?) "
cursor.execute(query, (studid, fname , lname, adress))
conn.commit()
messagebox.showinfo("Data added succesfully!")

#insert data into my_tree
my_tree.insert("", "end" , values=(studid, fname, lname, adress))


except Exception as e:
messagebox.showinfo("Error", f"Failed to add data: {str(e)}")



def del_data():
select_data = my_tree.focus()

if select_data:
values = my_tree.item(select_data)['values']
stud_id = int(values[0])
query = f"DELETE FROM {table_name} WHERE stud_id = ?"
cursor.execute(query, (stud_id,))
conn.commit()

my_tree.delete(select_data)



def load_data():
query = f"SELECT stud_id, firstname, lastname, adress FROM {table_name}"
cursor.execute(query)
rows = cursor.fetchall()


for row in rows:
studid, fname, lname, adress = row
my_tree.insert("", "end", values=row)
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte Code in code-tags setzen, damit er lesbar und semantisch korrekt bleibt, weil sonst die Einrueckungen verloren gehen.

Und das hier ist ein brilliantes Beispiel fuer die ungewollten Seiten-Effekte beim unnoetigen abkuerzen von Namen. stud_id heisst nicht, was du meinst, was es heisst. Jeder native speaker liegt auf dem Boden, weil du die hengst_id (gerne auch verstanden im Zusammenhang mit einem promiskuitiven Mann) abfragst.

Dann sind da ein paar Kardinalfehler drin. Zuviele globale Variablen, die Erzeugung der Tabelle sollte da nicht drin sein, genausowenig wie string-formatierte SQL-Statements. Statt solcher Bandwurm-ifs baut man eine simple Pruefung aller Entries mit

Code: Alles auswählen

if not all(value for value in [first_name, last_name, ..]):
    # fill out all entries
Das strip muss auch *vor* die Zuweisung, denn sonst vergleichst du gestrippte Daten, aber verarbeitest die Rohdaten weiter.

Eingerueckt wird auch immer mit 4 Leerzeichen, nicht 2.

Zur eigentlichen Frage: was steht denn in der Datenbank? Ist es das, was du erwartest? Und was kommt aus der Datenbank an der Stelle, an der du die Daten in den Baum ueberfuehren willst?
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

ich werde mich darum kümmern.
in der datenbank wird alles richtig zugeordnet.

Code: Alles auswählen

 
table_name = 'StudData'
schema = 'dbo'
columns = [
    ('stud_id', 'INT', 'PRIMARY KEY' ),
    ('firstname', 'CHAR(50)', 'NOT NULL'),
    ('lastname', 'CHAR(50)', 'NOT NULL'),
    ('adress', 'VARCHAR(100)', 'NOT NULL')
]

#check if table exists
cursor.execute(f"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '{table_name}'")
table_exists = cursor.fetchone()[0]

#build the create table query
if not table_exists:
    query = f"CREATE TABLE {schema}.{table_name} ("
    for column in columns:
     column_name, data_type, constraints = column
     query += f"{column_name} {data_type} {constraints}, "
    query = query.rstrip(', ') + ")"
    cursor.execute(query)
    conn.commit()
    print(f"Table '{table_name}' created succesfully.")
else:
    print(f"Table '{table_name}' already exists.")

#execute




def add_data():
  studid = studId_textbox.get()
  fname = firstname_textbox.get()
  lname = lastname_textbox.get()
  adress = address_textbox.get()

  if studid.strip() == "" or fname.strip() == "" or lname.strip() == "" or adress.strip() == "":
      messagebox.showinfo("Error", "Please fill up all the fields!")

  else:
      try:
          studid = int(studid)
          query = f"INSERT INTO {table_name}  (stud_id, firstname, lastname, adress) VALUES ( ?, ? ,? ,?) "
          cursor.execute(query, (studid, fname , lname, adress))
          conn.commit()
          messagebox.showinfo("Data added succesfully!")

          #insert data into my_tree
          my_tree.insert("", "end" , values=(studid, fname, lname, adress))


      except Exception as e:
          messagebox.showinfo("Error", f"Failed to add data: {str(e)}")





def del_data():
    select_data = my_tree.focus()

    if select_data:
        values = my_tree.item(select_data)['values']
        stud_id = int(values[0])
        query = f"DELETE FROM {table_name} WHERE stud_id = ?"
        cursor.execute(query, (stud_id,))
        conn.commit()

        my_tree.delete(select_data)




def load_data():
    query = f"SELECT stud_id, firstname, lastname, adress FROM {table_name}"
    cursor.execute(query)
    rows = cursor.fetchall()


    for row in rows:
        studid, fname, lname, adress = row
        my_tree.insert("", "end", values=row)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Zwischen Funktionen werden maximal zwei Leerzeilen gesetzt, bei 4 bis 5 wirkt der Code zu zerissen. Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal zwei und mal vier.

Man formatiert keine SQL-Statements zusammen; Tabellennamen sind fix für die Datenbank, ebenso Spaltennamen. Werte werden über Platzhalter an die Datenbank übergeben, was Du ja schon machst.
Wenn man wirklich immer die Tabllen erzeugen will, dann benutzt man `create table if not exists` statt irgendeine interne Tabelle nach dem Tabellennamen zu durchsuchen.
Man benutzt keine Abkürzungen, so allgemeine Anhängsel wie Data trägt nicht zum Verständnis und kann weg.
`cursor` sind etwas kurzlebiges, was bei Bedarf erzeugt wird, statt eine globalen Cursor zu benutzen.
Das Erzeugen einer Tabelle braucht kein commit.
CHAR zu benutzen, macht bei heutigen Datenbanken keinen Sinn mehr und ist oft sogar kontraproduktiv.
Man benutzt keine globalen Variablen, bei add_data fehlen die ganzen Textboxen und die Datenbankverbindung als Argumente.

Bei Dir gibt es wirklich viel Data, auch noch select_data.

Das ganze könnte also so aussehen:

Code: Alles auswählen

from contextlib import closing

SQL_CREATE_STUDENT_TABLE = """
    CREATE TABLE IF NOT EXISTS dbo.Student (
        student_id INT PRIMARY KEY,
        firstname VARCHAR NOT NULL,
        lastname VARCHAR NOT NULL,
        address VARCHAR NOT NULL
    )
"""
SQL_INSERT_STUDENT = """
    INSERT INTO dbo.Student (student_id, firstname, lastname, address) VALUES (?, ?, ?, ?)
"""
SQL_DELETE_STUDENT = """
    DELETE FROM dbo.Student where student_id=?
"""
SQL_SELECT_STUDENT = """
    SELECT student_id, firstname, lastname, address from dbo.Student
"""

def create_student_table(db_connection):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_CREATE_STUDENT_TABLE)
    print(f"Table 'Student' created succesfully.")


def add_student(db_connection, student_tree, student_id_textbox, firstname_textbox, lastname_textbox, address_textbox):
    student_id = student_id_textbox.get().strip()
    firstname = firstname_textbox.get().strip()
    lastname = lastname_textbox.get().strip()
    address = address_textbox.get().strip()
    if not student_id or not firstname or not lastname or not address:
        messagebox.showinfo("Error", "Please fill up all the fields!")
    else:
        try:
            with closing(db_connection.cursor()) as cursor:
                cursor.execute(SQL_INSERT_STUDENT, (int(student_id), firstname, lastname, address))
            db_connection.commit()
        except Exception as e:
            messagebox.showinfo("Error", f"Failed to add data: {e}")
        messagebox.showinfo("Data added succesfully!")
        student_tree.insert("", "end" , values=(student_id, firstname, lastname, address)


def del_student(db_connection, student_tree):
    selection = student_tree.focus()
    if selection:
        values = student_tree.item(selection)['values']
        student_id = int(values[0])
        with closing(db_connection.cursor()) as cursor:
            cursor.execute(SQL_DELETE_STUDENT, (int(student_id))
        db_connection.commit()
        student_tree.delete(selection)


def load_students(db_connection, student_tree):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_SELECT_STUDENT)
        for student_id, firstname, lastname, address in cursor:
            student_tree.insert("", "end", values=(student_id, firstname, lastname, address))
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde da noch SQLAlchemy in den Raum werfen wollen.

Beim Hinzufügen eines neuen Studenten würde man eher nicht den Benutzer eine ID eintragen lassen. Die könnte ja bereits existieren. Das überlässt man in der Regel der Datenbank.

Die `student_id` in der Datenbank würde ich noch in `id` umbenennen. Das es sich um die ID für einen Studenten handelt, wird ja schon durch den Tabellennamen ausgedrückt. Namenszusätze bei IDs sind eher etwas für Fremdschlüssel.

Ungetestet:

Code: Alles auswählen

import tkinter as tk
from tkinter import messagebox

from sqlalchemy import INT, VARCHAR, Column, select
from sqlalchemy.orm import declarative_base

Base = declarative_base()


class Student(Base):
    __tablename__ = "dbo.student"

    id = Column("student_id", INT, primary_key=True)
    firstname = Column(VARCHAR, nullable=False)
    lastname = Column(VARCHAR, nullable=False)
    address = Column(VARCHAR, nullable=False)


def create_student_table(engine):
    Student.__table__.create(engine, checkfirst=True)
    print("Table 'Student' created succesfully.")


def add_student(
    db_session,
    student_tree,
    firstname_textbox,
    lastname_textbox,
    address_textbox,
):
    firstname = firstname_textbox.get().strip()
    lastname = lastname_textbox.get().strip()
    address = address_textbox.get().strip()
    if not all(firstname, lastname, address):
        messagebox.showinfo("Error", "Please fill out all the fields!")
    else:
        try:
            student = Student(
                firstname=firstname, lastname=lastname, address=address
            )
            db_session.add(student)
            db_session.commit()
        except Exception as error:
            messagebox.showinfo("Error", f"Failed to add data: {error}")
        else:
            messagebox.showinfo("Data added succesfully!")
            student_tree.insert(
                "", tk.END, values=(student.id, firstname, lastname, address)
            )


def del_student(db_session, student_tree):
    selection = student_tree.focus()
    if selection:
        student_id = int(student_tree.item(selection)["values"][0])
        db_session.delete(db_session.get(Student, student_id))
        db_session.commit()
        student_tree.delete(selection)


def load_students(db_session, student_tree):
    for student in db_session.execute(select(Student)):
        student_tree.insert(
            "",
            tk.END,
            values=(
                student.id,
                student.firstname,
                student.lastname,
                student.address,
            ),
        )
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

Danke erstmal an euch beide aber ist das nicht so richtig eingesetzt? Nur wird in der DB keine Tabelle erstellt. PS: __blackjack__ dein Code ist mir als Anfänger erstmal zu kompliziert :)

Code: Alles auswählen

server_name = 'DESKTOP-FC3VM4U\SQLEXPRESS'
database_name = 'MANAGEMENT'

conn_str = 'Driver={SQL Server};Server=' + server_name + ';Database=' + database_name + ';Trusted_Connection=yes;'

conn = pyodbc.connect(conn_str)
cursor = conn.cursor()

SQL_CREATE_STUDENT_TABLE = """ 
    CREATE TABLE IF NOT EXISTS dbo.Student (
    student_id INT PRIMARY KEY,
    firstname VARCHAR NOT NULL,
    lastname VARCHAR NOT NULL,
    address VARCHAR NOT NULL
    )
"""

SQL_INSERT_STUDENT = """ INSERT INTO dbo.Student (student_id, firstname, lastname, address) VALUES (?, ? , ? , ? )"""
SQL_DELETE_STUDENT = """ DELETE FROM dbo.Student where student_id = ? """
SQL_SELECT_STUDENT = """ SELECT student_id, firstname, lastname, address from dbo.Student """

def create_student_table(conn):
    with closing (conn.cursor()) as cursor:
            cursor.execute(SQL_CREATE_STUDENT_TABLE)
    print("Table 'Student' created successfully ")
   
.....
root.mainloop()
create_student_table(conn)
    
    
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Der "Mainloop" ist genau das, was der Name sagt: Ein Loop. Also eine Schleife.
Jedes mir bekannte GUI-Framework hat einen solchen Loop, der endlos läuft und dafür sorgt, dass die Oberfläche "gezeichnet" wird. Dieser Mainloop darf niemals unterbrochen werden - zum Beispiel durch länger laufende Programmteile oder Berechnungen. Unter Windows erhälst du sonst die Meldung, dass die Anwendung nicht mehr reagiert.

Du startest den Loop und möchtest danach noch etwas tun. Aber diese Stelle im Code wird frühestens erreicht, wenn die GUI nicht mehr läuft - wenn überhaupt.

Zum Code:
Auf Modulebene, also nicht eingrückt, sollte nur folgendes stehen: Importe; die Definition von Konstaten (nicht Variablen!), Klassen und Funktionen. Das haben die Codebeispiele von Sirius3 und __blackjack__ bereits vorgemacht.
Wenn du nicht verstehst, wie man das vermeidet - also Funktionen korrekt einsetzt, dann frag nach, bevor du dich völlig falsch verrennst. Nur weil in Python Dinge möglich sind, heißt das nicht, dass sie richtig sind.

Das mit dem Nachfragen gilt auch für Code, der dir hier zu kompliziert erscheint. Fage nach den Stellen, die du nicht verstehst. Eine bessere Möglichkeit an (deinem verbesserten) Code zu lernen, gibt es wohl kaum.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@magocode: Was ist denn daran zu kompliziert? Der ist doch *einfacher* geworden.

Natürlich wird in Deinem neuen Code keine Tabelle erstellt. Der `mainloop()`-Aufruf startet die GUI und kehrt erst wieder zurück wenn das Hauptfenster geschlossen wird.

Das sollte wie schon erwähnt auch alles nicht auf Modulebene stehen. Da gehört nur Code hin, der Konstanten, Funktionen, und Klassen definiert. Konstanten werden per Konvention KOMPLETT_GROSS geschrieben.

Die Datenbankverbindung sollte auch wieder geschlossen werden.

Code: Alles auswählen

import tkinter as tk
from contextlib import closing

import pyodbc

SERVER_NAME = R"DESKTOP-FC3VM4U\SQLEXPRESS"
DATABASE_NAME = "MANAGEMENT"

SQL_CREATE_STUDENT_TABLE = """ 
    CREATE TABLE IF NOT EXISTS dbo.student (
        student_id INT PRIMARY KEY,
        firstname VARCHAR NOT NULL,
        lastname VARCHAR NOT NULL,
        address VARCHAR NOT NULL
    )
"""
SQL_INSERT_STUDENT = """
    INSERT INTO dbo.student (student_id, firstname, lastname, address)
        VALUES (?, ?, ?, ?)
"""
SQL_DELETE_STUDENT = "DELETE FROM dbo.Student where student_id = ?"
SQL_SELECT_STUDENT = (
    "SELECT student_id, firstname, lastname, address from dbo.Student"
)


def create_student_table(db_connection):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_CREATE_STUDENT_TABLE)
    print("Table 'student' created successfully.")


def main():
    root = tk.Tk()
    
    with closing(
        pyodbc.connect(
            f"Driver={{SQL Server}};"
            f"Server={SERVER_NAME};"
            f"Database={DATABASE_NAME};"
            f"Trusted_Connection=yes;"
        )
    ) as db_connection:
        create_student_table(db_connection)
        ...
        root.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

Ich bin gerade verwirrt, also mein Code hatte ja soweit funktioniert bis das nach Neustart die Daten in my_tree verschoben wurden...

Code: Alles auswählen

  import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from contextlib import closing

import pyodbc as pyodbc
import pypyodbc

server_name = 'DESKTOP-FC3VM4U\SQLEXPRESS'
database_name = 'MANAGEMENT'

conn_str = 'Driver={SQL Server};Server=' + server_name + ';Database=' + database_name + ';Trusted_Connection=yes;'

conn = pyodbc.connect(conn_str)
cursor = conn.cursor()

SQL_CREATE_STUDENT_TABLE = """ 
    CREATE TABLE IF NOT EXISTS dbo.Student (
    student_id INT PRIMARY KEY,
    firstname VARCHAR NOT NULL,
    lastname VARCHAR NOT NULL,
    address VARCHAR NOT NULL
    )
"""

SQL_INSERT_STUDENT = """ INSERT INTO dbo.Student (student_id, firstname, lastname, address) VALUES (?, ? , ? , ? )"""
SQL_DELETE_STUDENT = """ DELETE FROM dbo.Student where student_id = ? """
SQL_SELECT_STUDENT = """ SELECT student_id, firstname, lastname, address from dbo.Student """

def create_student_table(conn):
    with closing(conn.cursor()) as cursor:
        cursor.execute(SQL_CREATE_STUDENT_TABLE)
    print("Table 'student' created successfully.")



def add_student(conn, student_tree, student_id_textbox, firstname_textbox, lastname_textbox, address_textbox ):
    student_id = student_id_textbox.get().strip()
    firstname = firstname_textbox.get().strip()
    lastname = lastname_textbox.get().strip()
    address = address_textbox.get().strip()

    if not student_id or not firstname or not lastname or not address:
        messagebox.showinfo("Error", "Please fill up all the fields")
    else:
        try:
            with closing (conn.cursor()) as cursor:
                cursor.execute(SQL_INSERT_STUDENT, (int(student_id), firstname, lastname, address))
            conn.commit()
        except Exception as e:
            messagebox.showinfo("Error", f"Failed to add data: {e}")
        messagebox.showinfo("Data added succesfully!")
        student_tree.insert("", "end", values = (student_id, firstname,lastname,address))








# create table in database
# table_name = 'StudData'
# schema = 'dbo'
# columns = [
#     ('stud_id', 'INT', 'PRIMARY KEY' ),
#     ('firstname', 'CHAR(50)', 'NOT NULL'),
#     ('lastname', 'CHAR(50)', 'NOT NULL'),
#     ('adress', 'VARCHAR(100)', 'NOT NULL')
# ]
#
# #check if table exists
# cursor.execute(f"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '{table_name}'")
# table_exists = cursor.fetchone()[0]
#
# #build the create table query
# if not table_exists:
#     query = f"CREATE TABLE {schema}.{table_name} ("
#     for column in columns:
#      column_name, data_type, constraints = column
#      query += f"{column_name} {data_type} {constraints}, "
#     query = query.rstrip(', ') + ")"
#     cursor.execute(query)
#     conn.commit()
#     print(f"Table '{table_name}' created succesfully.")
# else:
#     print(f"Table '{table_name}' already exists.")
#
# #execute
#
#
#
#
# def add_data():
#   studid = studId_textbox.get()
#   fname = firstname_textbox.get()
#   lname = lastname_textbox.get()
#   adress = address_textbox.get()
#
#   if studid.strip() == "" or fname.strip() == "" or lname.strip() == "" or adress.strip() == "":
#       messagebox.showinfo("Error", "Please fill up all the fields!")
#
#   else:
#       try:
#           studid = int(studid)
#           query = f"INSERT INTO {table_name}  (stud_id, firstname, lastname, adress) VALUES ( ?, ? ,? ,?) "
#           cursor.execute(query, (studid, fname , lname, adress))
#           conn.commit()
#           messagebox.showinfo("Data added succesfully!")
#
#           #insert data into my_tree
#           my_tree.insert("", "end" , values=(studid, fname, lname, adress))
#
#
#       except Exception as e:
#           messagebox.showinfo("Error", f"Failed to add data: {str(e)}")
#
#
#
#
#
# def del_data():
#     select_data = my_tree.focus()
#
#     if select_data:
#         values = my_tree.item(select_data)['values']
#         stud_id = int(values[0])
#         query = f"DELETE FROM {table_name} WHERE stud_id = ?"
#         cursor.execute(query, (stud_id,))
#         conn.commit()
#
#         my_tree.delete(select_data)
#
#
#
#
# def load_data():
#     query = f"SELECT stud_id, firstname, lastname, adress FROM {table_name}"
#     cursor.execute(query)
#     rows = cursor.fetchall()
#
#
#     for row in rows:
#         studid, fname, lname, adress = row
#         my_tree.insert("", "end", values=row)




root = tk.Tk()
root.geometry("900x650")
root.title("Student Registration System")
student_tree = ttk.Treeview(root)

student_id = tk.Label(root, text="Student ID", font=("Arial", 12))
student_id.grid(row=0, column=0, padx=1, pady=1)

student_id_textbox = tk.Entry(root, font=("Arial", 12))
student_id_textbox.grid(row=0, column=1, padx=5, pady=5)

firstname = tk.Label(root, text="Firstname", font=("Arial", 12))
firstname.grid(row=1, column=0, padx=1, pady=1)

firstname_textbox = tk.Entry(root, font=("Arial", 12))
firstname_textbox.grid(row=1, column=1, padx=5, pady=5)

lastname = tk.Label(root, text="Lastname", font=("Arial", 12))
lastname.grid(row=2, column=0, padx=1, pady=1)

lastname_textbox = tk.Entry(root, font=("Arial", 12))
lastname_textbox.grid(row=2, column=1, padx=5, pady=5)

address = tk.Label(root, text="Address", font=("Arial", 12))
address.grid(row=3, column=0, padx=1, pady=1)

address_textbox = tk.Entry(root, font=("Arial", 12))
address_textbox.grid(row=3, column=1, padx=5, pady=5)

button_frame = tk.Frame(root)
button_frame.grid(row=0, column=2, rowspan=6, padx=1, pady=1)

add_button = tk.Button(button_frame, text="Add", font=("Arial", 12), command= add_student, height=2, width=15)
add_button.pack(side="top", padx=1, pady=5)

update_button = tk.Button(button_frame, text="Update", font=("Arial", 12), height=2, width=15)
update_button.pack(side="top", padx=1, pady=5)

delete_button = tk.Button(button_frame, text="Delete", font=("Arial", 12),  height=2, width=15)
delete_button.pack(side="top", padx=1, pady=5)

search_button = tk.Button(button_frame, text="Search", font=("Arial", 12), height=2, width=15)
search_button.pack(side="top", padx=1, pady=5)

reset_button = tk.Button(button_frame, text="Reset", font=("Arial", 12), height=2, width=15)
reset_button.pack(side="top", padx=1, pady=5)

select_button = tk.Button(button_frame, text="Select", font=("Arial", 12), height=2, width=15)
select_button.pack(side="top", padx=1, pady=5)

student_tree.grid(row=6, column=0, columnspan=2, padx=10, pady=10)

#define our columns
student_tree['columns'] = ("Student ID", "Firstname", "Lastname", "Address")

#format our columns
student_tree.column("#0", width=0, stretch= 0)
student_tree.column("Student ID", width=100)
student_tree.column("Firstname", width=150)
student_tree.column("Lastname", width=150)
student_tree.column("Address", width=200)

#create heading
student_tree.heading("Student ID", text="Student ID")
student_tree.heading("Firstname", text="Firstname")
student_tree.heading("Lastname", text="Lastname")
student_tree.heading("Address", text="Address")



#load_data()
#create_student_table(conn)
root.mainloop()  
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Die gesamte GUI wird noch immer global definiert.

Aber was genau verwirrt dich jetzt? Was geht? Was geht nicht? Fehlermeldungen?
Da `create_student_table` nie aufgerufen wird, wird die Tabelle natürlich nicht angelegt, falls das deine Verwirrung begründet.
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

genau das , an welcher stelle muss ich die funktion "create_student_table" aufrufen?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@magocode: An der Stelle an der das im Programmablauf passieren soll. Vermutlich vor dem Aufruf der GUI-Hauptschleife.

`add_student()` erwartet sechs Argumente, bekommt aber 0. Da muss man beispielsweise mit `functools.partial()` arbeiten um eine Funktion zu erzeugen die kein Argument erwartet und `add_student()` dann mit den entsprechenden Werten aufruft. Oder man schreibt eine eigene Klasse. Darauf läuft das bei GUI-Programmierung letztendlich sowieso hinaus, denn `functools.partial()` hat seine Grenzen und unübersichtlich ist es auch.

Ich würde `add_student()` die Texteingabefelder auch nicht einzeln übergeben, sondern als Liste. Da könnte man sowieso einiges an Wiederholungen von Code und Daten durch Schleifen ausdrücken. Und man muss auch nicht jedes Zwischenergebnis an einen Namen binden. Die Label die als Beschriftung für die Eingabefelder dienen, müssen beispielsweise nicht an verschiedene Namen gebunden werden, oder halt auch überhaupt gar nicht an einen Namen wenn man darauf nur eine einzige Methode aufruft und danach nie wieder darauf zugreift.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

@magocode: Naja, an welcher Stelle soll sie denn ausgeführt werden?
Immer, wenn das Programm startet? Dann an einer Stelle bevor du den Mainloop startest.

Ich denke, dir würde auch der Überblick sehr viel leichter fallen, wenn du nicht alle GUI-Elemente auf der Modulebene anlegen würdest. Das wurde ja schon mehrfach gesagt.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Da Du jetzt verschiedene Sachen gemischt hast, funktioniert das Programm so gar nicht mehr.
Saubere Programme benutzen schon konsequent keine globalen Variablen.
Warum das Verstümmeln von db_connection wieder zu conn notwendig ist, ist mir ein Rätsel.
Es wird auch noch ein globaler Cursor erzeugt, der nicht mehr gebraucht wird.

Bessert man das alles aus, funktioniert Dein Programm bei mir fehlerfrei.

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from contextlib import closing
from functools import partial
import pyodbc

SERVER_NAME = 'DESKTOP-FC3VM4U\SQLEXPRESS'
DATABASE_NAME = 'MANAGEMENT'
CONNECTION_PARAMETERS = f'Driver={{SQL Server}};Server={SERVER_NAME};Database={DATABASE_NAME};Trusted_Connection=yes;'

SQL_CREATE_STUDENT_TABLE = """ 
    CREATE TABLE IF NOT EXISTS Student (
    student_id INT PRIMARY KEY,
    firstname VARCHAR NOT NULL,
    lastname VARCHAR NOT NULL,
    address VARCHAR NOT NULL
    )
"""

SQL_INSERT_STUDENT = """ INSERT INTO Student (student_id, firstname, lastname, address) VALUES (?, ? , ? , ? )"""
SQL_DELETE_STUDENT = """ DELETE FROM Student where student_id = ? """
SQL_SELECT_STUDENT = """ SELECT student_id, firstname, lastname, address from Student """

def create_student_table(db_connection):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_CREATE_STUDENT_TABLE)
    print("Table 'student' created successfully.")


def add_student(db_connection, student_tree, student_id_textbox, firstname_textbox, lastname_textbox, address_textbox):
    student_id = student_id_textbox.get().strip()
    firstname = firstname_textbox.get().strip()
    lastname = lastname_textbox.get().strip()
    address = address_textbox.get().strip()

    if not student_id or not firstname or not lastname or not address:
        messagebox.showinfo("Error", "Please fill up all the fields")
    else:
        try:
            with closing(db_connection.cursor()) as cursor:
                cursor.execute(SQL_INSERT_STUDENT, (int(student_id), firstname, lastname, address))
            db_connection.commit()
        except Exception as e:
            messagebox.showinfo("Error", f"Failed to add data: {e}")
        messagebox.showinfo("Data added succesfully!")
        student_tree.insert("", "end", values = (student_id, firstname,lastname,address))


def load_students(db_connection, student_tree):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_SELECT_STUDENT)
        for student_id, firstname, lastname, address in cursor:
            print(student_id, firstname, lastname, address)
            student_tree.insert("", "end", values=(student_id, firstname, lastname, address))


def load_students(db_connection, student_tree):
    with closing(db_connection.cursor()) as cursor:
        cursor.execute(SQL_SELECT_STUDENT)
        for student_id, firstname, lastname, address in cursor:
            student_tree.insert("", "end", values=(student_id, firstname, lastname, address))


def main():
    db_connection = pyodbc.connect(CONNECTION_PARAMETERS)
    
    root = tk.Tk()
    root.title("Student Registration System")
    student_tree = ttk.Treeview(root)

    textbox_frame = tk.Frame(root)
    textbox_frame.grid(row=0, column=0, padx=1, pady=1)
    tk.Label(textbox_frame, text="Student ID").grid(row=0, column=0, padx=1, pady=1, sticky=tk.E)
    student_id_textbox = tk.Entry(textbox_frame)
    student_id_textbox.grid(row=0, column=1, padx=5, pady=5)

    tk.Label(textbox_frame, text="Firstname").grid(row=1, column=0, padx=1, pady=1, sticky=tk.E)
    firstname_textbox = tk.Entry(textbox_frame)
    firstname_textbox.grid(row=1, column=1, padx=5, pady=5)

    tk.Label(textbox_frame, text="Lastname").grid(row=2, column=0, padx=1, pady=1, sticky=tk.E)
    lastname_textbox = tk.Entry(textbox_frame)
    lastname_textbox.grid(row=2, column=1, padx=5, pady=5)

    tk.Label(textbox_frame, text="Address").grid(row=3, column=0, padx=1, pady=1, sticky=tk.E)
    address_textbox = tk.Entry(textbox_frame)
    address_textbox.grid(row=3, column=1, padx=5, pady=5)

    button_frame = tk.Frame(root)
    button_frame.grid(row=0, column=1, padx=1, pady=1)

    tk.Button(button_frame, text="Add",
        command=partial(add_student, db_connection, student_tree, student_id_textbox, firstname_textbox, lastname_textbox, address_textbox),
    ).pack(padx=1, pady=5, fill=tk.X)

    tk.Button(button_frame, text="Update").pack(padx=1, pady=5, fill=tk.X)

    tk.Button(button_frame, text="Delete").pack(padx=1, pady=5, fill=tk.X)

    tk.Button(button_frame, text="Search").pack(padx=1, pady=5, fill=tk.X)

    tk.Button(button_frame, text="Reset").pack(padx=1, pady=5, fill=tk.X)

    tk.Button(button_frame, text="Select").pack(padx=1, pady=5, fill=tk.X)

    student_tree.grid(row=1, column=0, columnspan=2, padx=10, pady=10)

    #define our columns
    student_tree['columns'] = ("Student ID", "Firstname", "Lastname", "Address")

    #format our columns
    student_tree.column("#0", width=0, stretch= 0)
    student_tree.column("Student ID", width=100)
    student_tree.column("Firstname", width=150)
    student_tree.column("Lastname", width=150)
    student_tree.column("Address", width=200)

    #create heading
    student_tree.heading("Student ID", text="Student ID")
    student_tree.heading("Firstname", text="Firstname")
    student_tree.heading("Lastname", text="Lastname")
    student_tree.heading("Address", text="Address")

    create_student_table(db_connection)
    load_students(db_connection, student_tree)
    root.mainloop()

if __name__ == "__main__":
    main()
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

wenn ich es vor mainloop mache dann started die anwendung nicht, hatte es deshalb danach geschrieben gehabt :) die anderen tipps versuche ich mal umzusetzen aber wäre erstmal glücklich wenn die tabelle erstellt wird in der datenbank
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Dann würde ich mal nach der Fehlermeldung suchen.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was heisst das? An der Funktion ist nichts zu seheh, dass das nahelegen wuerde. Also muss es etwas sein, dass du anders machst. Zeig den konkreten Code den du probierst, und die konkrete Fehlermeldung.
magocode
User
Beiträge: 24
Registriert: Dienstag 9. Mai 2023, 08:53

@Sirius3 Ich habe den Code so kopiert, Fehlermeldung:
Traceback (most recent call last):
File "C:\Users\mago\PycharmProjects\Projects\main.py", line 133, in <module>
main()
File "C:\Users\mago\PycharmProjects\Projects\main.py", line 127, in main
create_student_table(db_connection)
File "C:\Users\mago\PycharmProjects\Projects\main.py", line 28, in create_student_table
cursor.execute(SQL_CREATE_STUDENT_TABLE)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'IF'. (156) (SQLExecDirectW); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near 'Student'. (102)")

Process finished with exit code 1
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

SQL-Server kennt das ``IF NOT EXIST`` wohl nicht. Ein Grund mehr auf SQLAlchemy umzusteigen um von solchen produkspezifischen Unterschieden zwischen SQL-Datenbanken weg zu kommen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

@magocode: __blackjack__ hat Recht, SQLAlchemy nimmt einem hier viel Arbeit ab. Denn am Ende wirst du aus den Daten auch noch in Objekte mappen - und auch das nommt SQLAlchemy dir ab.

Solange du noch nicht überzeugt bist - was du sein solltest:

Code: Alles auswählen

SQL_CREATE_STUDENT_TABLE = """ 
IF OBJECT_ID(N'Student', N'U') IS NULL
    CREATE TABLE IF NOT EXISTS Student (
        student_id INT PRIMARY KEY,
        firstname VARCHAR NOT NULL,
        lastname VARCHAR NOT NULL,
        address VARCHAR NOT NULL
    )
GO
"""
Antworten