Datei-Inhalt ausgeben

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
havefun
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2024, 18:21

Hallo zusammen,
wenn ich mitleidig lächelnde Gesichter erzeuge, ich habe fogendes Problem:


In dem angezeigten Fenster befinden sich 2 Buttons

Button 1
1.) Über einen File open Dialog wähle ich eine Datei aus.Der Dateiname wir in der Variable "filename" gespeichert.
2.)Der Inhalt der Variable wird in einer Message-Box angezeigt.

Button 2 soll nun den Inhalt der Datei in einer Message-Box anzeigen.

Ich(Python-Newbie) kriege es einfach nicht hin. Schäm!
imonbln
User
Beiträge: 187
Registriert: Freitag 3. Dezember 2021, 17:07

Es gibt mehr als ein Grafik GUI Framework welches verwendest du?

Außerdem ist die Messagebox eigentlich für kurze Nachrichten gedacht, wenn du den Inhalt einer Datei ausgeben willst, solltest du ein neues Fenster mit einer Textbox bauen.

Last but not least, das Forum ist kein wir übernehmen deine (Haus)aufgaben, wünsch dir was, sondern eine Hilfe zur Selbsthilfe und die meist auch sehr engagiert. 
Also was hast du versucht, was ist der genaue Fehler, kannst du uns vielleicht einen minimalen Code (in Code tags) zeigen, mit den wir nachvollziehen können, woran du scheiterst?
havefun
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2024, 18:21

Hallo,
zuerst maldanke für die schnelle Antwort.
Hier mein letzter Stand:
code {
# -*- coding: iso-8859-1 -*-

import os

from fileinput import close, filename
from tabnanny import filename_only
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
from tkinter.messagebox import showinfo

# create the root window
root = tk.Tk()
root.title('Tkinter Open File Dialog')
root.resizable(False, False)
root.geometry('300x150')


def select_file():
filetypes = (
('text files', '*.txt'),
('All files', '*.*')
)

filename = fd.askopenfilename(
title='Datei öffnen',
initialdir='/',
filetypes=filetypes)


filename_2 = filename


showinfo(
title='Gewählte Datei',
message=filename
)


def print_file():
open (filename_2)
#print filename
close (filename_2)



# open button
open_button = ttk.Button(
root,
text='Datei öffnen',
command=select_file
)

open_button.pack(expand=True)


filename2 = (r"filename")

# open button2
open_button2 = ttk.Button(
root,
text='Datei öffnen2',
#command=print (filename2)

#datei = open(filename2,'r')
#command=print (r"filename")
#print(datei.read())



command = print_file()



)


open_button2.pack(expand=True)

# run the application
root.mainloop()
}

Zu
"Last but not least, das Forum ist kein wir übernehmen deine (Haus)aufgaben, wünsch dir was, sondern eine Hilfe zur Selbsthilfe und die meist auch sehr engagiert.


Bevor ich in Rente ging, habe ich jahrelang Visual C# programmiert (auch SQL- Datenbanken). Mein Sohn und mein Neffe befassen sich mit Python. Deshalb interessiere ich mich dafür.
Die Zeit der Hausaufgaben ist um.
Gruß,
Havefun
imonbln
User
Beiträge: 187
Registriert: Freitag 3. Dezember 2021, 17:07

Das mit den codetag hat leder nicht geklappt.

Das import os wird nicht verwendet und meistens sollte man bei Path Operationen auch besser die Pathlib verwenden.
Dein Hauptproblem ist, das du einmal ein filename2 als globale variable hast und an diversen stellen filename_2 als Lokale variablen.
Außerdem würde die Zuweisung von filename_2 in der Funktion select_file die globale Variable überlagern da musst du mit den global Keyword arbeiten. Generell in Python sollten globale Variablen großgeschrieben werden.

Hier mal eine leicht verbesserte Version deines Programms.

Code: Alles auswählen

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.filedialog as filedialog
import tkinter.messagebox as messagebox

from pathlib import Path


FILENAME = ""


def select_file():
    global FILENAME

    filetypes = (
        ('text files', '*.txt'),
        ('All files', '*.*')
    )

    FILENAME = filedialog.askopenfilename(
        title='Datei öffnen',
        initialdir=Path.home().as_posix(),
        filetypes=filetypes
    )


def show_file(root):
    new_window = tk.Toplevel(root)
    new_window.title(FILENAME)

    menu = tk.Menu(new_window)
    new_window.config(menu=menu)

    file_menu = tk.Menu(menu)
    file_menu.add_command(label="Exit", command=new_window.destroy)
    menu.add_cascade(label="Datei", menu=file_menu)

    textbox = tk.Text(new_window)
    textbox.pack(expand=True)
    try:
        with open(FILENAME, "r", encoding="utf-8") as inp:
            textbox.insert(tk.END, inp.read())
    except IOError:
        new_window.destroy()
        messagebox.showwarning(
            title="Datei Fehler",
            message=f"Die Datei {FILENAME} kann nicht geöffnet werden",
        )


def open_dialog():
    root = tk.Tk()
    root.title('Tkinter Open File Dialog')
    root.resizable(False, False)
    root.geometry('300x150')

    file_select_button = ttk.Button(
        root,
        text='Datei öffnen',
        command=select_file
    )

    file_view_button = ttk.Button(
        root,
        text="Datei anzeigen",
        command=lambda: show_file(root)
    )

    file_select_button.pack(expand=True)
    file_view_button.pack(expand=True)
    return root


def main():
    root = open_dialog()
    root.mainloop()


if __name__ == '__main__':
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@imonbln: Hier würde ich mal ganz stark widersprechen: Globale Variablen sollte es gar nicht geben, aber wenn dann auf gar keinen Fall KOMPLETT_GROSS geschrieben, denn das ist dann ja *noch* schlechter, weil man dann mit der Erwartung bricht, dass alles was KOMPLETT_GROSS geschrieben ist, eine *Konstante* ist, und keine Variable.

``as`` beim Import ist drei mal falsch verwendet, weil da nix umbenannt wird.

Warum steht in der `main()` fast nix drin? Die `open_dialog()` sollte da inhaltlich drin stehen.

@havefun: Fenstergrössen gibt man nicht hart in Pixeln vor. Das sollte man noch nie, weil das schon immer nicht funktioniert hat, aber heutzutage bei dem Zoo von Displaygrössen und -auflösungen, und -einstellungen geht das echt gar nicht mehr. Die Fenstergrösse ergibt sich automatisch aus dem Inhalt.

„Datei öffnen“ ist für beide Schaltflächen als Text inhaltlich nicht richtig. Mit der einen wählt man eine Datei aus, mit der anderen wird sie angezeigt.

Das Programm sollte den Fall berücksichtigen, das der Benutzer keine Datei ausgewählt hat. Entweder beim Anzeigen, oder in dem man die Schaltfläche zum Anzeigen solange deaktiviert bis der Benutzer eine Datei ausgewählt hat. Also erst prüfen ob eine Datei ausgewählt wurde, dann die Datei einlesen, mit Fehlerausgabe wenn das nicht funktioniert, und dann erst die Anzeige.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from pathlib import Path
from tkinter import filedialog, messagebox, ttk


def select_file(filename_var):
    filename_var.set(
        filedialog.askopenfilename(
            title="Datei öffnen",
            initialdir=Path.home().absolute(),
            filetypes=(("text files", "*.txt"), ("All files", "*.*")),
        )
    )


def show_file(master, filename_var):
    filename = filename_var.get()
    if filename:
        try:
            content = Path(filename).read_text(encoding="utf-8")
        except IOError as error:
            messagebox.showerror(
                "E/A-Fehler",
                f"Die Datei {filename} konnte nicht gelesen werden.\n{error}",
            )
        else:
            window = tk.Toplevel(master)
            window.title(filename)

            menu = tk.Menu(window)
            window.config(menu=menu)

            file_menu = tk.Menu(menu)
            file_menu.add_command(label="Exit", command=window.destroy)
            menu.add_cascade(label="Datei", menu=file_menu)

            textbox = tk.Text(window)
            textbox.pack(expand=True)
            textbox.insert(tk.END, content)
    else:
        messagebox.showerror(
            "Keine Datei gewählt",
            "Es muss eine Datei zur Anzeige ausgewählt werden!",
        )


def main():
    root = tk.Tk()
    root.title("Tkinter Open File Dialog")
    root.resizable(False, False)
    filename_var = tk.StringVar(value="")
    ttk.Button(
        root, text="Datei auswählen", command=lambda: select_file(filename_var)
    ).pack(expand=True)
    ttk.Button(
        root,
        text="Datei anzeigen",
        command=lambda: show_file(root, filename_var),
    ).pack(expand=True)

    root.mainloop()


if __name__ == "__main__":
    main()
Ganz allgemein kann man zu GUIs sagen, dass man bei jeder nicht-trivialen GUI nicht um objektorientierte Programmierung herum kommt, also man muss dafür eigene Klassen schreiben können. Nur bei sehr einfachen Sachen kommt man noch mit Closures aus. In diesem Beispiel hier konkret hat man noch Glück, dass ``tkinter`` die Tcl-Variablen in Objekte verpackt, weil man das braucht wenn man ”Listener” dafür registrieren will, weil in Tcl jede Variable ein ”Observable” ist, um das mal in Entwurfsmustern zu formulieren. Und das man maximal zwei Werte bei den Aufrufen weiter-/durchreichen muss.

Der Hinweis bezieht sich nicht nur auf Schule/Studium/Ausbildung und Hausaufgaben, sondern ganz allgemein. Zumal wir das ja auch alles nicht nachprüfen können, ob das hilflose nette Mädchen nicht nur Typ ist der denkt die Computernerds würden sich darum reissen ”ihr” bei den Hausaufgaben zu ”helfen”. Es ist manchmal erstaunlich wie viel Zeit und Energie manche Leute da rein stecken sich Komplettlösungen zu erbetteln, wo sie in weniger Zeit und mit weniger Energie die Aufgabe dreimal hätten selbst lösen können. 🙂

Das ist nicht gegen Dich persönlich gerichtet, man hat halt so seine Erfahrungen, und ist entsprechend misstrauisch wenn Eltern oder Grosseltern mit Aufgaben der Kinder oder Enkelkinder hier nach Lösungen fragen.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
havefun
User
Beiträge: 3
Registriert: Mittwoch 11. Dezember 2024, 18:21

@blackjack
nichts gegen dich persönlich ,
aber keine Hilfe ist besser als das überhebliche Geschwätz von Besserwissern, die der Welt
zeigen wollen, was für geistige Überflieger sie sind.
Gruß,
havefun
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

@__blackjack__ ich habe mal wieder Fragen, die eine hatten wir ähnlich, kürzlich erst, welchen Mehrwert bringt `_var` in `filename_var`? Ich sehe dass das ein `StringVar` - Objekt ist und dadurch hat das andere Methoden als ein String. Ist dass der Grund oder gibt es noch einen?

Und wäre die Funktion so eventuell etwas schöner? Mein Gedanke war, ich sehe auf einen Blick was im `if`-Zweig passiert und es wird übersichtlicher, weil der Rest nicht eingerückt werden muss.

Code: Alles auswählen

def show_file(master, filename_var):
    filename = filename_var.get()
    if not filename:
        messagebox.showerror(
            "Keine Datei gewählt",
            "Es muss eine Datei zur Anzeige ausgewählt werden!",
        )
        return
    try:
        content = Path(filename).read_text(encoding="utf-8")
    except IOError as error:
        messagebox.showerror(
            "E/A-Fehler",
            f"Die Datei {filename} konnte nicht gelesen werden.\n{error}",
        )
    else:
        window = tk.Toplevel(master)
        window.title(filename)

        menu = tk.Menu(window)
        window.config(menu=menu)

        file_menu = tk.Menu(menu)
        file_menu.add_command(label="Exit", command=window.destroy)
        menu.add_cascade(label="Datei", menu=file_menu)

        textbox = tk.Text(window)
        textbox.pack(expand=True)
        textbox.insert(tk.END, content)
Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@havefun: Da Du nichts über mich geschrieben hast, kann ich das ja auch nicht persönlich nehmen.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Genau das war die Idee hinter dem `*_var`, damit man nicht denkt, dass es direkt ein Dateiname ist und von Zeichenkette oder `Path`-Objekt ausgeht. Insbesondere in der `show_file()`-Funktion haben wir dann ja auch beides: `filename` und `filename_var`. Spätestens an der Stelle hätte man sonst ja auch das Problem wie man `filename` nennen soll, wenn das schon für das `StringVar`-Objekt steht.

Das mit dem „early return“ finde ich persönlich nicht schöner. So tief verschachtelt war das ja noch nicht. Und wenn, dann hätte ich wahrscheinlich auch eher dazu tendiert etwas in eine eigene Funktion auszulagern. Auf der anderen Seite hätte ich da aber auch keinen Drang das umzuschreiben, wenn ich das in Code so vorfinden würde. Am Anfang einer Funktion Randfälle abfragen und vorzeitig abbrechen ist nicht ungewöhnlich.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Benutzeravatar
Dennis89
User
Beiträge: 1503
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen,

okay, danke für die Erklärung.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten