Mehrere Entry-Einträge in einer Liste speichern

Fragen zu Tkinter.
Antworten
Python.Anfänger
User
Beiträge: 4
Registriert: Mittwoch 14. September 2016, 15:09

Hallo,
ich möchte mir ein Programm mit Python erstellen, das aus txt-Files (zwei Spalten mit Zahlen) Diagramme erstellt. Dabei sollen "Titel", "x-Achse", "y-Achse" und "Labels" über Einträge (Entry) in einem Fenster definiert werden. Da im Diagramm unterschiedlich viele Kurve dargestellt werden sollen, können auch mehrere txt-Files ausgewählt werden.
Möchte ich nun die Labels für mehrere Kurve im Diagramm hinzufügen (ebenfalls über Entry), scheitere ich leider :( Ich würde die "Labels" gerne ebenfalls über Entry-Einträge hinzufügen. Hierfür habe ich eine for-Schleife verwendet.

Code: Alles auswählen

entry = []
for k in range(Anzahl_files):
    tk.Label(window2, text='Label '+str(k+1)).grid(row=3+k, sticky=tk.E)
    entry = tk.Entry(window2, width=50).grid(row=3+k, column=1, padx=20)
#    entry.append(entry)
Kann man die Entry-Einträge in einer Liste speicher, auf die man später wieder gezielt zugreifen kann? Bzw. gibt es eine alternative Lösung für mein Problem?
Im folgenden ist der gesamte Code aufgeführt:

Code: Alles auswählen

# -*- coding: utf-8 -*-
import tkinter as tk
import numpy as np
import matplotlib.pyplot as mpl
#==============================================================================================
def Diagramm_erstellen():
    mpl.figure()
    mpl.grid(True)
        
    mpl.title(entry_t.get())
    mpl.xlabel(entry_x.get())
    mpl.ylabel(entry_y.get())
    
    for i in filenames:
            data = np.loadtxt(i)
            x = data[0:,0]
            y = data[0:,1]        
            mpl.plot(x, y, label='')    # im label soll auf Entry-Einträge zugegriffen werden
    mpl.legend(loc=4, fontsize=10)
    mpl.show()
#==============================================================================================        
global filenames, entry_t, entry_x, entry_y, entry_s, entry
# txt-Files auswählen:
filenames = tk.filedialog.askopenfilenames(defaultextension='.txt', title='Dateien auswählen')
Anzahl_files = len(filenames)
#
window2 = tk.Tk()
window2.title('Einstellungen für das Diagramm')
#
tk.Label(window2, text='Titel').grid(row=0, sticky=tk.E)
entry_t = tk.Entry(window2, width=50).grid(row=0, column=1, padx=20)
#
tk.Label(window2, text='x-Achse').grid(row=1, sticky=tk.E)
entry_x = tk.Entry(window2, width=50).grid(row=1, column=1, padx=20)
#
tk.Label(window2, text='y-Achse').grid(row=2, sticky=tk.E)
entry_y = tk.Entry(window2, width=50).grid(row=2, column=1, padx=20)
#
entry = []
for k in range(Anzahl_files):
    tk.Label(window2, text='Label '+str(k+1)).grid(row=3+k, sticky=tk.E)
    entry = tk.Entry(window2, width=50).grid(row=3+k, column=1, padx=20)
#    entry.append(entry)
#  
tk.Button(window2, text='Weiter', command=Diagramm_erstellen).grid(row=5+Anzahl_files, sticky=tk.E)
tk.Button(window2, text='Abbrechen', command=window2.destroy).grid(row=5+Anzahl_files, column=1, padx=20)
#==============================================================================================  
window2.mainloop()
Zuletzt geändert von Anonymous am Mittwoch 14. September 2016, 16:35, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Python.Anfänger
User
Beiträge: 4
Registriert: Mittwoch 14. September 2016, 15:09

Ich habe gerade festgestellt, dass der Code nicht ganz stimmt..
Hier nochmals die neue Version. Dennoch hab ich noch keine Lösung für das speichern der Entry-Einträge in einer Liste gefunden :(

Code: Alles auswählen

# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import filedialog
import numpy as np
import matplotlib.pyplot as mpl
#==============================================================================================
def Diagramm_erstellen():
    mpl.figure()
    mpl.grid(True)
        
    mpl.title(entry_t.get())
    mpl.xlabel(entry_x.get())
    mpl.ylabel(entry_y.get())
    
    for i in filenames:
            data = np.loadtxt(i)
            x = data[0:,0]
            y = data[0:,1]        
            mpl.plot(x, y, label='')    # im label soll auf Entry-Einträge zugegriffen werden
    mpl.legend(loc=4, fontsize=10)
    mpl.show()
#==============================================================================================        
global filenames, entry_t, entry_x, entry_y, entry_s, entry
# txt-Files auswählen:
filenames = tk.filedialog.askopenfilenames(defaultextension='.txt', title='Dateien auswählen')
Anzahl_files = len(filenames)
#
window2 = tk.Tk()
window2.title('Einstellungen für das Diagramm')
#
tk.Label(window2, text='Titel').grid(row=0, sticky=tk.E)
entry_t = tk.Entry(window2, width=50)
entry_t.grid(row=0, column=1, padx=20)
#
tk.Label(window2, text='x-Achse').grid(row=1, sticky=tk.E)
entry_x = tk.Entry(window2, width=50)
entry_x.grid(row=1, column=1, padx=20)
#
tk.Label(window2, text='y-Achse').grid(row=2, sticky=tk.E)
entry_y = tk.Entry(window2, width=50)
entry_y.grid(row=2, column=1, padx=20)
#
entry = []
for k in range(Anzahl_files):
    tk.Label(window2, text='Label '+str(k+1)).grid(row=3+k, sticky=tk.E)
    entry = tk.Entry(window2, width=50)
    entry.grid(row=3+k, column=1, padx=20)
#    entry.append(entry)
#  
tk.Button(window2, text='Weiter', command=Diagramm_erstellen).grid(row=5+Anzahl_files, sticky=tk.E)
tk.Button(window2, text='Abbrechen', command=window2.destroy).grid(row=5+Anzahl_files, column=1, padx=20)
#==============================================================================================  
window2.mainloop()
BlackJack

@Python.Anfänger: Der eigentlich recht offensichtliche Fehler ist das Du die Liste `entry` nennst und das einzelne `Entry`-Examplar auch `entry` nennst. An einen Namen ist zu jedem Zeitpunkt immer nur *ein* Objekt gebunden. Wäre auch komisch wenn das anders wäre, denn sonst wüsste man ja nicht welches Objekt für den Namen eingesetzt wird, wenn man ihn in einem Ausdruck verwendet.

Die Liste solltest Du dann `entries` nennen, denn der Name steht ja für mehrere Eingabefelder und nicht nur eines.

Beim gesamten Quelltext fällt auf, dass Du keine saubere Funktionen geschrieben hast und alles mögliche auf Modulebene existiert was dort nicht hingehört. Dort sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Wenn eine Funktion (oder Methode) Werte (ausser Konstanten) verwendet, kommen die als Argumente in die Funktion und nicht irgendwie ”magisch” aus der Umgebung.

``global`` hat auf Modulebene keinerlei Wirkung, die Zeile kann also ersatzlos wegfallen, und dieses Schlüsselwort solltest Du sofort vergessen. Das löst keine Probleme sondern schafft welche, nämlich undurchsichtige Abhängigkeiten zwischen Funktionen/Methoden die es erschweren sauberen, verständlichen, leicht testbaren und erweiterbaren Code zu schreiben.

Was hat die 2 bei `window2` zu bedeuten? Das ist *das* Hauptfenster. Nummerierte Namen sind ein Warnzeichen das man irgendwas falsch macht.

Abkürzungen sollte man auch vermeiden. Wenn man statt `entry_t` zum Beispiel `title_entry` schreibt, weiss der Leser sofort an jeder Stelle das `t` für „Titel“ steht und nicht zum Beispiel für „Time“, was im Zusammenhang mit Diagrammen ja auch öfter mal vorkommt.

Eine Schleifenvariable `i` sollte nur für ganze Zahlen verwendet werden. Alles andere überrascht fast jeden Programmierer und führt zu Verwirrung. Da Du an der Stelle ”parallel” die Eingabefelder haben möchtest, solltest Du Dir mal die `zip()`-Funktion anschauen.

Wieviele Spalten haben die Textdateien? Falls es immer zwei sind, schau Dir mal das `unpack`-Argument von `numpy.loadtxt()` an.
BlackJack

Das ganze mal ein bisschen aufgeräumt (ungetestet):

Code: Alles auswählen

from functools import partial
from itertools import count
import tkinter as tk
import matplotlib.pyplot as mpl
import numpy as np


def create_diagram(
    title_entry, x_label_entry, y_label_entry, filenames_and_label_entries
):
    mpl.figure()
    mpl.grid(True)
       
    mpl.title(title_entry.get())
    mpl.xlabel(x_label_entry.get())
    mpl.ylabel(y_label_entry.get())
    for filename, label_entry in filenames_and_label_entries:
        x, y = np.loadtxt(filename, unpack=True)
        mpl.plot(x, y, label=label_entry.get())
    mpl.legend(loc=4, fontsize=10)
    mpl.show()


def make_row_adder(start_row=0):
    counter = count(start_row)

    def add_grid_row(left_widget, right_widget):
        row = next(counter)
        left_widget.grid(row, column=0, sticky=tk.E)
        right_widget.grid(row, column=1, padx=20)

    return add_grid_row


def main():
    filenames = tk.filedialog.askopenfilenames(
        defaultextension='.txt', title='Dateien auswählen'
    )

    root = tk.Tk()
    root.title('Einstellungen für das Diagramm')

    add_grid_row = make_row_adder()
    entry_width = 50

    title_entry = tk.Entry(root, width=entry_width)
    add_grid_row(tk.Label(root, text='Titel'), title_entry)
    
    x_label_entry = tk.Entry(root, width=entry_width)
    add_grid_row(tk.Label(root, text='x-Achse'), x_label_entry)

    y_label_entry = tk.Entry(root, width=entry_width)
    add_grid_row(tk.Label(root, text='y-Achse'), y_label_entry)

    filenames_and_label_entries = list()
    for i, filename in enumerate(filenames, 1):
        entry = tk.Entry(root, width=entry_width)
        add_grid_row(tk.Label(root, text='Label {0}'.format(i)), entry)
        filenames_and_label_entries.append((filename, entry))
 
    add_grid_row(
        tk.Button(
            root,
            text='Weiter',
            command=partial(
                create_diagram,
                title_entry,
                x_label_entry,
                y_label_entry,
                filenames_and_label_entries
            )
        ),
        tk.Button(root, text='Abbrechen', command=root.quit)
    )
    root.mainloop()


if __name__ == '__main__':
    main()
Python.Anfänger
User
Beiträge: 4
Registriert: Mittwoch 14. September 2016, 15:09

@BlackJack:
Vielen Dank für die schnelle und vor allem ausführliche Hilfe :)
Mit Hilfe deines Codes und den zuvor beschriebenen Tipps konnte ich mir mein Programm für das Erstellen von Diagrammen erstellen.
Hat zwar etwas gedauert, aber es ist ja noch kein Meister vom Himmel gefallen :D

Ich muss jetzt nur noch die Funktionen sauber definieren! Sind dabei irgendwelche "inoffiziellen Regeln" zu beachten?

Zum Abschluss mein aktueller Stand:

Code: Alles auswählen

import tkinter as tk
from tkinter import filedialog
import numpy as np
import matplotlib.pyplot as mpl
from functools import partial
#==============================================================================
mpl.rc('font',**{'family':'serif','serif':['Computer Modern Roman']})
mpl.rc('text', usetex=True)
#==============================================================================
# Definition von Funktionen:

def Diagramm_erstellen(title_entry, x_axis_entry, y_axis_entry, solve_entry, entries, Dateinamen, fenster_einstellungen):
    mpl.figure()
    mpl.grid(True)
        
    mpl.title(title_entry.get())
    mpl.xlabel(x_axis_entry.get())
    mpl.ylabel(y_axis_entry.get())
    
    for namen, label in zip(Dateinamen, entries):
        x, y = np.loadtxt(namen, unpack=True)
        mpl.plot(x, y, label=label.get())
    mpl.legend(loc=4, fontsize=10)
    mpl.tight_layout()
    mpl.savefig(solve_entry.get()+'.pdf')
    fenster_einstellungen.destroy()
#    
def Dateien_auswaehlen(startfenster):
    Dateinamen = filedialog.askopenfilenames(defaultextension='.txt', \
    filetypes=[('All files', '.*'), ('Text files', '.txt')], initialdir='C:\\Users\\', \
    title='Dateien auswählen')
    Anzahl_Dateien = len(Dateinamen)
    
    if Dateinamen:
        fenster_einstellungen = tk.Tk()
        fenster_einstellungen.title('Einstellungen für das Diagramm')
        
        tk.Label(fenster_einstellungen, text='Titel').grid(row=0, sticky=tk.E)
        title_entry = tk.Entry(fenster_einstellungen, width=50)
        title_entry.grid(row=0, column=1, padx=20)
        
        tk.Label(fenster_einstellungen, text='x-Achse').grid(row=1, sticky=tk.E)
        x_axis_entry = tk.Entry(fenster_einstellungen, width=50)
        x_axis_entry.grid(row=1, column=1, padx=20)
        
        tk.Label(fenster_einstellungen, text='y-Achse').grid(row=2, sticky=tk.E)
        y_axis_entry = tk.Entry(fenster_einstellungen, width=50)
        y_axis_entry.grid(row=2, column=1, padx=20)
        
        entries = list()
        for k in range(Anzahl_Dateien):
            tk.Label(fenster_einstellungen, text='Label '+str(k+1)).grid(row=3+k, sticky=tk.E)
            entry = tk.Entry(fenster_einstellungen, width=50)
            entry.grid(row=3+k, column=1, padx=20)
            entries.append(entry)
        
        tk.Label(fenster_einstellungen, text='Speichern unter').grid(row=4+Anzahl_Dateien, sticky=tk.E)
        solve_entry = tk.Entry(fenster_einstellungen, width=50)
        solve_entry.grid(row=4+Anzahl_Dateien, column=1, padx=20)
      
        tk.Button(fenster_einstellungen, text='Weiter', command=partial(
            Diagramm_erstellen, title_entry, x_axis_entry, y_axis_entry,\
            solve_entry, entries, Dateinamen, fenster_einstellungen
            )).grid(row=5+Anzahl_Dateien, sticky=tk.E)
        tk.Button(fenster_einstellungen, text='Abbrechen', command=fenster_einstellungen.destroy)\
        .grid(row=5+Anzahl_Dateien, column=1, padx=20)
    else:
        print('Sie haben keine Dateien ausgewählt! \nAus diesem Grund kann kein Diagramm erstellt werden.')
        startfenster.destroy()
#    
def main():
    startfenster = tk.Tk()
    startfenster.title('Diagramme erstellen')
    startfenster.geometry('300x80')
    
    tk.Label(startfenster, text='Sie möchten ein Diagramm erstellen!').pack()
    tk.Button(startfenster, text='Dateien auswählen', command=partial(Dateien_auswaehlen, startfenster)).pack()
    tk.Button(startfenster, text='Beenden', command=startfenster.destroy).pack()
        
    startfenster.mainloop()     
#    
if __name__=='__main__':
    main()
Zuletzt geändert von Anonymous am Donnerstag 15. September 2016, 14:07, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Python.Anfänger: Was hier auf jeden Fall ein Fehler im Programm ist, sind die beiden `Tk`-Exemplare die gleichzeitig existieren. Das ist *das* Hauptfenster an dem auch der Tk-Interpreter hängt. Wenn das funktioniert, hast Du Glück oder hast Probleme übersehen. Zusätzliche Fenster muss man mit `Toplevel` erstellen.
Python.Anfänger
User
Beiträge: 4
Registriert: Mittwoch 14. September 2016, 15:09

@BlackJack: Ok, vielen Dank. Das wusste ich nicht. Bei mir lief das Programm zwar dennoch, aber ich habe es gleich mal geändert. Nicht dass die schlechten Dinge noch zur Gewohnheit werden..
Antworten