button placement.

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.
jan.b
User
Beiträge: 195
Registriert: Mittwoch 9. August 2017, 17:12

Hallo, wie kann ich diesen button umposittionieren? und was tut mainloop(hat damit nichts zu tun. würde ich trotzdem gerne wissen.)
danke schon mal. :D
from tkinter import*
tk = Tk()

canvas = Canvas(tk, width=400, height=400)
canvas.pack()

def hi():
print("hi")
btn = Button(tk, width=20, height=30, text="hallo", fg='red', bg='black', command=hi)
btn.pack()
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Lange nicht mehr da gewesen - immer noch nicht gelernt, Code in die Codebox zu stecken.... :roll:

Was deine mainloop Frage angeht: diese Thema wird ganz akut hier im Tkinter Forum diskutiert. In das dein Posting übrigens auch gehört.

Und ohne zu wissen wie das Ergebnis aussehen soll, kann man deine Hauptfrage auch nicht beantworten.
jan.b
User
Beiträge: 195
Registriert: Mittwoch 9. August 2017, 17:12

ok. das Ergebnis soll sein, dass ich weiß, wie man buttons platziert. also wäre eine dementsprechende antwort nett. :lol:
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du hast also wirklich kein einziges Beispiel im großen weiten Internet gefunden, in dem Buttons platziert werden? Und auch nicht hier im Forum, in dem zB Wuf permanent so etwas postet? Da bleibt nur der Schluss, das du weder Hände noch Augen hast, womit es ja dann auch egal ist, ob du einen Button platziert bekommst, ist ja eh nicht sicht- und benutzbar für dich :twisted:
jan.b
User
Beiträge: 195
Registriert: Mittwoch 9. August 2017, 17:12

harter diss. leider nicht hilfreich aber trotzdem hart.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Doch doch, hilfreich war der schon. Du bist halt ein bisschen sehr ignorant den dir gegebene Tipps gegenüber. Selbst in dem “harten Diss” habe ich dir erzählt, wie du an Beispiele kommst. Und Erklärungen.

Wenn du jemanden suchst, der dir auf hingerotzte zwei Sätze einen interaktiven Roman mit Tonspur & Glitzerstaub liefert, wirst du jemanden dafür bezahlen müssen. Wenn du HIER Hilfe willst, wirst du deutlich mehr liefern müssen. Aber das haben wir dir ja nun schon seit Anbeginn deiner Karriere hier dargelegt, oder?
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

Tkinter kennt drei verschiedene Layout Manager, damit kannst du Element platzieren. Wenn du jetzt fragen möchtest: "Wie?" -> RTMF. Dazu gibt es etliche Threads hier im Forum und tausende Seiten im Internet.

`btn = Button(tk, width=20, height=30, text="hallo", fg='red', bg='black', command=hi)` ist IMHO relativ sinnfrei - warum soll sich ein Button bei ein Klick darauf selber aufrufen?

Der mainloop macht das, was der Name sagt: es ist die Hauptschleife von Tkinter, die alle Interaktionen mit der GUI kontrolliert bzw. darauf reagiert.

Gruß, noisefloor
jan.b
User
Beiträge: 195
Registriert: Mittwoch 9. August 2017, 17:12

der button ruft sich ja über btn.pack auf. und ich glaube ohne geht's nicht.
jan.b
User
Beiträge: 195
Registriert: Mittwoch 9. August 2017, 17:12

ich habe ehrlich gesagt nicht genug zeit für den ganzen quatsch. manchmal brauche ich schnelle präzise antworten auf spezifische fragen. @noisenfloor hat's ja auch irgendwie hinbekommen einen antwort satz zu schreiben, der ein wenig hilfreich war. es ist nicht die konventionelle art etwas zu lernen, aber wenn du eine frage siehst, auf die du in ein oder zwei sätzen antorten kannst, wäre es einfach nur nett dies auch zu tun.
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@jan.b: Wenn du präzisere Antworten brauchst, dann stell' doch aml präzise Fragen. Was heißt "umpositionieren"? Du hast eine 400x400px großes Fenster mit einem Button. Umpositionieren kann alles mögliche sein - links oben, rechts unten, horizontal mittig 25% außerhab der vertikalen Mitte usw.

`pack()`kennt zusätzliche Argumente zu Positionierng -> RTMF

Außerdem mangelt es deiner Art der Kommunikation hier, also wie du antwortest, manchmal doch ein sozialer Verträglichkeit. Sprich die Motivation der hier regelmäßig helfenden, zu antworten, ist dann eher gering.

Und außerdem liegt bei dir auch immer, bezogen auf die Fragen und Antworten die Vermutung nah, dass deine Motivation, selber etwas herauszufinden und zu erarbeiten, eher gering ist. Hier im Forum gibt's Hilfe zur Selbsthilfe. Wenn Selbsthilfe nicht so dein Ding ist, dann ist das auch ein schlechter Ausgangspunkt für python-forum.de.

Gruß, noisefloor
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Keine deiner Fragen hier im Thread war spezifisch. Und du bist ein Schüler, du weißt noch nicht mal , was es heißt, keine Zeit zu haben. Mal abgesehen davon, das es kein Quatsch ist, was wir hier verlangen. Sondern notwendig. Was du überhaupt nicht einschätzen kannst, mangels Grundlagen.

Du hast einfach keinen Bock drauf auch nur ein Iota Anstrengung zu unternehmen, sondern willst ohne eigenen Aufwand abgreifen. Wird nix werden.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

__deets__ hat geschrieben:Wuf permanent so etwas postet?
Hier ist der 'wuf' schon wieder: :)

Hi Jan.b

Habe hier eine kleine Demo für die Platzierung des Buttons mit dem Pack-Layouter geschrieben:

Code: Alles auswählen

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

# Tkinter for Python 3.xx
import tkinter as tk

APP_TITLE = "Button placing with pack layouter"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 600
APP_HEIGHT = 200

SIDES = ['top', 'right', 'bottom', 'left']
ANCHORS = ['center', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw']
FONT = ('Helevetica', 14, 'bold')

        
class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.title(APP_TITLE)
    
    def build(self):
        self.protocol("WM_DELETE_WINDOW", self.close_app)
        self.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
        self.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
        self.option_add("*Button.highlightThickness", 0)
        
        frame = tk.Frame(self, bg='#FFFF00')
        frame.pack(fill='both', expand=True)
        
        self.pos_var = tk.StringVar()
        self.button = tk.Button(frame, textvariable=self.pos_var, width=18,
            height=2, font=FONT)
        self.button.pack(padx=10, pady=10)

        self.place_the_button()
        
    def place_the_button(self, pos_index=0, pos_mode='side'):
        if pos_mode == 'side':    
            side = SIDES[pos_index]
            self.pack_with_side(side)
            pos_index += 1
            if pos_index >= len(SIDES):
                pos_index = 0
                pos_mode = 'anchor'
                
        elif pos_mode == 'anchor':
            anchor = ANCHORS[pos_index]
            self.pack_with_anchor(anchor)
            pos_index += 1
            if pos_index >= len(ANCHORS):
                pos_index = 0
                pos_mode = 'side'

        self.after(2000,self.place_the_button, pos_index, pos_mode)

    def pack_with_side(self, side):
        # Wichtige voreingestellte Optionen für die Anwendung von 'side' sind:
        # 'anchor' = 'center'
        # 'expand' = False
        print('Side:', self.button.pack_info())
        
        self.button.config(bg='#90EE90')
        self.pos_var.set("Position with side:\n'{}'".format(side))
        self.button.pack_configure(side=side, anchor='center', expand=False)
        
    def pack_with_anchor(self, anchor):
        # Wichtige voreingestellte Optionen für die Anwendung von 'anchor' sind:
        # 'expand' = True 
        print('Anchor:', self.button.pack_info())
        
        self.button.config(bg='#1AB7EA')
        self.pos_var.set("Position with anchor:\n'{}'".format(anchor))
        self.button.pack_configure(anchor=anchor, expand=True)
        
    def close_app(self):
        # Here do something before apps shutdown
        print("Good Bye!")
        self.destroy()

        
def main():        
    app = Application()
    app.build()
    app.mainloop()

    
if __name__ == '__main__':
    main()      
Gruss wuf :wink:
Take it easy Mates!
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn es nur eine Moeglichkeit gegben haette, sich solcher Art Code hier aus dem Forum rauszusuchen...

https://www.google.com/search?q=site%3A ... e&ie=UTF-8

@wuf: wenn die App-Klasse eh nur sinnvoll ist, wenn "build" aufgerufen wird, ist es angezeigt, diesen Aufruf gleich in __init__ zu taetigen.

Fuer mainloop gilt das natuerlich nicht. Das sollte getrennt bleiben, damit man zwischen App instantiieren und Eintritt in die Ereignisbearbeitung noch Luft hat.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@__deets__: Danke für deinen Tipp. Habe mein Skript angepasst:

Code: Alles auswählen

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

# Tkinter for Python 3.xx
import tkinter as tk

APP_TITLE = "Button placing with pack layouter"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 600
APP_HEIGHT = 200

SIDES = ['top', 'right', 'bottom', 'left']
ANCHORS = ['center', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw']
FONT = ('Helevetica', 14, 'bold')

        
class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.title(APP_TITLE)
        self.build()
        
    def build(self):
        self.protocol("WM_DELETE_WINDOW", self.close_app)
        self.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
        self.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
        self.option_add("*Button.highlightThickness", 0)
        
        frame = tk.Frame(self, bg='#FFFF00')
        frame.pack(fill='both', expand=True)
        
        self.pos_var = tk.StringVar()
        self.button = tk.Button(frame, textvariable=self.pos_var, width=18,
            height=2, font=FONT)
        self.button.pack(padx=10, pady=10)

        self.place_the_button()
        
    def place_the_button(self, pos_index=0, pos_mode='side'):
        if pos_mode == 'side':    
            side = SIDES[pos_index]
            self.pack_with_side(side)
            pos_index += 1
            if pos_index >= len(SIDES):
                pos_index = 0
                pos_mode = 'anchor'
                
        elif pos_mode == 'anchor':
            anchor = ANCHORS[pos_index]
            self.pack_with_anchor(anchor)
            pos_index += 1
            if pos_index >= len(ANCHORS):
                pos_index = 0
                pos_mode = 'side'

        self.after(2000,self.place_the_button, pos_index, pos_mode)

    def pack_with_side(self, side):
        # Wichtige voreingestellte Optionen für die Anwendung von 'side' sind:
        # 'anchor' = 'center'
        # 'expand' = False
        print('Side:', self.button.pack_info())
        
        self.button.config(bg='#90EE90')
        self.pos_var.set("Position with side:\n'{}'".format(side))
        self.button.pack_configure(side=side, anchor='center', expand=False)
        
    def pack_with_anchor(self, anchor):
        # Wichtige voreingestellte Optionen für die Anwendung von 'anchor' sind:
        # 'expand' = True 
        print('Anchor:', self.button.pack_info())
        
        self.button.config(bg='#1AB7EA')
        self.pos_var.set("Position with anchor:\n'{}'".format(anchor))
        self.button.pack_configure(anchor=anchor, expand=True)
        
    def close_app(self):
        # Here do something before apps shutdown
        print("Good Bye!")
        self.destroy()

               
Application().mainloop()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Wuf: die Reduktion auf

Code: Alles auswählen

Application().mainloop()
ist auch nicht ideal, denn so verwirfst Du das Applikationsobjekt unmittelbar, sobald die Mainloop beendet wird. Dein vorheriger Ansatz, allerdings ohne den Aufruf von 'build', da dieses nach dem Hinweis von __deets__ nun in der Initialisierung mit integriert ist, war da sauberer. Kompakten Code zu schreiben ist gut, zu kompakt hingegen bringt keinen Vorteil.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi kbr

Danke auch für deinen Tipp. Habe mein Skript wieder korrigiert:

Code: Alles auswählen

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

# Tkinter for Python 3.xx
import tkinter as tk

APP_TITLE = "Button placing with pack layouter"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 600
APP_HEIGHT = 200

SIDES = ['top', 'right', 'bottom', 'left']
ANCHORS = ['center', 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw']
FONT = ('Helevetica', 14, 'bold')

        
class Application(tk.Tk):

    def __init__(self):
        tk.Tk.__init__(self)
        self.title(APP_TITLE)
        self.build()
        
    def build(self):
        self.protocol("WM_DELETE_WINDOW", self.close_app)
        self.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
        self.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
        self.option_add("*Button.highlightThickness", 0)
        
        frame = tk.Frame(self, bg='#FFFF00')
        frame.pack(fill='both', expand=True)
        
        self.pos_var = tk.StringVar()
        self.button = tk.Button(frame, textvariable=self.pos_var, width=18,
            height=2, font=FONT)
        self.button.pack(padx=10, pady=10)

        self.place_the_button()
        
    def place_the_button(self, pos_index=0, pos_mode='side'):
        if pos_mode == 'side':    
            side = SIDES[pos_index]
            self.pack_with_side(side)
            pos_index += 1
            if pos_index >= len(SIDES):
                pos_index = 0
                pos_mode = 'anchor'
                
        elif pos_mode == 'anchor':
            anchor = ANCHORS[pos_index]
            self.pack_with_anchor(anchor)
            pos_index += 1
            if pos_index >= len(ANCHORS):
                pos_index = 0
                pos_mode = 'side'

        self.after(2000,self.place_the_button, pos_index, pos_mode)

    def pack_with_side(self, side):
        # Wichtige voreingestellte Optionen für die Anwendung von 'side' sind:
        # 'anchor' = 'center'
        # 'expand' = False
        print('Side:', self.button.pack_info())
        
        self.button.config(bg='#90EE90')
        self.pos_var.set("Position with side:\n'{}'".format(side))
        self.button.pack_configure(side=side, anchor='center', expand=False)
        
    def pack_with_anchor(self, anchor):
        # Wichtige voreingestellte Optionen für die Anwendung von 'anchor' sind:
        # 'expand' = True 
        print('Anchor:', self.button.pack_info())
        
        self.button.config(bg='#1AB7EA')
        self.pos_var.set("Position with anchor:\n'{}'".format(anchor))
        self.button.pack_configure(anchor=anchor, expand=True)
        
    def close_app(self):
        # Here do something before apps shutdown
        print("Good Bye!")
        self.destroy()


def main():        
    app = Application()
    app.mainloop()

if __name__ == '__main__':
    main()
Noch ein Frage im Zusammenhang mit dem Aufruf von 'build' in der Klasse Application. Ist es problematisch wenn sich in dieser Methode weitere 10'000 Zeilen Kode befinden?

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
noisefloor
User
Beiträge: 3829
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ist es problematisch wenn sich in dieser Methode weitere 10'000 Zeilen Kode befinden?
Laufen tut das - nur ist eine Funktion mit 10.000 Zeilen Code nicht wartbar, darin findet du ja nichts mehr wieder... Das sollte man dann in mehr Funktionen runter brechen. Das ist aber nicht tkinter-spezifisch, dass gilt für jeglichen Code.

Gruß, noisefloor
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Wuf: Bei der Instanziierung eines Objektes sollte nichts weiter geschehen, als dieses Objekt in einen 'gebrauchsfähigen' Zustand zu versetzen. Wenn dafür 10000 Zeilen Code erforderlich sind, würde ich die Architektur hinterfragen. In der Praxis mag sowas zustande kommen, wenn ein Objekt sehr komplex ist und eine Vielzahl anderer Objekte als Attribute enthält (für die das ggf. auch wieder gilt). Für Python sind 10000 Zeilen Code bereits extrem viel.

Als Nachtrag noch: bei

Code: Alles auswählen

app = Application()
app.mainloop()
hast Du zudem die Möglichkeit, zwischen der Instanziierung und dem Aufruf der Mainloop, noch was einzufügen. So auch 'build', wie Du es ursprünglich getan hattest, aber dieses ist funktional der Initialisierung zuzuordnen und daher dort besser aufgehoben.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@noisefloor & kbr: Danke für eure Antworten.

OK ich habe natürlich ein wenig übertrieben mit den 10'000 Zeilen Code. Es könnten ja viel weniger Zeilen sein aber dafür ein Zeit konsumierender Algorithmus der in der Methode 'build' abgearbeitet wird. Meine Frage ist wäre es ein Unterschied, wenn dieser Zeit konsumierend Block in der __init__ Methode ausgeführt wird oder in der Klasse 'Application' aus der _init__ Methode aufgerufenen Methode 'build' abgearbeitet würde. Wenn diese zwei Varianten keinen Unterschied ausmachen wäre es dann doch besser die folgende Variante anzuwenden?:

Code: Alles auswählen

def main():        
    app = Application()
    app.build()
    app.mainloop()

if __name__ == '__main__':
    main()
So würde doch die __init__ Methode der Klasse 'Application' sofort vor dem zeitintensiven Block in der 'build'Methode ausgeführt werden?
N.B: Hoffe mich richtig ausgedrückt zu haben.

Gruss wuf :wink:
Take it easy Mates!
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Frage ist, was das build macht. Wenn du es weg lassen kannst, und das ganze ist immer noch sinnvoll zu nutzen - dann vielleicht. Aber wenn - wie bei dir - sowieso nach Konstruktion *IMMER* build aufrufen musst, dann ist alles was du geschafft hast eine Fehlerquelle einzubauen - wehe jemand vergisst, build aufzurufen. Die Laufzeit wird aber dadurch nicht besser, wieso sollte sie? Die Menge an Anweisungen ist gleich, und damit auch die Laufzeit.

Generell ist es eine selten sinnvolle Idee, Objekte zu bauen, fuer die man erst magische Zaubesprueche in Form von diversen Methodenaufrufen in genau der richtigen Reihenfolge taetigen muss, bevor sie was tun.
Antworten