Dropdown menü deaktivieren

Fragen zu Tkinter.
Marvin75854

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 @Marvin75854: Wo Unterscheiden sich die `HDPA_Sitzreihe_*`\en denn? Zumindst von dem was man sehen kann ist die `__init__()` mindestens bei den ersten beiden ja gleich. So viel Code zu kopieren würde ich im Grunde sogar als Fehler ansehen und nicht mehr einfach nur als unschön.
Ja stimmt, im Grunde genommen unterscheidet sich bei der 1. und 2. Nur das PhotoImage. Das kann ich aber ja auch einfach in der main Methode übergeben. Dann müsste auch noch übergeben werden um welche Sitzreihe es sich handelt, damit die Ausgabe in der Programmlogik angepasst wird. Also da kann ich eine Klasse löschen. Die 3. Klasse lasse ich erst mal so oder schreibe das PhotoImage in die main methode.

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 Du Übergibst beim erstellen des `HDPA_Berechnung`-Exemplars `hx`, `hz`, und `dy` als `Entry`-Objekte. Das sind Eingabeelemente aus der GUI, davon sollte die Berechnung nichts wissen müssen. Stell Dir mal vor Du möchtest das in einer interaktiven Python-Shell mal testen. Das würde man eigentlich gerne so machen können:

Code: Alles auswählen

>>> from Programmlogik import HDPA_Berechnung
>>> hb = HDPA_Berechnung(42, 23, 47.11, 'test.inc', 1, 1)
>>> hb.hdpa_berechnen()
>>> hb.links_unten_x
86
Geht aber nicht weil die ersten drei Argumente GUI-Eingabeelemente sind. Das heisst statt hier Wert übergeben zu können die man für die reine Berechnung benötigt, muss man erst `Entry`-Elemente erstellen (für die man vorher ein `Tk`-Objekt benötigt) und die Werte dort rein stecken. Anders kann man das nicht testen oder wiederverwenden. Man kann kein anderes GUI-Toolkit verwenden und auch keine Webanwendung daraus machen, obwohl die Art wie die Werte eingegeben wurden, mit der Berechnung eigentlich gar nichts zu tun hat.

Code: Alles auswählen

>>> import Tkinter as tk
>>> from Programmlogik import HDPA_Berechnung
>>> root = tk.Tk()
>>> hx = tk.Entry(root)
>>> hx.set('42')
>>> hz = tk.Entry(root)
>>> hz.set('23')
>>> dy = tk.Entry(root)
>>> dy.set('47.11')
>>> hb = HDPA_Berechnung(hx, hz, dy, 'test.inc', 1, 1)
>>> hb.hdpa_berechnen()
>>> hb.links_unten_x
86
>>> root.destroy()
Ja. Also, wenn ich bei mir das .get() der übergebenen Werte lösche, funktioniert das Testen. Also liegt es wohl daran. Ich habe mir nochmal eure Beispiele angeguckt und der einzige Unterschied ist, dass die get() Methode schon in der GUI Klasse verwendet wird und in der Programmlogik dann nur noch das hx. Ich glaube jetzt verstehe ich das. Mit dem .get() in der Programmlogik wurde das Entry Feld aus der GUI geholt. So wie es jetzt ist, wird das Feld aus der GUI schon vorher geholt und in der Programmlogik nur noch der Wert verwendet?

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 Wenn Du die `HDPA_Ausgabe()` mehrfach aufrufst, machst Du in dem Code aber nicht, *und* es macht auch dann immer noch keinen Sinn die Datei tatsächlich dreimal zu öffnen und zu schliessen. Die könnte man einmal öffnen und dann nicht den Dateinamen übergeben, sondern das offene Dateiobjekt. Ich persönlich würde den Datenfluss dann vielleicht auch umkehren: Nicht den Dateinamen oder das Dateiobjekt an die `HDPA_Ausgabe()` übergeben, sondern die Zeilen/Daten von `HDPA_Ausgabe()` zurückgeben lassen, damit der Aufrufer dann damit machen kann was er möchte. Beispielsweise die Daten in eine Datei schreiben.
Ja in meinem Beispiel ist das noch nicht mehrfahr aufgerufen, weil ich die Funktion bei Sitzreihe 2 noch nicht eingefügt habe. Da soll eben die selbe Berechnung mit anderen Punkten durchgeführt und die Ergebnisse im selben Format ausgegeben werden. Das heißt ich rufe die Funktion z.b. zwei mal auf und geben jeweil das Ergebnis zurück. Mit dem Code den du gezeigt hast. Und dann kann ich die Daten in eine Datei schreiben. Dafür schreibe ich am Besten noch eine extra Funktion?
Ich habe dann aber immer noch das Problem, dass in diese Datei zum späteren Zeitpunkt noch mehr geschrieben werden soll. Ich will also nur einen Button auf der GUI haben. Wenn ich jetzt alle Elemente auf der GUI in eine Klasse schreibe, dann könnte ich das Problem lösen, aber das will ich ja eigentlich vermeiden. Sonst könnte ich es ja genauso gut global lassen.
__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 Bei `HDPA_Berechnung()` bekommt die Funktion die Argumente in der Tat über die `__init__()`. Was keinen Sinn macht, denn man könnte ihr die Argumente auch direkt übergeben. Also der *Funktion*, denn eine Methode ist das ja nicht wirklich.
Ja ich verstehe immer noch nicht den Unterschied zwischen Funktionen und Methoden. Also einer Funktion kann man Argumente direkt übergeben und eine Methode bekommt ihre Argumente innerhalb einer Klasse von der __init__ .

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 Genau, `links_unten_x` & Co sind die Attribute die nicht in der `__init__()` definiert werden. Klar musst Du die Ergebnisse irgendwie benennen, aber die gehören halt nicht als Attribute auf die Klasse, genau so wenig wie die Argumente als Attribute auf diese Klasse gehören. Eventuell kann es Sinn machen Argumente für die Funktion und das Ergebnis der Funktion jeweils in einem eigenen Datentyp zusammen zu fassen, aber alle drei Sachen — Argumente, Funktion, und Ergebnisse — gehören einfach so nicht in einer Klasse.

Ich denke Du fängst bei der Programmlogik am falschen Ende an Daten in Klassen zusammenzufassen. Schreib das lieber erst einmal als Funktionen und schau dann was sich an ”Kleinteilen” zusammenfassen lässt, statt von ”oben” anzufangen und gleich erst mal die komplette Berechnung und Ausgabe in eine Klasse zu stecken.
Ja den Absatz verstehe ich überhaupt nicht. Ja so werde ich das jetzt mal machen.
__blackjack__ hat geschrieben: Montag 30. Juli 2018, 10:38 Die Berechnungsklasse mal als Funktionen, mit einem `collections.namedtuple()` um das Ergebnis der `hdpa_berechnen()`-Funktion zu einem Objekt zusammenfassen zu können:

Code: Alles auswählen

from collections import namedtuple

HDPAResult = namedtuple(
    'HDPAResult',
    'links_unten_x links_unten_z'
    ' rechts_unten_x rechts_unten_z'
    ' links_oben_x links_oben_z'
    ' rechts_oben_x rechts_oben_z'
    ' delta_y'
)

        
def hdpa_berechnen(hx, dy, hz, ddy):
    return HDPAResult(
        hx + 126 - 82, hz + 594 - 58,
        hx + 147 + 82, hz + 594 - 52,
        hx + 126 - 82, hz + 693 + 82,
        hx + 147 + 82, hz + 693 + 82,
        dy + ddy,
    )


def hdpa_ausgabe(hx, ddy, hz, sitzreihe, i_start, hdpa_result, out_file):
    out_file.write(
        '$H-Punkt: ({0}, {1}, {2})\n'
        '$HDPA-Feld fuer die {3}. Sitzreihe:\n'.format(hx, ddy, hz, sitzreihe)
    )
    node_values = [
        (hdpa_result.links_unten_x, hdpa_result.links_unten_z),
        (hdpa_result.rechts_unten_x, hdpa_result.rechts_unten_z),
        (hdpa_result.links_oben_x, hdpa_result.links_oben_z),
        (hdpa_result.rechts_oben_x, hdpa_result.rechts_oben_z),
    ]
    for i, (x, z) in enumerate(node_values, i_start):
        out_file.write(
            'NODE  / 1000000{0}{1:16.6f}{2:16.6f}{3:16.6f}\n'.format(
                i, x, hdpa_result.delta_y, z
            )
        )
    out_file.write(
        'SHELL / 1000000{0}       11000000{1}        \n'
        'PART  / 1000000{0}SHELL          1                        \n'
        'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
        '                    \n'
        '                              \n'
        '        1.    3               \n\n'
        'END_PART\n'.format(
            sitzreihe,
            '1000000'.join(str(i_start + j) for j in [0, 1, 3, 2]),
        )
    )
Hier sieht man IMHO ganz gut das es Sinn machen könnte eine Klasse für 3D-Punkte einzuführen.
Ok ich kann den Code nicht so richtig nachvollziehen was in dem Code passiert, werde mal ein bisschen rumprobieren.
Marvin75854

Sirius3 hat geschrieben: Montag 30. Juli 2018, 11:04 Sollen wirklich die ganzen Zahlen ohne Leerraum ausgegeben werden? Das erinnert so an kaputten Fortran-Output, den man nicht mehr parsen kann, sobald die Zahlen zu groß werden. Diese NODE-Zahlen, die da aneinandergeklebt werden, sehen auch komisch aus.
__blackjack__ hat geschrieben: Montag 30. Juli 2018, 12:18 @Sirius3: Da es sich ja wohl um irgendwelche numerischen Modellrechnungen/Simulationen handelt, könntest Du mit Fortran vielleicht sogar richtig liegen. Marvin75854's letzter Satz spricht IMHO auch für ein ”fixed size” Ein-/Ausgabeformat.
Ja richtig. Das soll am Ende eine Pamcrash Include Datei werden. Für ein HDPA Feld sieht das Ganze dann ungefähr so aus:

Code: Alles auswählen

$Erstellt durch COG-Tool am: 30.07.2018 14:20:52
$H-Punkt: (50, -365, 50)
$HDPA-Feld fuer die 1. Sitzreihe:
NODE  / 10000001       94.000000     -415.000000      592.000000
NODE  / 10000002      279.000000     -415.000000      592.000000
NODE  / 10000003       94.000000     -415.000000      825.000000
NODE  / 10000004      279.000000     -415.000000      825.000000
SHELL / 10000001       110000001100000021000000410000003        
PART  / 10000001SHELL          1                        
NAMEDefault HDPA_Feld_1.Sitzreihe
                    
                              
        1.    3               

END_PART
ENDDATA
Die Datei wird am Ende dann noch wesentlich lännger, je nachdem was auf der GUI alles eingegeben wird. Man kann das in Python sicherlich noch eleganter schreiben. Da kann ich später nochmal gucken, ob ich das noch anpasse.
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin75854: Wenn man sich das mal mit Punkten überlegt, dann scheint die Berechnungsfunktion beispielsweise vier Punkte zu berechnen, wobei die Y-Koordinaten bei allen gleich ist. Das Ergebnis könnt man also durch eine Liste mit vier Punkten ersetzen.

Code: Alles auswählen

class Vector(object):
    
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z
    
    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

        
def hdpa_berechnen(point, ddy):
    return [
        point + Vector(126 - 82, ddy, 594 - 58),
        point + Vector(147 + 82, ddy, 594 - 52),
        point + Vector(126 - 82, ddy, 693 + 82),
        point + Vector(147 + 82, ddy, 693 + 82),
    ]


def hdpa_ausgabe(h_point, sitzreihe, i_start, node_points, out_file):
    out_file.write(
        '$H-Punkt: {0}\n'
        '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
    )
    i = None
    for i, point in enumerate(node_points, i_start):
        out_file.write(
            'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                i, point
            )
        )
    indices = [0, 1, 3, 2]
    if len(indices) != i:
        raise ValueError(
            'wrong number of node points ({} != {})'.format(len(indices), i)
        )
    out_file.write(
        'SHELL / 1000000{0}       11000000{1}        \n'
        'PART  / 1000000{0}SHELL          1                        \n'
        'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
        '                    \n'
        '                              \n'
        '        1.    3               \n\n'
        'END_PART\n'.format(
            sitzreihe,
            '1000000'.join(str(i_start + j) for j in indices),
        )
    )
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

@__blackjack__: Vector könnte man noch eine __format__-Methode spendieren:

Code: Alles auswählen

class Vector(object):

    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)

    def __format__(self, format):
        return '{0.x:{1}}{0.y:{1}}{0.z:{1}}'.format(self, format)

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

[...]

    for i, point in enumerate(node_points, i_start):
        out_file.write('NODE  / 1000000{}{:16.6f}\n'.format(i, point))
Marvin75854

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 14:09 @Marvin75854: Wenn man sich das mal mit Punkten überlegt, dann scheint die Berechnungsfunktion beispielsweise vier Punkte zu berechnen, wobei die Y-Koordinaten bei allen gleich ist. Das Ergebnis könnt man also durch eine Liste mit vier Punkten ersetzen.

Code: Alles auswählen

class Vector(object):
    
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z
    
    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

        
def hdpa_berechnen(point, ddy):
    return [
        point + Vector(126 - 82, ddy, 594 - 58),
        point + Vector(147 + 82, ddy, 594 - 52),
        point + Vector(126 - 82, ddy, 693 + 82),
        point + Vector(147 + 82, ddy, 693 + 82),
    ]


def hdpa_ausgabe(h_point, sitzreihe, i_start, node_points, out_file):
    out_file.write(
        '$H-Punkt: {0}\n'
        '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
    )
    i = None
    for i, point in enumerate(node_points, i_start):
        out_file.write(
            'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                i, point
            )
        )
    indices = [0, 1, 3, 2]
    if len(indices) != i:
        raise ValueError(
            'wrong number of node points ({} != {})'.format(len(indices), i)
        )
    out_file.write(
        'SHELL / 1000000{0}       11000000{1}        \n'
        'PART  / 1000000{0}SHELL          1                        \n'
        'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
        '                    \n'
        '                              \n'
        '        1.    3               \n\n'
        'END_PART\n'.format(
            sitzreihe,
            '1000000'.join(str(i_start + j) for j in indices),
        )
    )
Ich will echt nicht immer alles nachfragen, aber ich habe keine Ahnung wie ich das jetzt verwenden soll. Also wie ich das in der GUI Klasse aufrufen soll. Ich muss ja jetzt die Eingabefelder in eine Liste schreiben und dann übergeben als "point und h_point? Die Funktion hdpa_berechnen verwendet die Klasse Vector bereits automatisch? Das heißt ich muss irgendwie die zwei Funktionen aufrufen. Ich werde mir das morgen nochmal angucken. Verstehe nicht mal was genau die Funktionen wie machen
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin75854: Ups, ich hatte einen Beitrag von Dir übersehen.

Der Unterschied zwischen einer Funktion und einer Methode ist nicht der wie die Argumente übergeben werden, das ist letztlich bei beiden gleich, sondern das eine Methode zu einem Objekt gehört in dem diese Methode, Daten die den Zustand des Objekts beschreiben, und noch andere Methoden, *sinnvoll* zusammengefasst sind. Und Du hast da IMHO zwei Funktionen und Argumente für die Funktionen zu einer Klasse zusammengefasst die semantisch gar keine Klasse ist. Was man dadurch zeigen kann, das es sich ganz einfach als zwei einzelne Funktionen schreiben lässt, und dabei IMHO auch gleich noch lesbarer wird, weil bei `berechnen()` und `ausgabe()` jetzt sichtbarer ist, was die jeweils an Werten brauchen und an den Aufrufer zurückgeben.

Bei der Variante mit `Vector` übergibt man nun statt `hx`, `dy`, und `hz` einzeln, ein `Vector`-Objekt für `point`. Und für `ddy` die -365 die vorher hart kodiert an zwei Stellen im Quelltext stand. Bei `h_point` so ähnlich nur das dort die `y`-Komponente die -365 ist.

Ich konnte mich ja nur an den Namen orientieren. Ist das echt so weit an der Bedeutung vorbei die das tatsächlich hat? Bilden die drei Argumente keinen Punkt? Und erstellt `HDPA_Berechnen()` nicht etwas das sich durch vier Punkte im Raum beschreiben lässt, wobei die alle in einer Ebene parallel zur Z-Achse liegen?

Benutzung könnte so aussehen (ungetestet):

Code: Alles auswählen

            ddy = -365
            hx, dy, hz = (
                float(entry.get()) for entry in [self.hx, self.dy, self.hz]
            )

            filename = tkFileDialog.asksaveasfilename(
                initialdir=os.getcwd(),
                title='Speichern der Include-Datei',
                filetypes=(('all files', '*.*'), ('inc files', '*.inc'))
            )
            with open(filename, 'a') as out_file:
                out_file.write(
                    '$Erstellt durch COG-Tool am: {0}\n'.format(
                        time.strftime('%d.%m.%Y %H:%M:%S')
                    )
                )
                
                hdpa_points = hdpa_berechnen(Vector(hx, dy, hz), ddy)
                hdpa_ausgabe(
                    Vector(hx, ddy, hz),
                    self.sitzreihe,
                    self.i,
                    hdpa_points,
                    out_file
                )
                
                out_file.write('ENDDATA\n') 
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Marvin75854

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 21:05 Der Unterschied zwischen einer Funktion und einer Methode ist nicht der wie die Argumente übergeben werden, das ist letztlich bei beiden gleich, sondern das eine Methode zu einem Objekt gehört in dem diese Methode, Daten die den Zustand des Objekts beschreiben, und noch andere Methoden, *sinnvoll* zusammengefasst sind. Und Du hast da IMHO zwei Funktionen und Argumente für die Funktionen zu einer Klasse zusammengefasst die semantisch gar keine Klasse ist. Was man dadurch zeigen kann, das es sich ganz einfach als zwei einzelne Funktionen schreiben lässt, und dabei IMHO auch gleich noch lesbarer wird, weil bei `berechnen()` und `ausgabe()` jetzt sichtbarer ist, was die jeweils an Werten brauchen und an den Aufrufer zurückgeben.
Ja das meinte ich ja ganz am Anfang schon mal, dass ich den Sinn der Klassen nicht so ganz verstehe, weil es mit normalen Funktionen genauso funktioniert und wahrscheinlich übersichtlicher ist. Vielleicht ist mein Code auch nicht perfekt für die Anwendung von Klassen am Anfang. Werde das jetzt wirklich erstmal mit Funktionen alles machen und vielleicht verstehe ich das später dann doch noch besser.

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 21:05 Bei der Variante mit `Vector` übergibt man nun statt `hx`, `dy`, und `hz` einzeln, ein `Vector`-Objekt für `point`. Und für `ddy` die -365 die vorher hart kodiert an zwei Stellen im Quelltext stand. Bei `h_point` so ähnlich nur das dort die `y`-Komponente die -365 ist.

Ich konnte mich ja nur an den Namen orientieren. Ist das echt so weit an der Bedeutung vorbei die das tatsächlich hat? Bilden die drei Argumente keinen Punkt? Und erstellt `HDPA_Berechnen()` nicht etwas das sich durch vier Punkte im Raum beschreiben lässt, wobei die alle in einer Ebene parallel zur Z-Achse liegen?
Nein ich habe es jetzt verstanden. Genau so ist es. Man gibt einen Punkt ein aus dem dann eine Fläche errechnet wird. Die y-Koordinate von dem Punkt den man eingibt ist -365. Da die immer -365 ist, wäre es einfach unnötig die eingeben zu müssen. Und ddy ist dann einfach die Verschiebung der Fläche auf der y-Achse. ddy soll auch später noch für ganze andere Funktionen verwendet werden. Wie ich das mache, weiß ich noch nicht.

__blackjack__ hat geschrieben: Montag 30. Juli 2018, 21:05 Benutzung könnte so aussehen (ungetestet):

Code: Alles auswählen

            ddy = -365
            hx, dy, hz = (
                float(entry.get()) for entry in [self.hx, self.dy, self.hz]
            )

            filename = tkFileDialog.asksaveasfilename(
                initialdir=os.getcwd(),
                title='Speichern der Include-Datei',
                filetypes=(('all files', '*.*'), ('inc files', '*.inc'))
            )
            with open(filename, 'a') as out_file:
                out_file.write(
                    '$Erstellt durch COG-Tool am: {0}\n'.format(
                        time.strftime('%d.%m.%Y %H:%M:%S')
                    )
                )
                
                hdpa_points = hdpa_berechnen(Vector(hx, dy, hz), ddy)
                hdpa_ausgabe(
                    Vector(hx, ddy, hz),
                    self.sitzreihe,
                    self.i,
                    hdpa_points,
                    out_file
                )
                
                out_file.write('ENDDATA\n') 
Das hilft mir extrem. Konnte ich auch fast genau so übernehmen. Ich werde jetzt wirklich erstmal versuchen alles in Funktionen zu machen. Die GUI Elemente würde ich aber weiterhin gerne auf Klassen aufteilen, weiß aber nicht so richtig wie ich dann am Ende über einen Ausgabe Button alles Funktionen bündeln kann.
Im Moment ist es ja so, dass ich mit einer Klasse hdpa die GUI Elemente auf dem ersten Reiter erzeuge. Dann habe ich die Klasse hdpa in der main Methode nochmal aufgerufen um auch auf dem zweiten Reiter der GUI die Elemente zu erzeugen. In der Klasse habe ich auch den Export Button definiert der die Funktionen in der Programmlogik aufruft. Der Funktioniert auch, allerdings habe ich das Problem, dass ich den Export Button jetzt zwei mal habe. Und es kommen später auch noch weitere Funktionen dazu die auch was exportieren sollen. Ich will also einen Export Button, der alle Berechnungen durchführt und alle Ergebnisse der gesamten GUI ausgibt. Bzw. wichtig ist nur die Ausgabe. Die Berechnungen können schon vorher durchgeführt worden sein.
Also meine Idee war eine eigene Klasse für den Button zu schreiben der dann die GUI Klassen aufruft. Dann hätte ich die GUI Elemente aber ja alle doppelt übereinander liegen. Hier nochmal der Code. Das meiste stammt ja eh von dir. :D :

Code: Alles auswählen

#!/usr/bin/python
from __future__ import print_function
import subprocess
from Tkinter import *
import Tkinter, Tkconstants, tkFileDialog
import os
from tkMessageBox import *
import math
import sys
import time
import Tix as tx

import Programmlogik_2



class HDPA_Sitzreihe_1(Frame):
    def __init__(self, parent, name_Bild):
        Frame.__init__(self, parent)
        
        Label(self, text="X").grid(row=13)
	Label(self, text="Z").grid(row=13, column=1)
        self.name_Bild = name_Bild

	self.hx = Entry(self)
	self.hz = Entry(self)
	self.hx.grid(row=14, column=0)
	self.hz.grid(row=14, column=1)

	Label(self, text="Y-Abstand: COG/H-Punkt zu Airbag").grid(row=15,pady=(20,0))
	self.dy = Entry(self)
	self.dy.grid(row=16, column=0) 
        
        
        self.HDPA = Label(self, text="H-Punkt WS50%")
	self.HDPA.grid(row=12, column=0, padx=20)
        
	self.box = IntVar()
	Checkbutton(self, text="HDPA Feld", variable=self.box).grid(row=11)        
        
        self.logo = PhotoImage(file=self.name_Bild)
	w1 = Label(self, image=self.logo).grid(row=0, column=0, pady=20,padx=20, rowspan=10, columnspan=5)
        
        self.sitzreihe = 1
        self.i = 1
        
        
        
        
        
        self.Export_button = Button(self, text="Export", command=self.Export)
        self.Export_button.grid(row=18, column=0)
        
        
        
    def Export(self):
    
        if self.box.get() == 1:
        
            ddy = -365
        
            hx, dy, hz = (
                float(entry.get()) for entry in [self.hx, self.dy, self.hz]
            )
        
            filename = tkFileDialog.asksaveasfilename(
                initialdir=os.getcwd(),
                title='Speichern der Include-Datei',
                filetypes=(('all files', '*.*'), ('inc files', '*.inc'))
            )
            with open(filename, 'a') as out_file:
                out_file.write(
                    '$Erstellt durch COG-Tool am: {0}\n'.format(
                        time.strftime('%d.%m.%Y %H:%M:%S')
                    )
                )
                
                hdpa_points = Programmlogik_2.hdpa_berechnen(Programmlogik_2.Vector(hx, dy, hz), ddy)
                Programmlogik_2.hdpa_ausgabe(
                    Programmlogik_2.Vector(hx, ddy, hz),
                    self.sitzreihe,
                    self.i,
                    hdpa_points,
                    out_file
                    
                )
                
                out_file.write('ENDDATA\n') 
            
        else:
            print("Kein HDPA-Feld")
            print(self.hx)
                
        
        
        
#class HDPA_Sitzreihe_3(Frame):
#    def __init__(self, parent):
#        Frame.__init__(self, parent)        
#        
#        self.logo = PhotoImage(file="Sitzreferenzfeld_3.Reihe.gif")
#        w = Label(self, image=self.logo).grid(row=0, column=0, pady=20,padx=20, rowspan=10, columnspan=5)
        
        
        

def main():
    GUI = tx.Tk()
    GUI.title ("COG Tool") 
    GUI.geometry("1800x800")
    
    swr=tx.ScrolledWindow(GUI)
    swr.pack(fill=tx.BOTH, expand=1)
    
    nb=tx.NoteBook(swr.window)
    nb.pack(fill=tx.BOTH, expand=1)

    nb.add("sitzreihe"+str(1),label="1. Sitzreihe")
    nb.add("sitzreihe"+str(2),label="2. Sitzreihe")
    nb.add("sitzreihe"+str(3),label="3. Sitzreihe")
     
    
    hdpa_sitzreihe_1 = HDPA_Sitzreihe_1(nb.sitzreihe1,"Sitzreferenzfeld.gif")
    hdpa_sitzreihe_1.grid(row=0, column=0)
    
    
    hdpa_sitzreihe_2 = HDPA_Sitzreihe_1(nb.sitzreihe2,"Sitzreferenzfeld_2.Reihe.gif")
    hdpa_sitzreihe_2.grid(row=0, column=0)
 
#    hdpa_sitzreihe_3 = HDPA_Sitzreihe_3(nb.sitzreihe3)
#    hdpa_sitzreihe_3.grid(row=0, column=0) 
 
    
    GUI.mainloop()


if __name__ == "__main__": 
    main()

Und die Programmlogik:

Code: Alles auswählen

#!/usr/bin/python
from __future__ import print_function
import subprocess
from Tkinter import *
import Tkinter, Tkconstants, tkFileDialog
import os
from tkMessageBox import *
import math
import sys
import time
import Tix as tx


class Vector(object):
    
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z
    
    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

        
def hdpa_berechnen(point, ddy):
    return [
        point + Vector(126 - 82, ddy, 594 - 58),
        point + Vector(147 + 82, ddy, 594 - 52),
        point + Vector(126 - 82, ddy, 693 + 82),
        point + Vector(147 + 82, ddy, 693 + 82),
    ]


def hdpa_ausgabe(h_point, sitzreihe, i_start, node_points, out_file):
    out_file.write(
        '$H-Punkt: {0}\n'
        '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
    )
    i = None
    for i, point in enumerate(node_points, i_start):
        out_file.write(
            'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                i, point
            )
        )
    indices = [0, 1, 3, 2]
    if len(indices) != i:
        raise ValueError(
            'wrong number of node points ({} != {})'.format(len(indices), i)
        )
    out_file.write(
        'SHELL / 1000000{0}       11000000{1}        \n'
        'PART  / 1000000{0}SHELL          1                        \n'
        'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
        '                    \n'
        '                              \n'
        '        1.    3               \n\n'
        'END_PART\n'.format(
            sitzreihe,
            '1000000'.join(str(i_start + j) for j in indices),
        )
    )
Meine Idee wäre eine Klasse für den Button zu schreiben, der dann eine Methode/Funktion aufruft die über die hdpa Klassen und die Klassen die noch später dazu kommen die jeweiligen Berechnungs/Ausgabe Funktionen aufruft. Also dass nicht erneut ein Objekt der Klassen erzeugt wird, sondern nur auf das bereits erzeugte Objekt zugegriffen wird. Also, dass die Funktionen der Klasse durch eine externe Klasse aufgerufen werden. Keine Ahnung ob ich das richtig erklären kann. Vielleicht könnte ich das über Vererbungen machen? Ich will das nicht wieder alles zu extrem miteinander verstricken.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Marvin75854 hat geschrieben: Dienstag 31. Juli 2018, 08:07 Meine Idee wäre eine Klasse für den Button zu schreiben,
Ein Button ist einfach nur ein Button, der braucht keine eigene Klasse. Was Du machen könntest, wäre eine Klasse für das Hauptfenster, denn das hat ja mit den ganzen Sitzreihen und Knöpfen einiges an Zustand.

Module werden komplett kein geschrieben, Programmlogik_2 hat außerdem noch eine Nummer, was kein guter Modulname ist. Komplett groß geschrieben Namen sind für Konstanten reserviert, GUI sollte also gui heißen, denn Variablen und Attribute werden komplett_klein geschrieben. Sternchenimporte vermeiden, die ganzen Tkinter-Namen kannst Du ja auch über tx.xxx referenzieren.
Marvin75854 hat geschrieben: Dienstag 31. Juli 2018, 08:07Also dass nicht erneut ein Objekt der Klassen erzeugt wird, sondern nur auf das bereits erzeugte Objekt zugegriffen wird.
Von welchen Klassen sprichst Du hier? Bisher hast Du nur GUI-Klassen, die einmal am Anfang erzeugt werden. Für die Berechnung sehe ich noch nicht die Notwendigkeit von Klassen. Vererbung ist dann noch eine Stufe später dran. Erst wenn Du merkst, dass es sinnvoll ist aus Funktionen eine Klasse zu machen und wenn Du später mehrere Klassen hast, die gemeinsame Methoden und Zustände haben, dann kannst Du darüber nachdenken, eine Überklasse einzurichten, aber wirklich nur dann, wenn es eine IST-EINE-Beziehung zwischen den Klassen gibt.
Marvin75854

Sirius3 hat geschrieben: Dienstag 31. Juli 2018, 08:46 Von welchen Klassen sprichst Du hier? Bisher hast Du nur GUI-Klassen, die einmal am Anfang erzeugt werden. Für die Berechnung sehe ich noch nicht die Notwendigkeit von Klassen. Vererbung ist dann noch eine Stufe später dran. Erst wenn Du merkst, dass es sinnvoll ist aus Funktionen eine Klasse zu machen und wenn Du später mehrere Klassen hast, die gemeinsame Methoden und Zustände haben, dann kannst Du darüber nachdenken, eine Überklasse einzurichten, aber wirklich nur dann, wenn es eine IST-EINE-Beziehung zwischen den Klassen gibt.
Ja bisher schon. Ich werde aber am Ende noch mehrere Klassen schreiben, da auf meiner GUI ja sehr viel mehr Eingabefelder sein sollen als ich bisher habe. Ich will am Ende alles über einen Button laufen lassen. Also ein Button soll sich Werte aus Eingabefeldern von der GUI holen, mehrere Funktionen aufrufen und alles in eine Text Datei schreiben. Die GUI Elemente in den Klassen werden ja ganz am Anfang in der main Methode erzeugt. Jetzt habe ich bisher immer nur aus der Klasse selbst auf Funktionen zugegriffen. Aber wie kann ich es hinkriegen, dass der Button aus bspw. 3 verschiedenen Klassen mit GUI Elementen die Werte holt und damit 5 verschiedene Funktionen ausführt. Ich wüsste wie ich es mache, wenn ich die gesamte GUI in eine Klasse schreibe, aber dann kann ich es ja auch gleich wieder global definieren...
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin75854: Die drei verschiedenen Klassen mit GUI-Elementen müssen da halt eine Methode für vorsehen. So wie `Entry`-Objekte eine `get()`-Methode haben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Marvin75854

Hier noch einige Tipps:
a) Für das Einrücken um 4 Stellen nur Tabs oder Spaces aber nicht beides verwenden. Ich verwende z.B. nur Spaces.
b) Ich würde nur mit tkinter Python3.xx verwenden.
c) Auf die Verwendung von Tix würde ich verzichten und an Stelle ttk Widgets verwenden.

Habe anhand der vorhergehenden Beiträgen versucht das folgende Skript zu erstellen. Konnte aber mit der Klassenmethode hdpa_ausgabe abbrechen müssen da ich eine nähere Beschreibung der ganzen Rechnerei und deiner Anwendung benötige. Was ist in deinem Skript der Unterschied zwischen self.sitzreihe und self.i (i_start) :

Code: Alles auswählen

import os
import time
from functools import partial

import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog

APP_TITLE = "COG Tool"
APP_XPOS = 50
APP_YPOS = 50
APP_WIDTH = 800 #1800
APP_HEIGHT = 400 #800

class ModelVector(object):

    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return ModelVector(
            self.x + other.x, self.y + other.y, self.z + other.z)

class ModelMain(object):
    DDY = -365
    def __init__(self, app):
        self.app = app
        self.ddy = self.DDY
        
    def export(self, filename, row_index, point_values):
        x, y, z = point_values
        
        with open(filename, 'a') as out_file:
            out_file.write('$Erstellt durch COG-Tool am: {0}\n'.format(
                    time.strftime('%d.%m.%Y %H:%M:%S')))

            
            hdpa_points = self.hdpa_berechnen(ModelVector(x, y, z), self.ddy)
            self.hdpa_ausgabe(
                ModelVector(x, self.ddy, z),
                row_index, #self.sitzreihe
                row_index, #self.i,
                hdpa_points,
                out_file)
            
            out_file.write('ENDDATA\n') 

    def hdpa_berechnen(self, point, ddy):
        return [
            point + ModelVector(126 - 82, ddy, 594 - 58),
            point + ModelVector(147 + 82, ddy, 594 - 52),
            point + ModelVector(126 - 82, ddy, 693 + 82),
            point + ModelVector(147 + 82, ddy, 693 + 82)]


    def hdpa_ausgabe(self, h_point, sitzreihe, i_start, node_points, out_file):
        print("Hier bricht meine Unterstützung ab!")
        return
        
        out_file.write(
            '$H-Punkt: {0}\n'
            '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
        )
        i = None
        for i, point in enumerate(node_points, i_start):
            out_file.write(
                'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                    i, point
                )
            )
    
        indices = [0, 1, 3, 2]
        print("Check:", len(indices), i)
        if len(indices) != i:
            raise ValueError(
                'wrong number of node points ({} != {})'.format(len(indices), i)
            )
        out_file.write(
            'SHELL / 1000000{0}       11000000{1}        \n'
            'PART  / 1000000{0}SHELL          1                        \n'
            'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
            '                    \n'
            '                              \n'
            '        1.    3               \n\n'
            'END_PART\n'.format(
                sitzreihe,
                '1000000'.join(str(i_start + j) for j in indices),
            )
        )
        
class GuiSeatRow(tk.Frame):
    ROW_NR_FONT = "Helvetica 22 bold"
    
    def __init__(self, gui, row):
        self.gui = gui
        self.row = row
        
        self.build()
        
    def build(self):
        tk.Frame.__init__(self, self.gui.main_frame)
        
        self.row_var = tk.IntVar(self.gui.app.main_win, self.row+1)
        tk.Label(self, textvariable= self.row_var, bg='blue',
            fg='white', font=self.ROW_NR_FONT, width=2
            ).pack(pady=(5, 10))
        
        self.box = tk.IntVar(self.gui.app.main_win, False)
        tk.Checkbutton(self, text="HDPA Feld", variable=self.box
            ).pack()        
 
        self.hdpa = tk.Label(self, text="H-Punkt WS50%")
        self.hdpa.pack(pady=5)
      
        entry_frame = tk.Frame(self)
        entry_frame.pack(pady=5)
        
        label_frame = tk.LabelFrame(entry_frame, text="X:", relief='flat')
        label_frame.pack(side='left')
        self.hx_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hx_var).pack()
        
        label_frame = tk.LabelFrame(entry_frame, text="Z:", relief='flat')
        label_frame.pack(side='left')
        self.hz_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hz_var).pack()
 
        label_text = "Y-Abstand:\nCOG/H-Punkt zu Airbag"
        label_frame = tk.LabelFrame(self, text=label_text,
            relief='flat')
        label_frame.pack(anchor='w', pady=5)
        self.dy_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.dy_var).pack() 

        tk.Button(self, text="Export", command=partial(
            self.gui.export, self.row)).pack(pady=5)

        
class GuiMain(object):
    NOTEBOOK_TAB_FONT = ("Helvetica", 12, "bold")
    ANZAHL_SITZREIHEN = 5
    
    def __init__(self, app):
        self.app = app
        
        self.seat_rows = list()
        
        self.build()
        
        for row in range(self.ANZAHL_SITZREIHEN):
            seat_row = GuiSeatRow(self, row)
            seat_row.pack()
            self.note_book.add(seat_row, text="Sitzreihe-{}".format(row+1),
                sticky='nw', padding=10)
            self.seat_rows.append(seat_row)
        
    def build(self):
        self.main_frame = tk.Frame(self.app.main_win)
        self.main_frame.pack(fill='both', expand=True, padx=5, pady=5)

        self.note_book = ttk.Notebook(self.main_frame)
        self.note_book.pack(fill='both', expand=True)

    def file_dialog(self):
        filename = filedialog.asksaveasfilename(
            initialdir=os.getcwd(),
            title='Speichern der Include-Datei',
            filetypes=(('all files', '*.*'), ('inc files', '*.inc')))
        return filename
            
        
    def export(self, row_index):
        if self.seat_rows[row_index].box.get():
            hx_var = self.seat_rows[row_index].hx_var
            dy_var = self.seat_rows[row_index].dy_var
            hz_var = self.seat_rows[row_index].hz_var
                       
            self.app.export(row_index, (float(entry_var.get()) 
                for entry_var in [hx_var, dy_var, hz_var]))
        else:
            print("Kein HDPA-Feld")
            print(self.seat_rows[row_index].hx_var.get())
     
class App(object):

    def __init__(self, main_win):
        self.main_win = main_win
        self.main_win.protocol("WM_DELETE_WINDOW", self.close)
        
        self.model = ModelMain(self)
        self.gui = GuiMain(self)
            
    def export(self, row_index, point_values):
        filename = self.gui.file_dialog()
        if filename != ():
            self.model.export(filename, row_index, point_values)
        else:
            print("Filedialog wurde abgebrochen")
                
    def close(self):
        print("Application-Shutdown")
        self.main_win.withdraw()
        self.main_win.destroy()
        
               
def main():
    main_win = tk.Tk()
    main_win.title(APP_TITLE)
    #main_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    main_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    main_win.option_add("*highlightThickness", 0)
    ttk_style = ttk.Style()
    ttk_style.configure('TNotebook.Tab', font="Helvetica 10 bold",
        foreground='blue', background='gray75')
    
    app = App(main_win)
    
    main_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf ;-)
Take it easy Mates!
Marvin75854

Hi wuf,


a) Für das Einrücken um 4 Stellen nur Tabs oder Spaces aber nicht beides verwenden. Ich verwende z.B. nur Spaces.

Mache ich eigentlich auch immer so. Habe aber viel zusammenkopiert. Deswegen ist es wahrscheinlich teilweise unterschiedlich.
wuf hat geschrieben: Donnerstag 2. August 2018, 10:06 b) Ich würde nur mit tkinter Python3.xx verwenden.
Ich arbeite nicht an meinem privaten Rechner und hier ist nur python 2.6.6 installiert. Ich weiß nicht, ob ich hier eine neuere Version installieren könnte. Ich müsste dafür dann mal mit der IT-Abteilung sprechen, denke aber das ist keine Option. Zumal ich sowieso nur noch 2 Monate Zeit habe.

wuf hat geschrieben: Donnerstag 2. August 2018, 10:06 c) Auf die Verwendung von Tix würde ich verzichten und an Stelle ttk Widgets verwenden.
Das ist bei mir glaube ich nicht dabei: ImportError: No module named ttk. Habe auch verschiedene Schreibweisen ausprobiert. Deshalb funktioniert auch leider dein Code nicht. Werde mir den gleich mal genauer angucken.
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wuf: Hier fällt gleich wieder auf das `hdpa_berechnen()` und `hdpa_ausgabe()` gar keine Methoden sind, sondern einfach nur Funktionen die in die Klasse gesteckt wurden. Ich würde da auch nicht überall den Präfix `Model` davor setzen. Zudem sollte das `app` nicht bekommen. Wird ja sowieso nicht verwendet.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Ok Marvin75854

Hier die Variante für Python2.xx:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time
from functools import partial

import Tkinter as tk
import ttk
import tkFileDialog

APP_TITLE = "COG Tool"
APP_XPOS = 50
APP_YPOS = 50
APP_WIDTH = 800 #1800
APP_HEIGHT = 400 #800

class ModelVector(object):

    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return ModelVector(
            self.x + other.x, self.y + other.y, self.z + other.z)

class ModelMain(object):
    DDY = -365
    def __init__(self):
        self.ddy = self.DDY
        
    def export(self, filename, row_index, point_values):
        x, y, z = point_values
        
        with open(filename, 'a') as out_file:
            out_file.write('$Erstellt durch COG-Tool am: {0}\n'.format(
                    time.strftime('%d.%m.%Y %H:%M:%S')))

            
            hdpa_points = self.hdpa_berechnen(ModelVector(x, y, z), self.ddy)
            self.hdpa_ausgabe(
                ModelVector(x, self.ddy, z),
                row_index, #self.sitzreihe
                row_index, #self.i,
                hdpa_points,
                out_file)
            
            out_file.write('ENDDATA\n') 

    def hdpa_berechnen(self, point, ddy):
        return [
            point + ModelVector(126 - 82, ddy, 594 - 58),
            point + ModelVector(147 + 82, ddy, 594 - 52),
            point + ModelVector(126 - 82, ddy, 693 + 82),
            point + ModelVector(147 + 82, ddy, 693 + 82)]


    def hdpa_ausgabe(self, h_point, sitzreihe, i_start, node_points, out_file):
        print("Hier bricht meine Unterstützung ab!")
        return
        
        out_file.write(
            '$H-Punkt: {0}\n'
            '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
        )
        i = None
        for i, point in enumerate(node_points, i_start):
            out_file.write(
                'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                    i, point
                )
            )
    
        indices = [0, 1, 3, 2]
        print("Check:", len(indices), i)
        if len(indices) != i:
            raise ValueError(
                'wrong number of node points ({} != {})'.format(len(indices), i)
            )
        out_file.write(
            'SHELL / 1000000{0}       11000000{1}        \n'
            'PART  / 1000000{0}SHELL          1                        \n'
            'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
            '                    \n'
            '                              \n'
            '        1.    3               \n\n'
            'END_PART\n'.format(
                sitzreihe,
                '1000000'.join(str(i_start + j) for j in indices),
            )
        )
        
class GuiSeatRow(tk.Frame):
    ROW_NR_FONT = "Helvetica 22 bold"
    
    def __init__(self, gui, row):
        self.gui = gui
        self.row = row
        
        self.build()
        
    def build(self):
        tk.Frame.__init__(self, self.gui.main_frame)
        
        self.row_var = tk.IntVar(self.gui.app.main_win, self.row+1)
        tk.Label(self, textvariable= self.row_var, bg='blue',
            fg='white', font=self.ROW_NR_FONT, width=2
            ).pack(pady=(5, 10))
        
        self.box = tk.IntVar(self.gui.app.main_win, False)
        tk.Checkbutton(self, text="HDPA Feld", variable=self.box
            ).pack()        
 
        self.hdpa = tk.Label(self, text="H-Punkt WS50%")
        self.hdpa.pack(pady=5)
      
        entry_frame = tk.Frame(self)
        entry_frame.pack(pady=5)
        
        label_frame = tk.LabelFrame(entry_frame, text="X:", relief='flat')
        label_frame.pack(side='left')
        self.hx_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hx_var).pack()
        
        label_frame = tk.LabelFrame(entry_frame, text="Z:", relief='flat')
        label_frame.pack(side='left')
        self.hz_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hz_var).pack()
 
        label_text = "Y-Abstand:\nCOG/H-Punkt zu Airbag"
        label_frame = tk.LabelFrame(self, text=label_text,
            relief='flat')
        label_frame.pack(anchor='w', pady=5)
        self.dy_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.dy_var).pack() 

        tk.Button(self, text="Export", command=partial(
            self.gui.export, self.row)).pack(pady=5)

        
class GuiMain(object):
    NOTEBOOK_TAB_FONT = ("Helvetica", 12, "bold")
    ANZAHL_SITZREIHEN = 5
    
    def __init__(self, app):
        self.app = app
        
        self.seat_rows = list()
        
        self.build()
        
        for row in range(self.ANZAHL_SITZREIHEN):
            seat_row = GuiSeatRow(self, row)
            seat_row.pack()
            self.note_book.add(seat_row, text="Sitzreihe-{}".format(row+1),
                sticky='nw', padding=10)
            self.seat_rows.append(seat_row)
        
    def build(self):
        self.main_frame = tk.Frame(self.app.main_win)
        self.main_frame.pack(fill='both', expand=True, padx=5, pady=5)

        self.note_book = ttk.Notebook(self.main_frame)
        self.note_book.pack(fill='both', expand=True)

    def file_dialog(self):
        filename = tkFileDialog.asksaveasfilename(
            initialdir=os.getcwd(),
            title='Speichern der Include-Datei',
            filetypes=(('all files', '*.*'), ('inc files', '*.inc')))
        return filename
            
        
    def export(self, row_index):
        if self.seat_rows[row_index].box.get():
            hx_var = self.seat_rows[row_index].hx_var
            dy_var = self.seat_rows[row_index].dy_var
            hz_var = self.seat_rows[row_index].hz_var
                       
            self.app.export(row_index, (float(entry_var.get()) 
                for entry_var in [hx_var, dy_var, hz_var]))
        else:
            print("Kein HDPA-Feld")
            print(self.seat_rows[row_index].hx_var.get())
     
class App(object):

    def __init__(self, main_win):
        self.main_win = main_win
        self.main_win.protocol("WM_DELETE_WINDOW", self.close)
        
        self.model = ModelMain()
        self.gui = GuiMain(self)
            
    def export(self, row_index, point_values):
        filename = self.gui.file_dialog()
        if filename != ():
            self.model.export(filename, row_index, point_values)
        else:
            print("Filedialog wurde abgebrochen")
                
    def close(self):
        print("Application-Shutdown")
        self.main_win.withdraw()
        self.main_win.destroy()
        
               
def main():
    main_win = tk.Tk()
    main_win.title(APP_TITLE)
    #main_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    main_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    main_win.option_add("*highlightThickness", 0)
    ttk_style = ttk.Style()
    ttk_style.configure('TNotebook.Tab', font="Helvetica 10 bold",
        foreground='blue', background='gray75')
    
    app = App(main_win)
    
    main_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Gruss wuf ;-)
Take it easy Mates!
Marvin75854

wuf hat geschrieben: Donnerstag 2. August 2018, 15:46 Ok Marvin75854

Hier die Variante für Python2.xx:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time
from functools import partial

import Tkinter as tk
import ttk
import tkFileDialog

APP_TITLE = "COG Tool"
APP_XPOS = 50
APP_YPOS = 50
APP_WIDTH = 800 #1800
APP_HEIGHT = 400 #800

class ModelVector(object):

    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return '({0.x}, {0.y}, {0.z})'.format(self)
    
    def __add__(self, other):
        return ModelVector(
            self.x + other.x, self.y + other.y, self.z + other.z)

class ModelMain(object):
    DDY = -365
    def __init__(self):
        self.ddy = self.DDY
        
    def export(self, filename, row_index, point_values):
        x, y, z = point_values
        
        with open(filename, 'a') as out_file:
            out_file.write('$Erstellt durch COG-Tool am: {0}\n'.format(
                    time.strftime('%d.%m.%Y %H:%M:%S')))

            
            hdpa_points = self.hdpa_berechnen(ModelVector(x, y, z), self.ddy)
            self.hdpa_ausgabe(
                ModelVector(x, self.ddy, z),
                row_index, #self.sitzreihe
                row_index, #self.i,
                hdpa_points,
                out_file)
            
            out_file.write('ENDDATA\n') 

    def hdpa_berechnen(self, point, ddy):
        return [
            point + ModelVector(126 - 82, ddy, 594 - 58),
            point + ModelVector(147 + 82, ddy, 594 - 52),
            point + ModelVector(126 - 82, ddy, 693 + 82),
            point + ModelVector(147 + 82, ddy, 693 + 82)]


    def hdpa_ausgabe(self, h_point, sitzreihe, i_start, node_points, out_file):
        print("Hier bricht meine Unterstützung ab!")
        return
        
        out_file.write(
            '$H-Punkt: {0}\n'
            '$HDPA-Feld fuer die {1}. Sitzreihe:\n'.format(h_point, sitzreihe)
        )
        i = None
        for i, point in enumerate(node_points, i_start):
            out_file.write(
                'NODE  / 1000000{0}{1.x:16.6f}{1.y:16.6f}{1.z:16.6f}\n'.format(
                    i, point
                )
            )
    
        indices = [0, 1, 3, 2]
        print("Check:", len(indices), i)
        if len(indices) != i:
            raise ValueError(
                'wrong number of node points ({} != {})'.format(len(indices), i)
            )
        out_file.write(
            'SHELL / 1000000{0}       11000000{1}        \n'
            'PART  / 1000000{0}SHELL          1                        \n'
            'NAMEDefault HDPA_Feld_{0}.Sitzreihe\n'
            '                    \n'
            '                              \n'
            '        1.    3               \n\n'
            'END_PART\n'.format(
                sitzreihe,
                '1000000'.join(str(i_start + j) for j in indices),
            )
        )
        
class GuiSeatRow(tk.Frame):
    ROW_NR_FONT = "Helvetica 22 bold"
    
    def __init__(self, gui, row):
        self.gui = gui
        self.row = row
        
        self.build()
        
    def build(self):
        tk.Frame.__init__(self, self.gui.main_frame)
        
        self.row_var = tk.IntVar(self.gui.app.main_win, self.row+1)
        tk.Label(self, textvariable= self.row_var, bg='blue',
            fg='white', font=self.ROW_NR_FONT, width=2
            ).pack(pady=(5, 10))
        
        self.box = tk.IntVar(self.gui.app.main_win, False)
        tk.Checkbutton(self, text="HDPA Feld", variable=self.box
            ).pack()        
 
        self.hdpa = tk.Label(self, text="H-Punkt WS50%")
        self.hdpa.pack(pady=5)
      
        entry_frame = tk.Frame(self)
        entry_frame.pack(pady=5)
        
        label_frame = tk.LabelFrame(entry_frame, text="X:", relief='flat')
        label_frame.pack(side='left')
        self.hx_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hx_var).pack()
        
        label_frame = tk.LabelFrame(entry_frame, text="Z:", relief='flat')
        label_frame.pack(side='left')
        self.hz_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.hz_var).pack()
 
        label_text = "Y-Abstand:\nCOG/H-Punkt zu Airbag"
        label_frame = tk.LabelFrame(self, text=label_text,
            relief='flat')
        label_frame.pack(anchor='w', pady=5)
        self.dy_var = tk.StringVar(self.gui.app.main_win, 0)
        tk.Entry(label_frame, textvariable=self.dy_var).pack() 

        tk.Button(self, text="Export", command=partial(
            self.gui.export, self.row)).pack(pady=5)

        
class GuiMain(object):
    NOTEBOOK_TAB_FONT = ("Helvetica", 12, "bold")
    ANZAHL_SITZREIHEN = 5
    
    def __init__(self, app):
        self.app = app
        
        self.seat_rows = list()
        
        self.build()
        
        for row in range(self.ANZAHL_SITZREIHEN):
            seat_row = GuiSeatRow(self, row)
            seat_row.pack()
            self.note_book.add(seat_row, text="Sitzreihe-{}".format(row+1),
                sticky='nw', padding=10)
            self.seat_rows.append(seat_row)
        
    def build(self):
        self.main_frame = tk.Frame(self.app.main_win)
        self.main_frame.pack(fill='both', expand=True, padx=5, pady=5)

        self.note_book = ttk.Notebook(self.main_frame)
        self.note_book.pack(fill='both', expand=True)

    def file_dialog(self):
        filename = tkFileDialog.asksaveasfilename(
            initialdir=os.getcwd(),
            title='Speichern der Include-Datei',
            filetypes=(('all files', '*.*'), ('inc files', '*.inc')))
        return filename
            
        
    def export(self, row_index):
        if self.seat_rows[row_index].box.get():
            hx_var = self.seat_rows[row_index].hx_var
            dy_var = self.seat_rows[row_index].dy_var
            hz_var = self.seat_rows[row_index].hz_var
                       
            self.app.export(row_index, (float(entry_var.get()) 
                for entry_var in [hx_var, dy_var, hz_var]))
        else:
            print("Kein HDPA-Feld")
            print(self.seat_rows[row_index].hx_var.get())
     
class App(object):

    def __init__(self, main_win):
        self.main_win = main_win
        self.main_win.protocol("WM_DELETE_WINDOW", self.close)
        
        self.model = ModelMain()
        self.gui = GuiMain(self)
            
    def export(self, row_index, point_values):
        filename = self.gui.file_dialog()
        if filename != ():
            self.model.export(filename, row_index, point_values)
        else:
            print("Filedialog wurde abgebrochen")
                
    def close(self):
        print("Application-Shutdown")
        self.main_win.withdraw()
        self.main_win.destroy()
        
               
def main():
    main_win = tk.Tk()
    main_win.title(APP_TITLE)
    #main_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    main_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    main_win.option_add("*highlightThickness", 0)
    ttk_style = ttk.Style()
    ttk_style.configure('TNotebook.Tab', font="Helvetica 10 bold",
        foreground='blue', background='gray75')
    
    app = App(main_win)
    
    main_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Gruss wuf ;-)

Ich habe leider das tkk Modul nicht. Das ist, wenn ich das richtig gelesen habe, nicht standardmäßig dabei. Oder gibt es dafür noch andere Schreibweisen? Daher hat der Code so bei mir leider auch nicht funktioniert. Ich konnte mir da aber trotzdem noch einige nützliche Dinge rausziehen.

Und nochmal Vielen Dank an euch alle. Hat mir sehr geholfen.
Habe immer noch nicht alles so richtig verstanden, aber mein Code ist jetzt um einiges besser geworden. Da das Programm laut Kunden voraussichtlich nur sehr wenig oder gar nicht erweitert wird, ist das so in Ordnung, wenn er nicht 100% perfekt ist. Leider könnte das zeitlich recht eng werden, wenn ich noch mehr Zeit investiere. Wichtig ist, dass ich einige Variablen Global definiere, die dann die Berechnungen beeinflussen und man das Programm so ggf. flexibel justieren kann. Und für meine Dummy Klassen werde ich ein extra Modul schreiben, falls noch einer hinzugefügt werden soll. Ansonsten wird im Programm nichts verändert werden.
Marvin75854

Eine Frage habe ich aber noch. Ist es möglich mit einer If-Abfrage zu testen ob eine bestimmte Funktion im Programm schon ausgeführt worden ist? Ich will über einen Button einen subprocess einbauen und Vorraussetzung dafür ist, dass vorher eine bestimmte Funktion bereits eine Datei rausgeschrieben hat. Das heißt, dass wenn die Funktion noch nicht ausgeführt wurde, soll diese automatisch ausgeführt werden, eine Datei rausschreiben und danach direkt der subprocess.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Man testet, ob eine Funktion schon ausgeführt worden ist, indem man ein Variable nach der Ausführung setzt und diese beim nächsten Mal abfrägt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du so etwas willst, dann musst du das programmieren. Indem du dir in einer Variable merkst, ob etwas passiert ist. Oder noch besser, indem du es pruefst, ob die gewuenschte Datei existiert. Denn dann kann es nicht passieren, dass du *denkst* du hast die Datei geschrieben, weil du die Variable gesetzt (oder nicht zurueck-gesetzt) hast, ohne das die Realitaet damit uebereinstimmt.
Marvin75854

Ja so ähnlich habe ich es schon, dachte nur es gibt da vielleicht eine bessere Möglichkeit.


Ist es möglich eine Klasse über eine Variable aufzurufen? Weiß nicht wie ich das beschreiben soll. Hier mal ein kurzes Beispiel:

Code: Alles auswählen


Dummy_1 = StringVar(self)
Dummy_1.set("H395")
popupMenuD1 = OptionMenu(GUI, Dummy_1, *choicesD)
popupMenuD1.grid(row=3, column=6, padx = 20)

        

x = Dummy_1(...)
x.calc()

class H395:
    def __init__(...):
        ...
    def calc(self):
        ...

class WS50:
... 

class...:
...
Also ich habe einige Klassen und will jetzt über ein Dropdownmenü einen Dummy auswählen und automatisch die entsprechende Klasse erstellt wird. Also den Namen der Klasse über die Variable "Dummy_1" aufrufe. In meinem Programm sind die Klassen und das OptionMenu noch in verschiedenen Modulen. Das Ziel ist, dass es möglich ist zu einem späteren Zeitpunkt eine Klasse hinzuzufügen ohne viel im Programm ändern zu müssen. Ich müsste dann ja nur "choicesD" noch anpassen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dazu benutzt man ein Wörterbuch. Das bildet Optionen auf Klassen oder Funktionen ab. Wenn eine neue Klasse dazu kommt, dann muss die nur in das Wörterbuch eingetragen werden. Und um die Reihenfolge zu definieren, benutzt man ein OrderedDict.
Antworten