string zu no string konvertieren ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

smashed to pieces hat geschrieben:Das mit dem mainloopen versteh ich jetzt allerdings nicht mehr. Weil ich brauch doch eine mainloop Anwendung damit sich das Fenster erst einmal oeffnet/zeigt. Wenn man dann nicht mehr das Ausstehn aendern kann ist das doch irgendwie falsch, da sich andauernt graphische Oberflaechen bei Programmen veraendern.
Ich wiederhole meinen Lektüre-Tipp von oben. Nimm dir mal 1-2 Tage Zeit dafür, gib die Beispiele ein, experimentiere damit. Das Layout dieser Anleitung ist zwar übel, aber wenn man es ausdruckt, geht es.
Das wird dir manche Erleuchtung bescheren.
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Danke, konnte mein Problem zwar schon loesen, werde mir die Lektuere aber mal genauer anschaun.

Wollt jetzt nur noch einmal fragen, in wie fern es schlecht es ist, global zu verwendet? Also in meinem jetzigem Code wuerde ich beispielsweise das Woerterbuch zum globalen Namensraum hinzufuegen, welches angibt welche Farbe ein bestimmter 'Stein' momentan hat.
Ist es in so einem Fall gerechtfertigt global zu benuetzen oder sollte man die Verwendung allgemein vermeiden, und wenn ja warum?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Das Problem mit "global" ist, dass es bereits bei nicht mehr ganz kleinen Programmen schnell unübersichtlich wird, und sich die Gefahr unerwünschter Seiteneffekte erhöht.

In den meisten Fällen lässt sich "global" dadurch vermeiden, dass man über Parameter und Rückgabewerte Daten austauscht. In den seltenen Fällen, wo mir das zu umständlich erscheint, würde ich "global" nur bei ganz kleinen Programmen einsetzen (etwa so viele Zeilen, wie mein Bildschirm ohne zu scrollen anzeigen kann), bei denen sich m.E. eine OOP-Konstruktion nicht lohnt.

Wenn du mit Klassen und Objekten arbeitest, ist "global" überflüssig, weil du das gleiche über Datenattribute von Objekten erreichen kannst.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Lesend kannst du ohne global drauf zugreifen. Schreibend nur mit global.

Für "Read Only" Konstanten ist der Modul Namespace da, sofern die Konstante nicht direkt mit einer Klasse verbunden werden könnte.

global braucht man in der Regel nicht. GIbt eigentlich nur selten solche Fälle, maximal vielleicht bei notwendiger Verkapselung von Daten in einem Modul, die mittels einer Setter Funktion gesetzt werden sollen. Bevor man sowas macht sollte man sein Design nochmal überdenken. Wenn du es mehr als maximal einmal verwendest, hast du eigentlich immer ein kränkelndes Design.
BlackJack

Und im vorliegenden Beispiel würden die aktuellen Farben auf den Flächen ja in irgendeiner Weise von einem `Würfel`-Objekt gekapselt, welches man als Argument übergeben kann und nicht "global" auf Modulebene bekannt machen muss.
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Also global gilt es, bei etwas größeren Programmen, zu vermeiden.
Sollte möglich sein, danke.

Hab grad bisschen bei Thinking in Tkinter herumgelesen und auch verschiedenes ausprobiert.
Dabei haben sich mir wieder ein paar Fragen gestellt:

Erstens:
Warum definiert der Autor, von Thinking in Tkinter, die root = Tk() und die mainloop-Anweisung immer außerhalb der Klasse und übergibt root dann als Parameter?
Hat das einen Vorteil gegenüber dem, wenn man auch diese Anweisungen mit in die Klasse packt? Bin verunsichert, da ich bei anderen "Anleitungen" diese immer in der Klasse definiert gefunden habe.


Zweitens:

Code: Alles auswählen

button.pack(side=tk.LEFT)
button.pack(side='left')
Funktioniert beides.
Warum stellt Python zwei Möglichkeiten zur verfügung? Ist das nicht sinnlos?
Oder sollte man eine der beiden eh nicht verwenden, da sie in späteren Versionen von Python nicht mehr vorhanden sein wird?


Drittens:
Habe im irgendwo gelesen, dass man Längeneinheiten bei Tkinter auch in Zentimeter, Millimeter und Inch angeben kann.
Das funktioniert bei Canvas auch ausgezeichnet:

Code: Alles auswählen

import Tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width='10c', height='10c')
canvas.pack()
root.mainloop()
Wenn ich das ganze allerdings bei einem Button versuche funktioniert es nicht, obwohl es, laut Beschreibung, für alle Widgets von Tkinter funktionieren sollte:

Code: Alles auswählen

button = tk.Button(root, width='10c', height='10c')
button.pack()

Viertens und Letztens:
Warum braucht mein Computer so lange um die Buttons zu plazieren?
Wenn man sich Minesweeper anschaut funktioniert das ja erheblich schneller :D .
Also was mach ich falsch? :?
Code:

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self, myParent):
        self.myParent=myParent
        
        myContainer1 = tk.Frame(self.myParent)
        myContainer1.pack()
        
        
        self.button = self.buttonDict(width=25)
             
        for i in xrange(25):
            for o in xrange(25):
                self.button[i][o] = tk.Button(myContainer1, width=2, height=1)
                self.button[i][o].grid(row=i, column=o)
 
    
    def buttonDict(self,width):
        button = []
        for i in xrange(1,width*width,width):
            button += [[['button%u' %(i+dummy)] for dummy in xrange(width)]]
        return button


root = tk.Tk()
myapp = MyApp(root)
root.mainloop()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

smashed to pieces hat geschrieben:Warum definiert der Autor, von Thinking in Tkinter, die root = Tk() und die mainloop-Anweisung immer außerhalb der Klasse und übergibt root dann als Parameter?
Hat das einen Vorteil gegenüber dem, wenn man auch diese Anweisungen mit in die Klasse packt? Bin verunsichert, da ich bei anderen "Anleitungen" diese immer in der Klasse definiert gefunden habe.
Das scheint mir ein bisschen Geschmackssache zu sein. Bei Shipman z.B. findet es z.B. wieder ganz anders (http://infohost.nmt.edu/tcc/help/pubs/t ... l-app.html).
smashed to pieces hat geschrieben:

Code: Alles auswählen

button.pack(side=tk.LEFT)
button.pack(side='left')
Funktioniert beides.
Warum stellt Python zwei Möglichkeiten zur verfügung? Ist das nicht sinnlos?
Oder sollte man eine der beiden eh nicht verwenden, da sie in späteren Versionen von Python nicht mehr vorhanden sein wird?
Soweit ich mich erinnere, hat das mit Tk/Tcl zu tun und irgendeiner Abwärtskompatibilität. Nach meiner Einschätzung ist die Variante mit den Konstanten in Großbuchstaben die gebräuchlichere, weil es eher der allgemeinen Konvention im Umgang mit Konstanten entspricht. Es gibt aber mindestens einen Fall (ich glaube, es war irgendein Button-Zustand), wo es NUR mit der String-Variante möglich ist, weil keine entsprechende Konstante existiert.

smashed to pieces hat geschrieben:Habe im irgendwo gelesen, dass man Längeneinheiten bei Tkinter auch in Zentimeter, Millimeter und Inch angeben kann. Das funktioniert bei Canvas auch ausgezeichnet: [...]
Wenn ich das ganze allerdings bei einem Button versuche funktioniert es nicht, obwohl es, laut Beschreibung, für alle Widgets von Tkinter funktionieren sollte:
Bei Buttons, die mit Text (und nicht mit einem Image) belegt werden, gibt width/height die Breite/Höhe in Zeichen an. Da funktioniert das nicht. Wenn man ein Icon drauflegt, dann sollte es funktionieren (laut Doku - ausprobiert habe ich es noch nicht).
smashed to pieces hat geschrieben:Warum braucht mein Computer so lange um die Buttons zu plazieren?
Bei mir sind die Buttons nach dem Start sofort alle da.

Was deinen Code angeht, so ist die Methode buttonDict überflüssig und auch der Name ist schlecht gewählt, weil es kein Dictionary ist, sondern eine zweidimensionale Liste. Die Zeile

Code: Alles auswählen

self.button = self.buttonDict(width=25)
dient ja eigentlich nur zu Initialisierung der Liste. Da genügt z.B. auch

Code: Alles auswählen

self.button = [[None]*25 for k in xrange(25)]
Wobei ich persönlich die Liste eher "self.buttonlist" oder "self.buttonfield" o.ä. nennen würde, weil "self.button" eher nach einem einzelnen Button klingt.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Nachtrag/Korrektur: Der eine Fall, wo es keine Konstante zur Zeichenkettenvariante gibt, ist der Readonly-Zustand eines Entry-Widgets.

Während es für "normal" und "disabled" die passenden Konstanten tk.NORMAL und tk.DISABLED gibt, gilt dies für "readonly" nicht. Interessanterweise ist der "readonly"-Zustand zwar für Entry-Widgets definiert, nicht aber für Text-Widgets.
BlackJack

Die meisten Tkinter-Konstanten (wenn nicht gar alle) sind als Zeichenketten definiert:

Code: Alles auswählen

In [82]: tk.LEFT
Out[82]: 'left'
IMHO ist es aber besser den Namen als die Zeichenkette zu verwenden weil man dann auf den ersten Blick sieht, dass es sich um eine Konstante handelt und der Interpreter auch an Stellen mit einem `NameError` auf Fipptehler reagiert, wo eine falsch geschriebene Zeichenkette vielleicht "lautlos" durchgeht, aber eben nicht richtig funktioniert.

Bei dem Geschwindigkeitsproblem könntest Du mal das "pack"en des `Frame` hinter die Schleife mit den `Button`\s verschieben. Sonst kann es eventuell passieren, dass durch jeden der 625 Knöpfe das Layout neu berchnet und die Anzeige aktualisiert wird.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo smashed to pieces

Die Konstante:

Code: Alles auswählen

button.pack(side=tk.LEFT)
stammt aus dem Skript 'Tkconstants.py', welches durch das Tkinter-Hauptskript 'Tkinter.py' mittels Sternchen-Import importiert wird. Das Skripts ist unter dem Pfad ...python/lib-tk/ auffindbar. Da diese Konstanten in deinem Programm-Skript durch das Tkinter-Modul Tkinter as tk importiert werden braucht es noch das tk. vor der Konstante. Du kannst nach dem import von Tkinter as tk noch das Modul Tkconstants mit Sternchenimport (unschön) importieren dann braucht es das tk. nicht mehr. Schau einmal in das Skript Tkconstants.py. Dort siehst du fast alle Konstanten die für Tkinter-Widgets gebraucht werden. Ich perönlich brauche meistens die Strings an Stelle der Konstanten.

Betreffs Geschwindigkeitssteigerung könntest du IMHO durch den Ersatz der Button-Widgets mittels Canvas 'Rectangle-Objekte' platziert auf einem Canvas-Widget noch eine Steigerung erreichen. Allerdings ohne den Einsatz des Pack-Managers.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

BlackJack hat geschrieben:IMHO ist es aber besser den Namen als die Zeichenkette zu verwenden weil man dann auf den ersten Blick sieht, dass es sich um eine Konstante handelt und der Interpreter auch an Stellen mit einem `NameError` auf Fipptehler reagiert, wo eine falsch geschriebene Zeichenkette vielleicht "lautlos" durchgeht, aber eben nicht richtig funktioniert.
Was den zweiten Aspekt angeht, so wären die Zeichenketten vorzuziehen, weil man im Traceback einen konkreteren Hinweis bekommt.

Beispiel: Die Konstante tk.NONAME als Wert für die Option "state" eines Entry-Widgets produziert:

Code: Alles auswählen

AttributeError: 'module' object has no attribute 'NONAME'
Die Zeichenkette "noname" hingegen:

Code: Alles auswählen

_tkinter.TclError: bad state "noname": must be disabled, normal, or readonly
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

numerix hat geschrieben:Was deinen Code angeht, so ist die Methode buttonDict überflüssig und auch der Name ist schlecht gewählt, weil es kein Dictionary ist, sondern eine zweidimensionale Liste.
Ja stimmt, sieht auch gleich schöner aus ohne die Methode. :)
BlackJack hat geschrieben:Bei dem Geschwindigkeitsproblem könntest Du mal das "pack"en des `Frame` hinter die Schleife mit den `Button`\s verschieben. Sonst kann es eventuell passieren, dass durch jeden der 625 Knöpfe das Layout neu berchnet und die Anzeige aktualisiert wird.
Hm. Hab's ausprobiert, funktioniert aber alles nicht. Braucht immer ewige einundhalb bis zwei Sekunden bis die Buttons endlich erscheinen.
Also das Fenster ist sofort da. Auch mit Titel und die Größe stimmt auch. Aber die Buttons erscheinen erst noch langen einundhalb Sekunden, dann aber alle auf einmal. :?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ich habe mal eine Zeitmessung vor und nach MyApp() geschaltet: Bei mir dauert das ca. 0,16 Sekunden, also praktisch keine sichtbare Verzögerung.
Gemessen auf einem 7 Jahre alten Rechner mit Python 2.5 / Tk 8.4 auf einem Linux-System mit KDE .

Edit: Ich glaube, die Zeitmessung sagt nichts aus. Habe es gerade mal unter wine laufen lassen. Da zeigt er mit 0,23 s an, aber der Aufbau der Buttons erfolgt sichtbar von unten nach oben und ist erst fertig, wenn die Ausgabe der Zeit auf der Konsole schon erfolgt ist ...
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Hm. Liegt anscheinend irgendwie an meinem Computer.
Oder Windows hat eine andere Vorgehensweise ôô.

Find ich komisch. Hab den Code jetzt einfach mal umgestellt:

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self, myParent):
        self.myParent = myParent
        
        self.myContainer1 = tk.Frame(self.myParent)
        self.myContainer1.pack()
                     
        self.buttonlist = [[['button%u' %(i+dummy)] for dummy in xrange(25)] for i in xrange(1,25*25,25)]
        
        for i in xrange(25):
            for o in xrange(25):
                self.buttonlist[i][o] = tk.Button(self.myContainer1, width=2, height=1)
                self.buttonlist[i][o].grid(row=i, column=o)



root = tk.Tk()
root.title("Ein paar Buttons")
myapp = MyApp(root)
print 'Hallo'
root.mainloop()
Sollte jetzt nicht erst Hallo erscheinen und sich dann erst das Fenster öffnen :? ?
Naja warscheinlich ein Denkfehler meinersteis ..
numerix hat geschrieben:Edit: Ich glaube, die Zeitmessung sagt nichts aus. Habe es gerade mal unter wine laufen lassen. Da zeigt er mit 0,23 s an, aber der Aufbau der Buttons erfolgt sichtbar von unten nach oben und ist erst fertig, wenn die Ausgabe der Zeit auf der Konsole schon erfolgt ist ...
Bei mir erscheinen die Buttons alle auf einmal.

Und jetzt nach dem obenstehendem Code erscheint zuerst ein Fenster in der gewollten Größe usw.
Dann ist eine Pause von 1-2 Sekunden, inder die Maus das Sympol der bekannten Sanduhr annimmt. Dann erscheinen die Buttons alle auf einmal. Und zuletzt, nachdem das Fenster + Buttons sichtbar ist, erscheint der Text, welcher von der Print-Anweisung ausgeht, in der Editor ansicht.

Ohne die mainloop Anweisung geht der Programmablauf bis zur Ausgabe von Hallo schnell. Also gradezu ohne Verzögerung.



Edit: Ausgabe über print erscheint eh zuerst. Nur beim Programmlauf über den Editor ist die Reinfolge verkehrt herum.
BlackJack

Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
Oder einfacher initialisieren (siehe unten Zeile 10)
Aber das verursacht sicher die Verzögerung nicht ...

Da ich die Verzögerung beim Programmstart nicht reproduzieren kann, mal zwei Vorschläge ins Blaue hinein:

Zum einen könntest du versuchen festzustellen, an welcher Stelle das Problem liegt, indem du ein paar Zeitmessungen einschiebst. Dann könnte z.B. so aussehen:

Code: Alles auswählen

import time, platform
import Tkinter as tk

timer = time.time if platform.system() == "Linux" else time.clock

class MyApp(object):
    def __init__(self, myParent):
        t0 = timer()
        self.myParent = myParent
        self.buttonlist = [[None]*25 for k in xrange(25)]
        print timer()-t0
        for i in xrange(25):
            for o in xrange(25):
                self.buttonlist[i][o] = tk.Button(self.myParent, width=2, height=1)
        print timer()-t0
        for i in xrange(25):
            for o in xrange(25):
                self.buttonlist[i][o].grid(row=i, column=o)
        print timer()-t0

root = tk.Tk()
myapp = MyApp(root)
root.mainloop()
Möglicherweise hilft das aber auch nicht, weil die Konsolenausgaben erscheinen, bevor die GUI steht.

Zweite Idee: Vielleicht liegt es am grid-Manager, obwohl das mal ein Aufbau ist, wo grid besser passt als pack. Versuch es doch mal mittels pack(), ob das irgendeinen Unterschied macht:

Code: Alles auswählen

import Tkinter as tk

root = tk.Tk()
for y in xrange(25):
    row = tk.Frame(root)
    for x in xrange(25):
        tk.Button(row, width=2, height=1).pack(side="left")
    row.pack()
root.mainloop()
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Gute Idee die Zeit zu messen.

Hab deinen Code in den Editor reinkopiert und laufenlassen:

3.77142905034e-005
0.0742387649827
0.0935973706155

Also diese Zeiten kann man nicht merken.
Außerdem sieht man, nachdem sie Zeiten schon dastehen, wie sich das Fenster mit den Buttons erst erzeugt.
(Jetzt, da die Buttons direkt in das Fenster kommen und nicht in ein extra Frame, erscheinen die Buttons nacheinander.)


Der Tipp mit dem pack() war allerdings besser.
Das Fenster erscheint mit Buttons fast ohne Verzögerung :) . Danke.

Versteh ich allerdings nicht warum mit grid() ein Verzögung von 2 Sekunden entsteht !?
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
War das in etwa so gemeint?

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self, myParent):
        self.myParent = myParent
        self.buttonlist = []
        for i in xrange(25):
            self.buttonlist.append([])
            self.row = tk.Frame(self.myParent)
            self.row.pack()
            for o in xrange(25):
                self.buttonlist[i].append('button%d'%((i*25)+o))
                self.buttonlist[i][o] = tk.Button(self.row, width=2, height=1)
                self.buttonlist[i][o].pack(side='left')

root = tk.Tk()
myapp = MyApp(root)
root.mainloop()
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

smashed to pieces hat geschrieben:
BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
War das in etwa so gemeint? Bzw. kann man das so machen?

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self):
        self.root = tk.Tk()
        self.root['bg'] = '#2ff2ff2ff'
        self.root.geometry("%dx%d+%d+%d" % (750, 750, 250, 50))
        self.root.title("Ein paar Knoepfe")

        self.container1 = tk.Frame(self.root)
        self.container1.pack(expand='yes')
        
        self.buttonlist = []
        
        for i in xrange(25):
            self.buttonlist.append([])
            self.row = tk.Frame(self.container1)
            self.row.pack()
            for o in xrange(25):
                self.buttonlist[i].append('button%d'%((i*25)+o))
                self.buttonlist[i][o] = tk.Button(self.row, width=2, height=1)
                self.buttonlist[i][o].pack(side='left',padx=1, pady=1)
        self.root.mainloop()


myapp = MyApp()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

So ähnlich auf jeden Fall. Die Zeilen 20-22 würde man eher so schreiben:

Code: Alles auswählen

button = tk.Button(self.row, width=2, height=1)
button.pack(side='left') 
self.buttonlist[i].append(button)
oder auch kürzer (aber weniger schön):

Code: Alles auswählen

self.buttonlist[i].append(tk.Button(self.row, width=2, height=1))
self.buttonlist[i][-1].pack(side='left')
Im übrigen würde für row auch eine lokale Variable genügen; am Ende ist in self.row ohnehin nur die zuletzt erzeugte Reihe mit Knöpfen.

Mir persönlich gefällt es so besser, dass "root" ein Attribut von myapp ist.
Die Bezeichnung container1 finde ich nicht so gelungen, weil es nichts Inhaltliches aussagt (außer, dass es ein Container ist und zwar der erste).
Antworten