Gui Designer auf GitHub

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Danke, dass Du mir das mit dem asymmetrischen paddding schreibst, wollte nämlich schon Spinboxen statt Entries machen für folgende Einträge:

Code: Alles auswählen

Spinbox instead of Entry for Integers and Floats in Config Options and Layout Options:

Integers ind Floats in Config Options:

"from", # Spinbox (decimal default 0.0)
"to",   # Spinbox, Scale (decimal Spinbox default 0,0, Scale default 100.0)
"increment", # Spinbox, (decimal default 1.0)
"resolution", # Scale (decimal default 1.0)
"bigincrement", # Scale (decimal default 0.0)
"tickinterval", # Scale (decimal default 0.0)
"digits", # Scale (Integer default 0)
"underline", # Label, Button (Integer starting at -1)
"width", # often (Integer default 0)
"height", # often (Integer default 0)
"length", # Spinbox (Integer default 100)
"sliderlength", # Spinbox (Integer default 30)
"wraplength", # often (Integer default 0)
"padx", # often (Label: Integer default 0, Button ? default 3m)
"pady", # often (Label: Integer default 0, Button ? default 1m)
"bd", # often (Integer default 1)
"insertwidth", # Entry (Integer default 2)
"insertborderwidth", # Entry (Integer default 0)
"insertontime", # Entry (Integer default 600)
"selectborderwidth", # Entry (Integer default 0)
"sashwidth", # PanedWindow (Integer default 3)
"sashpad", # PanedWindow (Integer default 0)
"opaqueresize", # PanedWindow (Integer default 1)
"handlesize", # PanedWindow (Integer default 8)
"handlepad", # PanedWindow (Integer default 8)

Integers in Layout Options:

"x", # Place Layout
"y", # Place Layout
"column", # Grid Layout
"row", # Grid Layout
"columnspan", # Grid Layout (Integer default 1)
"rowspan", # Grid Layout (Integer default 1)
"width", # Place Layout (Default leer "" oder Integer)
"height", # Place Layout (Default leer "" oder Integer)
"expand", # Pack Layout (Integer default 0)
"padx", # Pack Layout und Grid Layout (Integer default 0)
"pady", # Pack Layout und Grid Layout (Integer default 0)
"ipadx", # Pack Layout und Grid Layout (Integer default 0)
"ipady", # Pack Layout und Grid Layout (Integer default 0)
"relx", # Place Layout (Integer default 0)
"rely", # Place Layout (Integer default 0)
"relwidth", # Place Layout (Default leer "" oder Integer)
"relheight",  # Place Layout (Default leer "" oder Integer)
Muss mir dazu noch überlegen: from, to, increment
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

wuf hat geschrieben:Hi Alfons
Noch ein kleiner Tipp betreffs den Layout Options padx und pady. Dies betrifft also nur die padx und pady, welche als Layout Options verwendet werden! Nebst dem symetrischen padding kann auch ein asymetrisches definiert werden.
Hi wuf. Hab gesehen, dass man das eingeben kann. Einfach zwei Werte mit Leerzeichen dazwischen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Alfons
Alfons Mittelmeyer hat geschrieben:Hi wuf. Hab gesehen, dass man das eingeben kann. Einfach zwei Werte mit Leerzeichen dazwischen.
Super! Funktioniert bestens. Habe zu wenig Varianten ausprobiert. Noch eine Frage. Bei der configuration von z.B. dem root-Fenster oder Frame verwendest du die Option link diese aber nicht bei z.B. Labels, Entries oder Checkboxes. Ich dachte zuerst es sei der Referenzname für die Instanz dieser Widgets die du dann in den Skripts verwendest um diese GUI-Widgets anzusprechen. Dann aber müsste die Option link aber doch für alle Widgets verfügbar sein?

Gruss wuf :wink:
Take it easy Mates!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Nein, die Option 'link' gibt es nur für Container Widgets und sie bedeutet etwas völlig Anderes. Was denkst Du, was hier im Script Modules.py bassiert?

Code: Alles auswählen

Frame('CreateFrame',link="guidesigner/CreateFrame.py")
grid(sticky='n',row='0')

Frame('CreateAndLayout',link="guidesigner/CreateAndLayout.py")
grid(column='1',sticky='n',row='0')

LabelFrame("ConfigOptions",text="Config",link="guidesigner/ConfigOptions.py")
rcgrid(0,2,sticky=N)

Frame("DetailedLayout",link="guidesigner/DetailedLayout.py")
rcgrid(0,3,sticky=N)

LabelFrame("Selection",text="Selection",link="guidesigner/Selection.py")
rcgrid(0,4,sticky=N)

### CODE ===================================================

widget("ConfigOptions").unlayout()
widget("DetailedLayout").unlayout()

### ========================================================
Die Option 'link' lädt diese Scripts nach, füllt also den Inhalt der Frames und so lade ich den kompletten GUI Designer. - Sozusagen Script Import als Widget Option :wink:

Ich sollte dann auch die andere Save Routine - eigentlich dieselbe - wieder mit hineinnehmen - mit der man die Scripts zerteilen kann. Nur hatte die automatisch beim Speichern den Link gesetzt. Und dann war alles doppelt. Muss das automatische Link setzen herausnehmen sowohl beim Laden als auch beim Speichern. Soll man händisch machen.

Das Problem ist, wenn ein Script Links enthält, wird dann alles geladen und man soll die Widgets nicht speichern oder wird ein Teil der Widgets geladen? Aber welche soll man dann speichern?
Nö da habe ich noch einen Denkfehler drin, denn wenn man nur Inhalt des Containers nachlädt, dann gehören die Widgets ja nur zum Subcontainer und das Problem besteht nicht. Hatte nur gestern statt einen Container Inhalt den Container gespeichert. Und beim Reinladen war es dann doppelt.

Ist eigentlich lustig, wenn man etwa ein Menü entwirft und hat aber auch noch Anderes, dass man dann speziell nur das Menü speichert. Und das ist dann durch den Link abgetrennt in einer eigenen Datei.

Man sollte aber da noch die Entscheidung einbauen, nur diesen Teil speichern oder gleich dabei mit abtrennen.

Und bei den Expert Laderoutinen, die ich vorläufig herausgenommen habe, kann man dann auch gezielt Teile hereinladen. Das kann man aber auch, wenn man den Link manuell setzt. Allerdings speichere ich zur Zeit die Links nicht in der Nicht-Expert Save Funktion, sondern speichere alle Widgets.

Die Expert Save Funktion dagegen darf dann den betreffenden Subcontainer Inhalt nicht speichern, sondern nur einfach den Link. Dabei ist aber dumm, wenn jemand darin etwas geändert hat und von Anfang an speichert und sich dann wundert, wenn seine Änderungen nicht gespeichert wurden. Da hätte er den Container Inhalt extra noch speichern müssen.

Ohne Dokumentation sollte man diese Funktionen daher nicht anbieten, weil dann einer nicht weiss, was passiert und zerschießt sich vielleicht etwas und ärgert sich dann.

Manuell lange Scripts im Editor zerteilen macht aber auch keinen Spass. Mit der Save Funktion, die automatisch den Link setzt, geschieht es Ruck Zuck.
Zuletzt geändert von Alfons Mittelmeyer am Mittwoch 30. September 2015, 09:07, insgesamt 2-mal geändert.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Alfons

Danke! Sorry jetzt hat es gedämmert. Du vergibst die Referenznamen ja beim erstellen der Widgets im Feld Create Widget in der Eingabe für Namen

Gruss wuf :wink:
Take it easy Mates!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Ja, der erste Parameter ist der Widgetname, da wo normalerweise der Parent steht. DynTkInter kann aber auch den Parent Parameter als Parent behandeln und ist daher kompatibel mit tkinter Scripts.
Der Gui Designer kann allerdings noch keine tkinter Panels und Menüs erfassen. Da muss ich erst noch die betreffenden tkinter Methoden ergänzen..
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Bräuchte noch eine Lösung für padx und padx in den Config Options. Schön wäre auch da eine Spinbox. Nur da gibt es die Angabe in Pixel und Millimeter und wenn ich eine Spinbox nehme ist das 'm' weg.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Alfons

Hier habe ich etwas zusammengebastelt. Schau es dir einmal an:

Code: Alles auswählen

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

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
    import tkFont as fnt
except:
    # Tkinter for Python 3.xx
    import tkinter as tk
    import tkinter.font as fnt

APP_TITLE = "Dimension-Creator"
APP_BACK_GND = "#d1d19d"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200

DIMENSIONS = ('pixel', 'centimeter', 'inches', 'millimeter')
MIN_VAL = 0
MAX_VAL = 20

class DimensionValueCreator(tk.Spinbox):
    
    def __init__(self, parent, min_val, max_val, callback=None, **options):
        self.parent = parent
        self.min_val = min_val
        self.max_val = max_val
        self.value = 0
        self.unit = DIMENSIONS[0]
        self.callback = callback

        self.var = tk.StringVar()
        self.var.trace_variable('w', self.update_value)
        
        tk.Spinbox.__init__(self, parent, from_=min_val, to_=max_val,
            textvariable=self.var, **options)
        
    def set_value(self, value=0):
        if self.min_val <= value <= self.max_val:
            self.var.set('{} {}'.format(value, self.unit))
            self.value = value
    
    def set_unit(self, unit=''):
        if unit in DIMENSIONS:
            value = self.get_value_only()
            self.change_unit(unit)
            self.set_value(value)
            
    def get_value_only(self):
        mixed_value = self.get()
        value = int(mixed_value.replace(self.unit, ''))
        return value
                
    def change_unit(self, new_unit=''):
        old_unit = self.unit
        old_dim_value = self.var.get()

        new_dim_value = old_dim_value.replace(old_unit, new_unit)
        value = new_dim_value.replace(new_unit, '')
        self.unit = new_unit
                
    def update_value(self, *args):
        mixed_value = self.get()
        self.value = self.get_value_only()
        try:
            self.var.set('{} {}'.format(self.var.get(), self.unit))
        except AttributeError:
            return False
        else:
            self.creator_callback()
            return True        

    def creator_callback(self):
        if self.callback != None:
            self.callback(self.unit, self.value)
            
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        self.master.protocol("WM_DELETE_WINDOW", self.close)
        tk.Frame.__init__(self, master)

        dim_value_frame = tk.LabelFrame(self, text="Dimension-Value")
        dim_value_frame.pack(expand=True)
        
        self.dimension_value_creator = DimensionValueCreator(dim_value_frame,
            MIN_VAL, MAX_VAL, callback=self.creator_callback, width=10,
                bg='khaki1')
        self.dimension_value_creator.pack(padx=4, pady=4)
        
        unit_frame = tk.LabelFrame(self, text="Test-Unit (Dimensions)")
        unit_frame.pack(expand=True)
        
        self.unit_spinbox = tk.Spinbox(unit_frame, values=DIMENSIONS,
            command=self.update_unit)
        self.unit_spinbox.pack(padx=4, pady=4)

        value_frame = tk.LabelFrame(self, text="Test-Value (padx & pady)")
        value_frame.pack(expand=True)

        self.value_spinbox = tk.Spinbox(value_frame, from_=0, to_=100,
            command=self.update_value)
        self.value_spinbox.pack(padx=4, pady=4)
    
    def creator_callback(self, unit, value):
        print(unit, value)
        
    def update_unit(self):
        unit = self.unit_spinbox.get()
        self.dimension_value_creator.set_unit(unit)
        
    def update_value(self):
        value = int(self.value_spinbox.get())
        self.dimension_value_creator.set_value(value)
        
    def close(self):
        print("Application-Shutdown")
        self.master.destroy()
    
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True, padx=6, pady=6)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
N.B. Kann sicher noch optimiert werden.

Gruss wuf :wink:
Take it easy Mates!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Danke, hast Dir da aber grosse Mühe gegeben. Ich habe mich heute mal mit dem Grid Konzept beschäftigt. Und zwar in Form einer sichtbaren Tabelle. Und man kann dann die Widgets einfach mit der Maus ziehen. Das sieht super aus. Zuvor muss ich allerdings noch ein wenig Konzeptänderung machen. Das Konzept bisher beim Place Layout war, dass man das Bewegen mit der Maus für einzelne Widgets ein und ausgeschaltet hatte.

Ich hatte gedacht, wenn jemand bereits Events drauf hat, sollte man sie nicht zerstören. Aber dieses Konzept muss jetzt geändert werden. Selektion mit der Maus und eventuell auch noch bewegen für alle Widgets im betreffenden Container, ob nun Pack oder Grid oder Place oder Pane - aber nicht bei Menüs, weil das dort nicht geht.

Dann kann man beliebig Widgets selektieren oder gar mit der Maus bei grid oder place verschieben.
Naja, das mit einer schönen Grid Implementierung gibt es bisher nirgends.

Ach übrigends habe ich heute bei Github die Änderung draufgespielt, dass es bei Zahlenwerten - bis auf wenige Ausnahmen - jetzt Spinboxen gibt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Habe mir heute das neue Grid ausgedacht. Sollte nicht schwer zu verstehen sein:

Bild
Antworten