class, Window

Fragen zu Tkinter.
Antworten
stoffl6781
User
Beiträge: 11
Registriert: Sonntag 14. Dezember 2014, 19:04

Hallo zusammen,

ich habe mir das Buch Raspberry Pi - programmieren mit Python zugelegt.

Nun wollte ich zwei "Scripte" in einem Fenster laufen lassen.
Im Buch wurden daszu pro Script eine Calss mit einem neuen Window gemacht.
Nun habe ich versucht das ganze in einem Fenster zu realisieren, leider ohne Erfolg.

Hier meine Ergebnise:

Code: Alles auswählen

from tkinter import *
from tkinter import messagebox

import time
from temperature import TempDevices
from tkinter import *

import time, _thread

def About(message=None,title='Über'):
        messagebox.showinfo("Über")
#Fenster

root = Tk()
root.title('RPI')
root.resizable(width=FALSE, height=FALSE)
root.geometry('600x500')

#Menu
menu = Menu(root)
root.config(menu=menu)

filemenu = Menu(menu)
menu.add_cascade(label="Datei", menu=filemenu)
filemenu.add_command(label="Schließen", command=root.quit)

extramenu = Menu(menu)
menu.add_cascade(label="Extras", menu=extramenu)
extramenu.add_command(label="Export USB Stick")
extramenu.add_command(label="Einstellungen")
helpmenu = Menu(menu)
menu.add_cascade(label="Hilfe", menu=helpmenu)
helpmenu.add_command(label="Über", command=About)
# End Menu
mainloop()
# Anzeige Temparaturen 1
class App:
    def __init__(self):
        self.window = Tk()
        self.tempLabels = [Thermometer(self.window, t)
                           for t in TempDevices()]
        for t in self.tempLabels: t.pack()
        self.window.mainloop()

class Thermometer(Label):
    def __init__ (self, window, tempDevice):
        Label.__init__(self, font=("Arial", 20), width=12)
        self.window = window
        self.device = tempDevice
        self.update()

    def update(self):
        text = str(round(self.device.read(), 2)) + " °C"
        self.config(text=text)
        self.window.after(1000, self.update)
App()


# Diagramm
class Plotter:
    def __init__(self):
        self.colors = ["red", "green", "blue", "black"]
        self.window = Tk()
        self.c = Canvas(master=self.window, width = 320,
                        height= 250, bg="white")
        self.c.create_text(20, 20, text="30 °C")
        self.c.create_text(20, 220, text="20 °C")
        self.c.pack()
        t = TempDevices()
        self.pens = []
        for i in range(len(t)):
            self.pens.append(Pen (self.c,
                t[i], self.colors[i%4]))
        _thread.start_new_thread(self.update, ())
        self.window.mainloop()

    def update(self):
        while True:
            for i in range(60):
       for pen in self.pens:
                    pen.draw(i*5)
                time.sleep(1)
            self.c.delete("point")

class Pen:
    def __init__ (self, canvas, tempDevice, color):
        self.canvas = canvas
        self.device = tempDevice
        self.color = color

    def draw(self, x):
        y = 400 + 220 - self.device.read() * 20
        self.canvas.create_line(x, y, x+3, y, width=3,
                                fill=self.color, tag="point")
Plotter()

mainloop()

Ich versuche #Temperatur und #Diagramm auf eine Seite zu bekommen - leider ohne Erfolg

Kan nmir jemand erklären was ic da falsch verstanden habe?


Danke im Voraus

Stoffl
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

"Funktioniert nicht" ist eine sehr ungenügende Problembeschreibung. Was für ein Verhalten erwartest du und was passiert? Siehst du einfach nichts, brennt deine Wohnung ab oder gibt es eine Fehlermeldung? Und falls letzteres zutrifft: Wie lautet diese? Wie sieht der dazugehörige Traceback aus?
Das Leben ist wie ein Tennisball.
stoffl6781
User
Beiträge: 11
Registriert: Sonntag 14. Dezember 2014, 19:04

EyDu hat geschrieben:Hallo und willkommen im Forum!

"Funktioniert nicht" ist eine sehr ungenügende Problembeschreibung. Was für ein Verhalten erwartest du und was passiert? Siehst du einfach nichts, brennt deine Wohnung ab oder gibt es eine Fehlermeldung? Und falls letzteres zutrifft: Wie lautet diese? Wie sieht der dazugehörige Traceback aus?
Hi, wenn ich das Programm ausführe, dann kommt das root fenster. =) OK
Wenn ich auf Schließen gehe, wird das nächste fenster class App geladen. nicht gewollt
wenn ich dieses schließe wird die nächste Class geladen. nicht gewollt

eigentlich will ich alles im root fenster und nicht auf mehrere verteilt.

Ich denke,dass die schwierigkeit die Update in Class App sein wird.

Gruß
Stoffl
BlackJack

@stoffl6781: Das sieht so aus als wenn versucht wurde zwei bestehende Programme irgendwie in einer Datei zu mischen. So funktioniert programmieren nicht. Man sollte schon verstehen was der Code bewirkt und bedeutet den man in ein Modul schreibt. Also selber schreibt, und nicht ohne zu verstehen aus anderen Modulen zusammenkopiert.

Das fällt schon bei den Importen auf wo ganz offensichtlich einiges redundant ist.

Wo auch immer Du das Importieren vom `_thread`-Modul gesehen hast, die Quelle solltest Du meiden. Der führende Unterstrich bei dem Namen bedeutet dass dieses Modul nicht Teil der öffentlichen Schnittstelle ist, man das als Programmierer also nicht verwenden sollte. Für nebenläufige Programme gibt es schon *sehr* lange das `threading`-Modul in der Python-Standardbibliothek.

Sternchenimporte sind keine gute Idee weil man dann schnell den Überblick verliert welcher Name aus welchem Modul kommt und ausserdem die Gefahr von Namenskollisionen steigt. Bei `tkinter` ist es üblich das Modul mit ``import tinter as tk`` unter dem Namen `tk` zu importieren.

Es darf immer nur ein `Tk`-Objekt zur gleichen Zeit existieren. Das ist *das* *Haupt*fenster und da hängt auch der Hauptzustand der GUI dran. Wenn es davon mehr als eines gibt, dann ensteht Chaos und nicht vorhersehbares Verhalten der GUI.

Genau wie das Hauptfenster nur einmal existieren darf, ist es unüblich die Funktion mit der *Haupt*schleife, `mainloop()` mehr als einmal aufzurufen. Und *nach* diesem Aufruf steht in der Regel kaum Code denn der wird ja erst ausgeführt *nachdem* der Benutzer das Hauptfenster geschlossen hat, also dann wenn im Grunde alles vorbei ist.

Der Aufruf sollte auch nicht in einer `__init__()`-Methode stehen. Diese Methode ist dazu da das Objekt zu initialisieren und einen Benutzbaren Zustand zu bringen. Wenn dieser Aufruf nicht zurückkehrt und man mit dem Objekt dann auch mindestens theoretisch etwas machen könnte, dann ist das ein „code smell”. Das sieht man dann auch am Aufruf wo in der jeweiligen Zeile einfach nur das Objekt erstellt, aber nicht an einen Namen gebunden oder irgend eine Operation damit durchgeführt wird.

Die Fenstergrösse ergibt sich üblicherweise automatisch aus dem Inhalt den man in dem Fenster darstellt, darum sollte man die nicht von aussen fest vorgeben.

Auf Modulebene sollte man nur Konstanten, Funktionen, und Klassen definieren. Keine anderen Variablen und kein Code der das Hauptprogramm ausmacht. Das Hauptprogramm steckt üblicherweise in einer Funktion die `main()` genannt wird und durch folgendes Idiom aufgerufen wird:

Code: Alles auswählen

if __name__ == '__main__':
    main()
Dann kann man das Modul sowohl als Programm aufrufen, als auch als Modul importieren *ohne* dass das Hauptprogramm abläuft. Zum Beispiel um Teile des Moduls zu testen oder in anderen Modulen zu verwenden. Es gibt auch Werkzeuge, zum Beispiel um Dokumentation zu erstellen, die erwarten das man Module importieren kann, ohne dass dabei etwas ”passiert”.

Da die Labels und der Plot die gleichen Daten darstellen sollten die beiden Anzeigen nicht jeweils die Temperaturdaten selber und separat lesen, sondern man sollte die einmal gelesenen Daten in beiden Anzeigen darstellen.

Threads vertragen sich nicht mit GUIs wie das in der `Plotter`-Klasse gemacht wird. Die GUI darf immer nur aus dem Hauptthread verändert werden.

Die `Plotter.update()`-Methode enthält einen offensichtlichen Syntaxfehler bei der Einrückung.

Bezüglich einiger weniger Namen empfiehlt sich ein Blick in den Style Guide for Python Code.
Antworten