Breite von dynamischen Label ermitteln

Fragen zu Tkinter.
Antworten
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

dieses Thema wurde evtl. bestimmt schon mehrmals behandelt, leider konnte ich bisher aber keine Lösung finden.

Mit Tkinter erstelle ich ein Frame, in dem ich zuerst unten ein schmales Label über die ganze Breite erstelle, dann links und rechts je ein Label in denen Buttons platziert werden.
In die Mitte kommt ein weiteres Label, das ich als Listbox benutze.

Da meine Buttons links und rechts, je nach dem unterschiedlich breit sind, suche ich eine Möglichkeit, die Breite des Labels in der Mitte zu ermitteln.

Wie läßt die Breite eines dynamischen Labels ermitteln?

Grüße Nobuddy
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Warum habe ich das http://www.galileocomputing.de/download ... aechen.pdf nur nicht vorher gefunden?

Code: Alles auswählen

labelbreite = self.listboxWindow.winfo_width()
Jetzt muß ich nur noch die Umrechnung von Pixel zu der Maßeinheit von 'width=xxx' finden.

Vielleicht habt Ihr da einen Tip für mich?
BlackJack

@Nobuddy: Mein Tipp: Lass es sein. Das klingt alles sehr eigenartig und irgendwie als wenn Du etwas selber machen willst, wofür Tk Layoutmanager hat.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nobuddy

Eventuell braucht es noch ein update() um einen korrekten Pixelwert der Breite zu bekommen:

Code: Alles auswählen

root.update()
labelbreite = self.listboxWindow.winfo_width()
Gruss wuf :wink:
Take it easy Mates!
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo wuf, danke für die Info! :wink:

@BlackJack, der Tk Layoutmanager tut gute Dienste, keine Frage.
In meinem Fall, was ich auch oben nicht erwähnt habe, kommt noch canvas und grid mit ins Spiel.
Hier habe ich zu einem, mein Mittleres Label, in dem dann ein Scrollmenü mit canvas eingebunden wird.
In diesem Scrollmenü gibt es eine Namens- und eine Datenspalte, die je nach Anwendung unterschiedliche Breite haben.
Dieses Scrollmenü soll die maximale Breite des mittleren Label nutzen, so daß auch noch der Scrollbalken sichtbar und nutzbar ist.
Nun versuche ich das so einzustellen, daß bei verschiedenen Displaygrößen, ich immer das gleiche Ergebnis erhalte.

Ich poste hier mal den betreffenden Code.
Die betreffenden Stellen habe ich mit '####': markiert.

Code: Alles auswählen

    def set_scrolled_entries(self, label_names, result):
        """Scrollmenü zur Datenverarbeitung.
        Gibt den gewählten Datensatz aus."""

        try:
            if self.baseWindow:
                self.baseWindow.destroy()
        except AttributeError:
            pass
        h_now = max([len(row) for row in [label_names]]) * 60
        try:
            try:
                if self.kunde:
                    habzug = 155
            except AttributeError:
                if self.lieferant:
                    habzug = 155
        except AttributeError:
            habzug = 65
        h_max = self.winLabel.winfo_height() - habzug
        if h_now < h_max:
            h_max = h_now
#######################
        scrollbalken = 20
        self.root.update()
        b_pix = self.listboxWindow.winfo_width() - scrollbalken
        b_max = round(b_pix / (int(self.txt2[1]) - 0.25))
#######################
        self.baseWindow = tk.Label(self.listboxWindow)
        self.baseWindow.pack(anchor='ne', expand=False, fill='x')
        self.scrollWindow = tk.Label(self.baseWindow, text='', 
            bg=self.bg, fg=self.fc, font=self.txt2)
        self.scrollWindow.pack(anchor='ne', expand=False)

        # Individuelle Buttons und Eingabefelder
        self.scrolled_entries_buttons(self.master_check, self.sub_check)

        self.entry_vars = [tk.StringVar() for _ in label_names]
        self.result = result
        self.entries = list()
        self.scroll_frame = tk.Frame(self.scrollWindow, bg='red')
        canvas = tk.Canvas(self.scroll_frame, highlightthickness=0)
        canvas.grid(row=0, column=1, sticky=tk.NSEW)
        xscroll = tk.Scrollbar(self.scroll_frame, orient=tk.HORIZONTAL,
            command=self.horizontal_scroll)
        xscroll.grid(row=1, column=1, sticky=tk.EW)
        self.xscroll = xscroll
        yscroll = tk.Scrollbar(self.scroll_frame, orient=tk.VERTICAL,
            command=canvas.yview)
        yscroll.grid(row=0, column=2, sticky=tk.NS)
        canvas.config(xscrollcommand=xscroll.set)
        self.scroll_frame.grid_rowconfigure(1, weight=1)
        canvas.config(yscrollcommand=yscroll.set)
        self.scroll_frame.grid_rowconfigure(0, weight=1)
        self.canvas = canvas
        self.bind_scroll(yscroll, self.y_scroll)
        label_frame = tk.Frame(canvas)
        ENTRY_IPADX = 5 # Abstand zu Text in x
        ENTRY_IPADY = 2 # Abstand zu Text in y
        try:
            x_count = len(label_names)
        except ValueError:
            x_count = 0
        for i, (var, name) in enumerate(zip(self.entry_vars, label_names)):
            label_container = tk.Frame(label_frame)
            label_container.grid(row=i, column=0, padx=10, pady=10,
                sticky=tk.NW)
            label = tk.Label(label_container, text=name, font=self.txt2)
            label.grid(ipady=5, sticky=tk.W)
            entry_container = tk.Frame(label_frame,relief='sunken',
                bd=1, bg=self.bg)
            entry_container.grid(row=i, column=1)
#######################
            entry = tk.Entry(entry_container, textvariable=var,
                width=b_max, font=self.txt2, bg=self.bg, bd=0,
                highlightthickness=0)
#######################
            entry.grid(row=0, column=0, padx=ENTRY_IPADX, pady=ENTRY_IPADY)
            entry.bind("<FocusIn>", self.entry_focus_callback)
            try:
                if len(self.result) == 1:
                    var.set(''.join([row[i] for row in self.result]))
                elif len(self.result) > 1:
                    var.set('\t'.join([row[count2]
                        for count, row in enumerate(self.result)
                        if i == count for count2 in range(x_count)]))
            except (TypeError, IndexError):
                var.set('IndexError')
            self.entries.append(var)
        canvas.create_window(0, 0, window=label_frame, anchor=tk.NW)
        canvas.update_idletasks()
        x, y, w, h = label_frame.bbox(tk.ALL)
#######################
        canvas.config(scrollregion=(x, y, w, h), width=b_pix, height=h_max)
#######################

        return self.scroll_frame
Ich weiß, Du hast da schon schöneren Code gesehen .... :wink:

Bei

Code: Alles auswählen

        b_max = round(b_pix / (int(self.txt2[1]) - 0.25))
hole ich mir aus 'self.txt2[1]', die verwendete Schriftgröße (hier 14).
b_max ergibt dann die Breite für die Spalte Daten.
Da kann man schon Haarausfall bekommen, mir ist aber da nichts bessere eingefallen.

Wie ich gelesen habe, wird als Einheit die Zeichenbreite bei 'width=xx' verwendet.
Dabei wird die '0' als Zeichenbreite, abhängig von der Schriftgröße verwendet.
Nur wie genau man das umsetzen kann, die Pixel in Zeichenbreite einigermaßen genau umzurenchen?
BlackJack

@Nobuddy: Ich behaupte einfach mal das geht auch ohne das man selber an den Layout-Grössen rumschrauben muss. Und falls nicht, sollte man es bleiben lassen und eine andere Lösung finden. GUI-Toolkits sind ja dazu da dass man solchen Code *nicht* schreiben muss.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, evtl. fehlt mir einfach noch das Wissen darüber, daß ich so einen Spagat nicht brauche, oder es gibt Ausnahmen wie überall sonst auch!?

Ich habe jetzt für mich hier http://code.activestate.com/recipes/552 ... cm-and-mm/ eine Lösung gefunden.

Code: Alles auswählen

        ## Maximale Breite für Scrollmenü
        self.root.update()
        # Breite von Label in Pixel
        pixels = self.listboxWindow.winfo_width()
        # Breite von Zeichen in Pixel
        sign_width = int(self.txt2[1]) / 2
        # Größte Zeichenlänge von Bezeichnung-Spalte
        maxname = max([len(row) for row in label_names])
        # Ermittle wieviel Pixel 1 Punkt hat
        pixels_per_point = 0
        View.pixels_per_point = self.root.winfo_fpixels( '1p' )
        # Ermittle die Zeichenlänge für den Label
        sign_in_label = pixels / (View.pixels_per_point * sign_width)
        # Ermittle die Zeichenlänge für den Scrollbalken
        sign_in_scrollbalken = 2 * View.pixels_per_point * sign_width
        # Ermittle die Zeichenlänge für die Bezeichnung-Spalte
        sign_in_name = maxname * View.pixels_per_point
        # Ermittle die maximale Zeichenlänge für die Daten-Spalte
        sign_in_data = round(sign_in_label - sign_in_scrollbalken
            - sign_in_name)
        # Label-Gesamtbreite - Scrollbalken
        b_pix = self.listboxWindow.winfo_width() - sign_in_scrollbalken
PS Nachtrag:
Habe oben die Zeile 'PIXELS_PER_POINT = 0' in 'pixels_per_point = 0' abgeändert.
Antworten