Problem: beim 2. Sash nimmt tkinter die Koordinaten nicht

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

Hab das mit dem GUI Desgner erstellt. Und ging auch alles. Hab es abgespeichert und wieder geladen.
Doch da wurden die Koordinaten des zweiten Sashes nicht eingestellt.

Hab es auf tkinter Syntax umgeschrieben. Auch da ging es nicht. Hab es mit time.sleep, pack bereits vorher probiert, auch mit Laden nach mainloop.
Aber alles ohne Erfolg. Komm einfach nicht drauf, woran es liegen könnte:

Code: Alles auswählen

import tkinter as tk

root = tk.Tk()

paned_window = tk.PanedWindow(root,sashrelief='raised',handlepad='40',sashwidth='8',handlesize='20',showhandle='1',height='200',width='300')

paned_window.add(tk.Label(paned_window,text="Label 1"))
paned_window.add(tk.Label(paned_window,text="Label 2"))
paned_window.add(tk.Label(paned_window,text="Label 3"))
paned_window.sash_place(0,100,1)
paned_window.sash_place(1,200,1)

paned_window.pack()

print(paned_window.sash_coord(0)) # this is correct
print(paned_window.sash_coord(1)) # I get 186 instead of 200 with one computer with the other one I get 171

root.mainloop()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Hab die Lösung gefunden.

Den zweiten Sash erst nach der Mainloop platzieren und zwischen erstem und zweitem Sash eine Pause machen:

Code: Alles auswählen

import tkinter as tk

root = tk.Tk()

paned_window = tk.PanedWindow(root,sashrelief='raised',handlepad='40',sashwidth='8',handlesize='20',showhandle='1',height='200',width='300')

paned_window.add(tk.Label(paned_window,text="Label 1"))
paned_window.add(tk.Label(paned_window,text="Label 2"))
paned_window.add(tk.Label(paned_window,text="Label 3"))
paned_window.sash_place(0,100,1)

paned_window.pack()

def set_sashes():
	paned_window.sash_place(1,200,1)

	print(paned_window.sash_coord(0)) # this is correct
	print(paned_window.sash_coord(1)) # I get 186 instead of 200 with one computer with the other one I get 171

root.after(100,set_sashes)

root.mainloop()
Also am Besten solche Scripte innerhalb mainloop laden mit einer Pause mittels after zwischen den Sash Platzierungen.

Muss mir nur noch überlegen, wie man das Script Einlesen zum Stoppen bringt, bis es nach after weiter geladen wird. Aber da müßte man dann wohl auf eine Funktion main() außen drum rum verzichten. Denn eine after Pause innerhalb einer Funktion geht wohl kaum.

Man könnte es ja so machen, dass man per after eine Funktion aufruft, die erst nachdem mainloop gestartet ist, das Script zeilenweise einliest bis eine Pausenmarkierung kommt, dann das vor der Pausenmarkierung ausführt und wartet. Und danach geht es weiter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Also, was meint Ihr? So schaut zur Zeit der DynTkInter Code aus für dieses Beispiel:

Code: Alles auswählen

def main(parent=None):

    config(title='tk')
    Button('Button',text="""Button""")
    PanedWindow('PanedWindow',sashrelief='raised',handlepad='40',sashwidth='8',handlesize='20',showhandle='1',height='200',width='300')
    goIn()

    Label('Label 1',text="""Label 1""")
    Label('Label 3',text="""Label 3""")
    Label('Label 2',text="""Label 2""")

    widget('Label 1').pane()
    widget('Label 2').pane()
    widget('Label 3').pane()
    container().sash_place(0,100,1)
    container().sash_place(1,200,1)

    goOut()

    widget('Button').pack()
    widget('PanedWindow').pack()
Wenn ich das aber mit main wieder herausnehme, könnte ich auch schreiben:

Code: Alles auswählen

config(title='tk')
Button('Button',text="""Button""")
PanedWindow('PanedWindow',sashrelief='raised',handlepad='40',sashwidth='8',handlesize='20',showhandle='1',height='200',width='300')
goIn()

Label('Label 1',text="""Label 1""")
Label('Label 3',text="""Label 3""")
Label('Label 2',text="""Label 2""")

widget('Label 1').pane()
widget('Label 2').pane()
widget('Label 3').pane()

container().sash_place(0,100,1)

### PAUSE 100 

container().sash_place(1,200,1)

goOut()

widget('Button').pack()
widget('PanedWindow').pack()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Hab jetzt das Main Script für DynTkInter Scripts geändert. Das Script wird dann erst innerhalb der Mainloop geladen:

Code: Alles auswählen

import DynTkInter as tk
 
tk.Tk().mainloop("guidesigner/Guidesigner.py")
Jetzt muss ich nur noch das mit der Pause hinbringen.

Aber das mit der Pause ist ein Problem bei rekursivem Nachladen von Scripts. Da darf das eine Script das nachgeladen wird, nicht sagen, es ist fertig, obwohl es nur pausiert. Da bräuchte man dann wohl so etwas wie einen Filehandlestack. Wenn das eine Script fertig nachgeladen ist, wird das vorherige Filehandle wieder abgehoben, damit es dann erst da wieder weitergeht.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Alfons

Es ist so wie du sagst. Die Handles können erst nach dem Start der Mainloop patziert werden. Hier ein Skript mit Platzierung durch aktivieren von Buttons:

Code: Alles auswählen

#!/usr/bin/env python
# coding: UTF-8

from functools import partial
try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

def place_pane_handle(sash_index, xpos):
    paned_window.sash_place(sash_index, xpos, 1)
    coords = paned_window.sash_coord(sash_index)
    label3_var.set("Hadle-{} Coords: {}".format(sash_index, coords)) 
         
root = tk.Tk()
 
paned_window = tk.PanedWindow(root, sashrelief='raised', handlepad='40',
    sashwidth='8', handlesize='20', showhandle='1', height='200', width='400',
    bd=10)

label3_var = tk.StringVar()
label3_var.set("Label 3") 
paned_window.add(tk.Label(paned_window, text="Label 1"))
paned_window.add(tk.Label(paned_window, text="Label 2"))
paned_window.add(tk.Label(paned_window, textvariable=label3_var))
 
paned_window.pack(expand=True)

button_frame = tk.Frame(root)
button_frame.pack(padx=5, pady=10)
 
tk.Button(button_frame, text='Place Handle-0 to 100', command=partial(
    place_pane_handle, 0, 100)
    ).pack(side='left')
    
tk.Button(button_frame, text='Place Handle-1 to 200', command=partial(
    place_pane_handle, 1, 200)
    ).pack(side='left')
 
root.mainloop()
und hier ein Skript mit Platzierung mittels der Verzögerung root.after(...:

Code: Alles auswählen

#!/usr/bin/env python
# coding: UTF-8

from functools import partial
try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

def place_pane_handle(sash_index, xpos):
    paned_window.sash_place(sash_index, xpos, 1)
    coords = paned_window.sash_coord(sash_index)
    label3_var.set("Hadle-{} Coords: {}".format(sash_index, coords)) 

def positioning_the_handles():
    place_pane_handle(0, 100)
    place_pane_handle(1, 200)
    
root = tk.Tk()
 
paned_window = tk.PanedWindow(root, sashrelief='raised', handlepad='40',
    sashwidth='8', handlesize='20', showhandle='1', height='200', width='400',
    bd=10)

label3_var = tk.StringVar()
label3_var.set("Label 3") 
paned_window.add(tk.Label(paned_window, text="Label 1"))
paned_window.add(tk.Label(paned_window, text="Label 2"))
paned_window.add(tk.Label(paned_window, textvariable=label3_var))
 
paned_window.pack(expand=True)

root.after(50, positioning_the_handles)
 
root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf Ja, darüber hatte ich auch nachgedacht. Und eine Lösung mit Einlesen pausieren ist nicht machbar, da man zwar mit dem Einlesen anhalten könnte, nicht aber mit der Ausführung.

Und mir ist dann folgende Lösung eingefallen:

Code: Alles auswählen

# statt
paned_window.sash_place(0,100,1)
paned_window.sash_place(1,200,1)

# ein after triggern mit:
paned_window.trigger_sash_place(0,100,1)
paned_window.trigger_sash_place(1,200,1)
Da würde man bei der PanedWindow Klasse einfach eine Variable für die after Zeit haben, die bei jeder Sash Platzierung um einen Zeitstep (wieviel Millisekunden weiss ich jetzt nicht) hochgezählt wird.

Vielleicht wäre es auch besser, die trigger_sash_place Methode beim Generieren mit der Zeit zu versehen, dann kann sich jeder selbst aussuchen, ob er das Script erst innerhalb der Mainloop laufen lassen will oder normal und kann die Zeiten dann an seine Umgebung und sein System anpassen. Ich mache es vielleicht dann so zum Anpassen:

Code: Alles auswählen

paned_window.trigger_sash_place(50,0,100,1)
paned_window.trigger_sash_place(100,1,200,1)
Später für tkinter, das dann nicht mit erweiterten Klassen und zusätzlichen Methoden arbeitet, müsste man die Widget Referenz in die Funktion mit reinnehmen.


wuf, und es reicht nicht die sashes einfach nur in der mainloop zu platzieren, das hatte ich nämlich getan, als ich das mit dem GUI Designer geladen hatte. Zwischen den einzelnen sash Platzierungen braucht es auch noch eine Pause, sonst tut es tkinter auch nicht.

Ich denke, es ist so, dass sash Platzierungen Zeit kosten und tkinter sie relativ zur vorherigen macht. Die erste geht immer. Nur muß man dann warten, bis diese tatsächlich dann auch vollständig ausgeführt wurde - und das kostet etwas Zeit. Und erst danach darf man die nachfolgende ausführen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Hab es geschafft. Das Script sieht jetzt so aus:

Code: Alles auswählen

PanedWindow('PanedWindow',sashrelief='raised',handlepad='40',sashwidth='8',handlesize='20',showhandle='1',height='200',width='300')
goIn()

Label('Label 1',text="""Label 1""")
Label('Label 3',text="""Label 3""")
Label('Label 2',text="""Label 2""")

widget('Label 1').pane()
widget('Label 2').pane()
widget('Label 3').pane()
container().trigger_sash_place(0,0,100,1)
container().trigger_sash_place(100,1,200,1)

goOut()

widget('PanedWindow').pack()
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf PanedWindow ist drin. Die Laderoutinen stimmen wieder mit der Speicherroutine überein. Auch Listboxeinträge lassen sich sichern. Scripts können auch nach Mainloop Start geladen werden. Fehler beim save Menü beseitigt. Hab allerdings recht viele Änderungen drin, etwa die Funktion main() herausgenommen. Da passierte es dann an einigen Stellen, dass Funktionsnamen nicht mehr bekannt waren mit Programmabbruch. Hab es aber wieder berichtigt. Völlig durchgetestet habe ich es jetzt noch nicht, ob nicht doch noch irgendwo ein Bug sein könnte.

Also neue Version mit PanedWindow Behandlung auf: https://github.com/AlfonsMittelmeyer/py ... -messaging
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Alfons: Du hast ja immer noch die Zip-Datei im Repo drin. Das ist unnötig. Schau mal auf der Einstiegsseite deines Repos in die Spalte rechts neben den Repo-Inhalten. Da ist relativ weit unten ein Button, durch den man automatisch das Repo als Zip-Datei herunterladen kann. Du musst also nicht ständig dein Zip-Archiv aktualisieren, sondern diese Funktion bringt Github schon von sich aus mit.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@snafu Danke, für die Info. Werfe ich dann das nächste Mal raus.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Alfons

Habe die neuste Version deines DynTkinter GuiDesigners heruntergeladen. Im zip-Archiv fehlte noch die proxy.py Datei. Habe diese aus deiner früheren Version übernommen. Probierte dein neu erstelltes Auswahl-Widget PanedWindow aus. Ich fügte dem Widget drei Labels horizontal hinzu. Diese Labels befanden sich dann auf dem PanedWindow. An den vertikalen Trennstellen der Labels fehlten aber die ziehbaren Handles und Sashes. Ich speicherte meinen Testentwurf ab und aktivierte nach einem Neustart des GuiDesigners den Button load & run. Aber das Resultat war das gleiche. Ok eventuell ist das beim jetzigen Stand deines Projektes noch nich möglich.

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

@wuf Hab gesehen, dass die proxy Datei im Archiv nicht aktualisiert wurde. Aber wichtig ist es, gerade hier die richtige Version zu haben und nicht eine frühere. Wenn Du meine GuiDesigner.zip lädst, da ist sie drin. Heute werden dann wahrscheinlich noch Menu und Menubutton kommen. Muss noch den Menubutton machen und die Speicherroutine.

Komisch, mein Git Archiv auf dem Rechner zeigt an, dass die Datei committed wurde und aktualisiert. Auf Github ist es aber noch die frühere Version.

Weiss nicht, wie ich das lösen soll, wenn Github eine frühere Versio drauf hat, obwohl ich die richtige gepush hatte. Wie bringe ich die Archive wieder zur Übereinstimmung?
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@wuf das mit proxy.py war Fehlalarm. Hab ich jetzt versehentlich auf github gelöscht. Damit Du die sashes siehst, musst Du beim PanedWindow sashrelief ungleich flat stellen und bei den handles musst Du showhandle auf 1 stellen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Alfons

Super! Mit der letzten Version von GitHub heruntergeladen funktioniert es wie du es vorgeschlagen hast. Die Handles & Sashes werden jetzt sichtbar. Hier einige Bilder meines Tests.

Auf dem Designer:
Bild

Im Gui-Fenster:
Bild

Meine Feststellung ist. Im Designer-Fenster unter selection werden die Labelnamen nicht in der Reihenfolge angezeigt wie ich sie dem PanedWindow hinzugefügt habe. Da weisst du sicher besser was der Grund hierfür sein könnte.

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

wuf hat geschrieben:Meine Feststellung ist. Im Designer-Fenster unter selection werden die Labelnamen nicht in der Reihenfolge angezeigt wie ich sie dem PanedWindow hinzugefügt habe. Da weisst du sicher besser was der Grund hierfür sein könnte.Gruss wuf :wink:
Ja wuf, das stimmt allerdings. Über eine Sortierreihenfolge hatte ich noch nicht nachgedacht. Jetzt ist sie rein zufällig aus einem Dictionary heraus:

Code: Alles auswählen

for key,entry in dictionary.items():
Da könnte man auch Sortierungen nehmen, wie alphabetisch, oder eine Nummer für die Reihenfolge der Erfassung hinzufügen. Allerdings, wenn jemand gleiche Namen für verschiedene Einträge verwendet, dann würde ich das ungerne nach Eintragsreihenfolge splitten. Eine Sortierng nach Eintragsreihenfolge für den Namen wäre bestimmt nicht verkehrt und "rename" sollte darauf keine Auswirkung haben. Könnte man mal realisieren.
Die Einträge sehen jetzt so aus bei Berücksichtigung gleicher Namen:

Code: Alles auswählen

{
...
Name:[widget1,widget2,wiget3]
...
}
Man könnte ja dann noch eine Nummer reinlegen und nach der sortieren, etwa:

Code: Alles auswählen

{
...
Name:[Nummer,[widget1,widget2,wiget3]]
...
}
Antworten