Problem mit horizontalem Scrollbar bei Textwidget

Fragen zu Tkinter.
Antworten
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Mittwoch 11. Juni 2008, 20:25

Ich möchte in einer Anwendung ein Text-Widget mit horizontalem und vertikalem Scrollbar. Problem:

Ich habe für das Text-Widget per width eine feste Breite gesetzt. Sobald ich den horizontalen Scrollbar ergänze, wird diese Vorgabe offenbar aber ignoriert und das Text-Widget ist nur noch so breit, wie die beiden Dreicke des Scrollbars zusammen.

Laut Doku kann man die Breite eines Scrollbars mittels dessen option width ändern. Stimmt auch, aber leider ändert man damit bei einem horizontalen Scrollbar nicht etwa die Breite des Scrollbars, sondern die Größe (in beiden Dimensionen!) der Pfeilspitzen! Sieht übel aus.

Obwohl ein Text-Widget mit zwei Scrollbars nicht so ungewöhnlich sein dürfte, habe ich auch kein Beispiel dazu gefunden. Eine kurze Notiz bei effbot.org könnte man so verstehen, dass man in Fällen wie meinem mit dem pack()-Manager nicht gut fährt und stattdessen grid() verwenden sollte.
Okay, könnte ich machen. Oder noch einen Extra-Frame einsetzen. Könnte ich auch machen.

Aber vielleicht gibt es ja doch einen Trick, um das Problem zu lösen, ohne Eingriffe am Layout der GUI vornehmen zu müssen.
Benutzeravatar
wuf
User
Beiträge: 1481
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 12. Juni 2008, 09:35

Hallo pütone

Ich habe hier einmal ein Code-Schnippet für das Text-Widget mit dem Einsatz des Grid-Layout-Managers zusammengestellt. Es ist schon so, dass man mit den verschiedenen Layout-Managern herumspielen muss. Vielleicht ist dies auch der Grund, dass es von denen drei unterschiedlich Typen gibt. Ermöglicht aber eine sehr flexible Konfigurierung der GUI-Applikation. Beim herumspielen mit dem Pack-Manager kippt das Programmieren manchmal in Zauberei um Hi. Hoffe, dass ich dir hiermit ein wenig geholfen zu haben.

Code: Alles auswählen

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

"""
Funktion: Text-Widget mit Ziehleisten in
          einem positionierbaren Rahmen.
          Layoutmanager: Place,Grid
          Mit den Layout-Manager-Typen
          muss manchmal ein bisschen herum-
          gespielt werden.
          Dieses Beispiel wurde auf Linux
          SuSE 10.0 getestet.
"""

import Tkinter as tk

def configure_scrollbar(widget_object):
    """Konfiguriert die Ziehleiste"""

    #~~ Konfiguration ist rein intuitiv!
    #   z.B. Van Goch, Dali, Picasso, Tcl ....
    widget_object.configure(
        cursor              = 'hand1',
        bg                  = 'gray',
        activebackground    = 'gray90',
        troughcolor         = 'gray50',
        bd                  = 1,
        width               = 12,
        highlightthickness  = 0,
        highlightcolor      = 'red'
        )

#--- Erstelle ein Tk-Hauptfenster ----
root = tk.Tk()
root.geometry('300x180')
root['bg'] = 'steelblue2'
root.title('Text-Widget mit Ziehleisten')

#~~ Konstanten
TEXT_WIDGET_FONT   = ('Times','10','normal')
TEXT_WIDGET_XPOS   = 50     # Pixel
TEXT_WIDGET_YPOS   = 30     # Pixel
TEXT_WIDGET_WIDTH  = 25     # Zeichen
TEXT_WIDGET_HEIGHT = 5      # Zeichen

#~~ Rahmen für die Aufnahme des Text-Widget
container_frame = tk.Text(root,
    bd = 0,
    highlightthickness = 0,
    )
container_frame.place(x=TEXT_WIDGET_XPOS,y=TEXT_WIDGET_YPOS)

#~~ Text-Widget
text_plane = tk.Text(container_frame,
    width  = TEXT_WIDGET_WIDTH,
    height = TEXT_WIDGET_HEIGHT,
    relief = 'sunken',
    bd     = 0,
    font   = TEXT_WIDGET_FONT,
    wrap   = 'none',         #'char','word'
    highlightthickness = 0,
    )
text_plane.grid(row=0,column=0)

#~~ Horizontale Ziehleiste
x_scrollbar = tk.Scrollbar(container_frame,
    orient  = 'horizontal',
    command = text_plane.xview,
    )
x_scrollbar.grid(row=1,column=0,sticky='we')
configure_scrollbar(x_scrollbar)

#~~ Vertikale Ziehleiste
y_scrollbar = tk.Scrollbar(container_frame,
    orient  = 'vertical',
    command = text_plane.yview,
    )
y_scrollbar.grid(row=0,column=1,sticky='ns')
configure_scrollbar(y_scrollbar)

#~~ Initialisieren der Ziehleisten
text_plane['xscrollcommand'] = x_scrollbar.set
text_plane['yscrollcommand'] = y_scrollbar.set

#~~ Setze Fokus auf das Text-Widget
text_plane.focus_set()

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

Donnerstag 12. Juni 2008, 12:50

Da hast du dir ja - wie schön des öfteren hier - richtig viel Arbeit gemacht.
Ich hoffe, du konntest selbst (auch) davon profitieren, denn für mich wäre es jetzt nicht nötig gewesen.

Das Problem bestand ja nicht darin, dass ich es nicht realisieren konnte bzw. kann, sondern meine Hoffnung war, dass es nur irgendeines gezielten Eingriffs bedurft hätte, um das ohne die Scrollbars einwandfreie Layout vor weitergehenden Eingriffen retten zu können.

Da ich den ganzen Rest der GUI mittels pack()-Manager realisiert habe und auch alles wie gewünscht aussieht - eben bis auf den beschriebenen Effekt durch die ergänzten Scrollbars -, wollte ich nicht gerne auf das grid()-Layout umsteigen und mischen wollte ich es auch nicht.

Meine Lösung sieht jetzt so aus, dass ich einen weiteren Frame eingesetzt habe, dem ich rechts und unten die Scrollbars verpasst habe und dann das Text-Widget hineingesetzt. Das funktioniert - ebenso wie deine grid-Variante.
Benutzeravatar
wuf
User
Beiträge: 1481
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 12. Juni 2008, 15:46

Hallo pütone

Freut mich, dass du eine passende Lösung gefunden hast. Für mich ist der Arbeitsaufwand für die Code-Snippets kein Problem. Alle Snippets landen bei mir in einer Ablage. Können irgendwann sicher wieder verwendet werden. Wenn ich hier etwas Code hinterlasse haben eventuell auch noch ander interessiert Forum-Mitglieder etwas davon.

Deine Lösung würde mich auch noch interessieren. Könntest du hier evt. auch noch deinen Code präsentieren, sofern du diesen nicht für ein Closed-Source-Project benötigst.

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

Donnerstag 12. Juni 2008, 16:29

Auf das Wesentliche reduziert in etwa so:

Code: Alles auswählen

import Tkinter as tk

root = tk.Tk()
frame = tk.Frame(root)
frame.pack(side=tk.LEFT,fill=tk.Y)
editor = tk.Text(frame)
editor.pack(side=tk.TOP,fill=tk.Y,expand=True)
scroll_y = tk.Scrollbar(root,command=editor.yview)
scroll_y.pack(side=tk.LEFT,fill=tk.Y)
scroll_x = tk.Scrollbar(frame,command=editor.xview,orient=tk.HORIZONTAL)
scroll_x.pack(side=tk.BOTTOM,fill=tk.X)
editor.config(width=30,wrap="none",padx=5,pady=5,
            yscrollcommand=scroll_y.set,xscrollcommand=scroll_x.set)
root.mainloop()
Benutzeravatar
wuf
User
Beiträge: 1481
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 12. Juni 2008, 17:10

Hallo pütone

Besten Dank.
Super-Lösung der Aufgabe.

Wünsche die alles Gute und viel Erfolg!

Gruss wuf :wink:
Take it easy Mates!
Antworten