tkinter textausgaben aus anderer Datei

Fragen zu Tkinter.
Antworten
ake
User
Beiträge: 5
Registriert: Sonntag 28. Februar 2016, 14:26

Hi,

ich bin seit kurzen dabei mich etwas in Python einzuarbeiten.

Ich habe 2 Dateien, einmal das main.py und einmal das test.py



Ich starte mit dem main.py und möchte eine Ausgabe die von test_datei.py hervorgerufen wird in der main.py anzeigen lassen.

main.py

Code: Alles auswählen

from tkinter import *
import os

def button_action1():
       
       text_ausgabe.insert(END, 'hier steht ein text\n')
       import test_datei
     
fenster = Tk()
text_ausgabe = Text(fenster, height=20, width=50)
text_ausgabe.pack(side=LEFT)

button1 = Button(fenster, text="test button", command=button_action1)
button1.place(x = 10, y = 30, width=80, height=25)

fenster.mainloop()


test_datei.py

Code: Alles auswählen

text_ausgabe .insert(END, 'text aus import \n', 'follow')

Jetzt habe ich aber drei Probleme bei dem ganzem, da ich denke das das alles miteinander zusammenhängt versuche ich das mal zu erklären.


Zum einem wird text aus import aus der test_datei.py nicht ausgeführt. Als Fehlermeldung bekomme ich, dass text_ausgabe nicht definiert ist. in main geht das allerdings.

Das zweite Problem ist, dass die Schaltfläche test button solange als "gedrückt" dargestell wird bis die test_datei.py komplett durchgearbeitet ist.

Und das dritte Problem ist dass die Textausgabe erst stattfindet wenn wie auch im zweiten Problem die test_datei.py komplett durchgearbeitet ist.

Code: Alles auswählen

def button_action1():
       
       text_ausgabe.insert(END, 'hier steht ein text\n')
       import test_datei

Ich denke ich habe da mehrere Fehler gemacht, aber googel hat mir leider nicht geholfen. Daher die Anfrage hier im Forum.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@ake: »import« importiert Module. Dabei hat jedes Modul seinen eigenen Namensraum, das heißt, Namen aus z.B. »main.py« sind in »test_datei.py« unbekannt.
Das was Du vorhast, funktioniert so nicht. In Modulen werden Funktionen definiert, die man aus anderen Modulen aufrufen kann. Dabei ist eine Funktion eine unabhängige Einheit, die über Parameter ihre Daten, die sie braucht, bekommt und per Rückgabewert ein Ergebnis zurückgibt.

Also ungefähr so:

main.py:

Code: Alles auswählen

import tkinter as tk
from functools import partial
import test_datei

def button_action(text_ausgabe):
    text_ausgabe.insert(tk.END, 'hier steht ein text\n')
    text_ausgabe.insert(tk.END, test_datei.funktion())
     
def main():
    fenster = tk.Tk()
    text_ausgabe = tk.Text(fenster, height=20, width=50)
    text_ausgabe.pack(side=tk.LEFT)

    button = tk.Button(fenster, text="test button", command=partial(button_action, text_ausgabe))
    button.place(x = 10, y = 30, width=80, height=25)
    fenster.mainloop()
	
if __name__ == '__main__':
    main()
test_datei.py:

Code: Alles auswählen

def funktion():
    return "text aus test_datei\n"
ake
User
Beiträge: 5
Registriert: Sonntag 28. Februar 2016, 14:26

Ok, danke für deine Antwort.

Hierzu habe ich aber noch eine Frage.

Wie geht das hier, dass ich mehrere Ausgaben hinzufüge?

Code: Alles auswählen

def funktion():
    # mach iregendwas
    return "text1"
    # mach noch mehr
    return "text2"
    # hier passiert auch noch etwas
    return "text3"
if __name__ == '__funktion__':
    funktion()
BlackJack

Man könnte mehrere Teilergebnisse in einer Liste sammeln und die am Ende zurückgeben.

Code: Alles auswählen

def funktion():
    # mach irgendwas
    result = ['text1']
    # mach noch mehr
    result.append('text2')
    # hier passiert auch noch etwas
    result.append('text3')
    return result
ake
User
Beiträge: 5
Registriert: Sonntag 28. Februar 2016, 14:26

Hi,

ich bin schon etwas weiter gekommen. Hänge aber schon wieder fest!

Im Beispiel, wie bekomme ich es nun hin, dass die Eingabe verwendet werden kann?

Code: Alles auswählen

from tkinter import *
import threading
import time



     
     
class MyThread (threading.Thread):
    def run(selfself):
        text2.insert(END, 'start \n') 
        
        def button_action_e():
            print(eingabefeld.get())
            
        #warten auf Eingabe?!
            erhaltene_eingabe = eingabefeld.get()
            text2.insert(END, eingabefeld.get()) 
        
        
        eingabefeld = Entry(fenster, bd=5, width=40)
        eingabefeld.pack()  

        change_button = Button(fenster, text="Klick me", command=button_action_e)    
        change_button.pack()
          
        erhaltene_eingabe = eingabefeld.get()
        text2.insert(END, (erhaltene_eingabe)) 
        print(erhaltene_eingabe)
        # mach was mit der eingabe
        time.sleep(1)
        text2.insert(END, 'weiter \n')
        time.sleep(1)
        text2.insert(END, 'und Ende \n')
        



def button_action1():
    m = MyThread();
    m.start()     

      
fenster = Tk()
text2 = Text(fenster)
text2.pack()

change_button = Button(fenster, text="testing", command=button_action1)
change_button.pack()
    
fenster.mainloop()
 
BlackJack

@ake: Das sieht alles etwas konfus aus. Du kannst an der Stelle wo der Kommentar steht nicht warten. So funktioniert GUI-Programmierung nicht. Man hat da keinen linearen Programmablauf bei dem man selbst die Kontrolle über die Reihenfolge hat, sondern man sagt dem GUI-Rahmenwerk wie man auf welche Ereignisse reagieren möchte, in dem man Rückruffunktionen/-methoden registriert die dann etwas tun. Und zwar jeweils nur kurz, damit die GUI nicht blockiert wird. Länger laufende Programmabläufe kann man in Threads auslagern, aber diese Threads haben dann nichts mit der GUI zu tun. Das Dein `MyThread` die GUI verändert und Werte aus Eingabefeldern abfragt ist falsch! Ich habe da so ein bisschen das Gefühl als würdest Du versuchen mit dem Thread die ereignisbasierte Programmierung die GUIs mit sich bringen, zu umgehen. Das funktioniert so nicht.

`time.sleep()` ist bei der GUI-Programmierung ziemlich sicher ein Zeichen das man etwas falsch macht.

Asynchrone Ausführung von Code kann man in Tk auch ohne Threads mit `after_idle()` erreichen und mit `after()` wenn man eine Verzögerung braucht. Wie bei allen Ereignissen von der GUI dürfen auch hier die Rückruffunktionen nur kurz etwas machen und müssen dann zur GUI-Hauptschleife zurückkehren, damit die GUI nicht blockiert wird.

Für länger laufende Programmlogik kann man wie gesagt Threads verwenden, die man vom GUI-/Hauptthread aus regelmässig mit `after_idle()` abfragen kann. Wenn während des längeren Ablaufs Informationen, wie Fortschritt oder (Zwischen)Ergebnisse zur GUI gelangen sollen, kann man über eine `Queue.Queue` zwischen den Threads kommunizieren.
ake
User
Beiträge: 5
Registriert: Sonntag 28. Februar 2016, 14:26

Hm, Ok... Ich dachte, ich hätte zumindestens einen kleinen Schritt nach vorne gemacht :?

Die Sleep Anweisungen hatte ich da eigentlich nur drin um zu sehen wann was passiert.

Ich habe das etwas umgebaut, aber das läuft wieder nicht. Wie bekomme ich denn die Eingabe da rein?

Code: Alles auswählen

class MyThread (threading.Thread):
    def run(selfself):    
            
        print(erhaltene_eingabe)   
        
def button_action1():  
    def button_action_e():
        m = MyThread();
        m.start()
           
         erhaltene_eingabe = eingabefeld.get()
        print(erhaltene_eingabe) 
        
        
    eingabefeld = Entry(fenster, bd=5, width=40)
    eingabefeld.pack()  

    change_button = Button(fenster, text="Klick me", command=button_action_e)    
    change_button.pack()
    erhaltene_eingabe = eingabefeld.get()
BlackJack

@ake: Das sieht jetzt nach wild herumraten aus. So funktioniert programmieren nicht. Objektorientierte Programmierung (OOP), nebenläufige Programmierung (zum Beispiel mit Threads), und ereignisorientierte Programmierung (zum Beispiel bei GUIs) sind drei für sich genommen schon nicht ganz einfache Teilgebiete. Falls Du das jetzt gerade alles auf einmal lernen willst, würde ich empfehlen einen Schritt zurück zu gehen und einfach mal mit Objektorientierung alleine anzufangen. Wenn das sitzt, dann ereignisbasierte Programmierung und wie man dort mit `after()` und `after_idle()` grössere Aufgaben schrittweise asynchron erledigen kann. Dabei kann etwas was noch ein wenig vor OOP liegt hilfreich sein: Generatorfunktionen. Und erst dann sollte man sich an Threads wagen.
ake
User
Beiträge: 5
Registriert: Sonntag 28. Februar 2016, 14:26

Ok, dann beenden wir das hier und lassen das mal liegen.
Antworten