Variablen in config schreiben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Mitico.eu
User
Beiträge: 1
Registriert: Sonntag 13. Oktober 2019, 15:47

Hallo,
ich habe ein kleines problem und komme nicht auf die lösung.

Code: Alles auswählen

# Setup
from tkinter import *
from tkinter import ttk
from configparser import ConfigParser

#config
cfg = ConfigParser()
cfg.read('config.ini')

def einstellung_speichern_action():
	cfgfile = open("config.ini","w")
	cfg.set("Stichworte", "Stichworte", stichworte_var2)
	cfg.write(cfgfile)
	cfgfile.close()

# Einstellungsfenster
einstellungsfenster = Tk()
einstellungsfenster.title("Einstellungen")
einstellungsfenster.geometry("400x490")

# Tabs
tabControl = ttk.Notebook(einstellungsfenster)          
tab1 = ttk.Frame(tabControl)
tabControl.add(tab1, text='Stichworte')
tabControl.pack(expand=1, fill="both")

#Button
e_speichern_button = Button(einstellungsfenster, text="Speichern", command=einstellung_speichern_action)

# Stichworte
stichworte_scroll = Scrollbar (tab1)
stichworte_var2 = Text(tab1, height=10, width=50)
stichworte_scroll.pack(side=RIGHT, fill=Y)
stichworte_var2.pack(side=LEFT, fill=Y)
stichworte_scroll.config(command=stichworte_var2.yview)
stichworte_var2.config(yscrollcommand=stichworte_scroll.set)
stichworte_var2.insert(END, cfg.get("Stichworte", "Stichworte"))
e_speichern_button.pack()

 
# Ereignisschleife
einstellungsfenster.mainloop()
die config.ini sieht wie folgt aus.

Code: Alles auswählen

[Stichworte]
Stichworte=	F 1
		F 2
		F 2 Y
		F 3
		F 3 Y
		F 4
		F BMA
		F BUS Y
		F FLUG 1 Y
		F FLUG 2 Y
		F GAS 1
		F GAS 2
		F LKW
		F ZUG
		F ZUG Y
		F RWM
		F SCHIFF 1
		F SCHIFF 2
		F SCHIFF 2 Y
		F SCHIFF 2 GEFAHR
		F WALD 1
		F WALD 2
		H 1
		H 1 Y
		H 2
		H ABST Y
		H ELEK
		H EINST Y
		H FLUSS
		H FLUSS Y
		H WASS Y
		H GAS 1
		H GAS 2
		H GEFAHR 1
		H GEFAHR 2
		H KLEMM 1 Y
		H KLEMM 2 Y
		H ÖL FLUSS
		H ÖL WASS
		H RADIOAKTIV
		H SCHIFF
		H SCHIFF Y
		H ZUG 1 Y
		H ZUG 2 Y
als fehler bekomme ich.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\maike\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "problem.py", line 14, in einstellung_speichern_action
cfg.set("Stichworte", stichworte_var2)
File "C:\Users\maike\AppData\Local\Programs\Python\Python37-32\lib\configparser.py", line 1197, in set
self._validate_value_types(option=option, value=value)
File "C:\Users\maike\AppData\Local\Programs\Python\Python37-32\lib\configparser.py", line 1179, in _validate_value_types
raise TypeError("option keys must be strings")
TypeError: option keys must be strings
kann mir da einer helfen?
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

In ini-Dateien kann man nur Strings speichern. Keine Textwidgets. Für den gezeigten Inhalt ist ini auch das falsche Fornat. CSV oder json wären passender. Dazu muß man aber den Inhalt des Textfeldes in eine passende Struktur parsen.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mitico.eu: Noch ein paar Anmerkungen zum Quelltext: Die Kommentare sind alle überflüssig. Ein Kommentar sollte dem Leser einen Mehrwert bieten. Faustregel: Kommentare beschreiben nicht *was* passiert, denn das steht da bereits als Code, sondern *warum* das *so* passiert – sofern das nicht offensichtlich ist.

Sternchen-Importe sind Böse™. Gerade bei `tkinter` holt man sich so Unmengen an Namen in das Modul von denen nur ein kleiner Bruchteil verwendet wird. Und nicht nur welche die im `tkinter`-Modul definiert werden, sondern auch alle die das Modul seinerseits von woanders importiert.

Auf Modulebene gehört nur Code der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Man sollte keine kryptischen Abkürzungen und/oder Prä-/Suffixe in Namen verwenden. Also Beispielsweise `config` statt `cfg` oder `einstellungen_speichern_button` statt `e_speichern_button`.

Ebenfalls ein no-go sind nummerierte Namen. Da möchte man entweder bessere Namen suchen oder keine Einzelnamen/-werte sondern eine Datenstruktur. Oft eine Liste. Im vorliegenden Quelltext sind die Nummern aber einfach nur überflüssig. Warum stehen die da?

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

`stichworte_var` für ein `Text`-Widget ist ungünstig, weil es in `tkinter` auch Variablentypen gibt deren Namen mit `Var` endet, und man deshalb hinter `stichworte_var` ein Objekt von so einem Typ vermuten würde.

Weder Daten noch Code sollten wiederholt werden. Wenn man beispielsweise einen festen Dateinamen mehr als einmal im Programm benötigt, definiert man den einmal als Konstante, statt den Namen im Quelltext zu wiederholen. Das ist fehleranfällig und arbeitsaufwändig wenn man den Namen mal ändern/anpassen will/muss.

Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen als Argument(e) übergeben. Das bedeutet bei GUI-Programmierung das man mindestens `functools.partial()` benötigt, aber bei jeder nicht-trivialen GUI um objektorientierte Programmierung (OOP) nicht herum kommt.

Bei Textdateien sollte man immer eine Kodierung angeben.

Dateien wenn möglich mit der ``with``-Anweisung öffnen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from configparser import ConfigParser
from functools import partial
import tkinter as tk
from tkinter import ttk

CONFIG_ENCODING = "utf-8"
CONFIG_FILENAME = "config.ini"


def einstellungen_speichern(config, stichworte_textwidget):
    config.set("Stichworte", "Stichworte", stichworte_textwidget.get())
    with open(CONFIG_FILENAME, "w", encoding=CONFIG_ENCODING) as config_file:
        config.write(config_file)


def main():
    config = ConfigParser()
    config.read(CONFIG_FILENAME, CONFIG_ENCODING)

    einstellungsfenster = tk.Tk()
    einstellungsfenster.title("Einstellungen")

    notebook = ttk.Notebook(einstellungsfenster)
    tab_frame = ttk.Frame(notebook)
    notebook.add(tab_frame, text="Stichworte")
    notebook.pack(expand=True, fill=tk.BOTH)

    stichworte_scrollbar = tk.Scrollbar(tab_frame)
    stichworte_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    stichworte_textwidget = tk.Text(tab_frame, height=10, width=50)
    stichworte_textwidget.pack(side=tk.LEFT, fill=tk.Y)
    stichworte_textwidget.config(yscrollcommand=stichworte_scrollbar.set)
    stichworte_textwidget.insert(
        tk.END, config.get("Stichworte", "Stichworte")
    )

    stichworte_scrollbar.config(command=stichworte_textwidget.yview)

    tk.Button(
        einstellungsfenster,
        text="Speichern",
        command=partial(
            einstellungen_speichern, config, stichworte_textwidget
        ),
    ).pack()

    einstellungsfenster.mainloop()


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten