Scrollbar Problem

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

Hallo zusammen,
habe ein Problem mit der Scrollbar, dazu poste ich Euch ein Beispiel zum Testen und zur Fehlerfindung.
Das Fenster vertikal, ist größer als die Bildschirmhöhe und die vertikale Scrollbar lässt sich nicht scrollen.

Code: Alles auswählen

#!/usr/bin/env python
# _*_ coding: utf_8 _*_
# For Python3.x

import tkinter as tk
from tkinter import ttk

RANGE = 45
def scroll_test():

	root = tk.Tk()
	# Create y- and x-scrollbar.
	yscrollbar = tk.Scrollbar(root, orient=tk.VERTICAL,
		bg='lightgrey', activebackground='lightsteelblue',
		troughcolor='red')
	yscrollbar.grid(row=0, column=1, sticky=tk.NS)
	xscrollbar = tk.Scrollbar(root, orient=tk.HORIZONTAL,
		bg='lightgrey', activebackground='lightsteelblue',
		troughcolor='red')
	xscrollbar.grid(row=1, column=0, sticky=tk.EW)
	# Create y- and canvas for table or dataset.
	canvas = tk.Canvas(root, bd=0, scrollregion=(0, 0, 0, 0),
		xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
	canvas.grid(row=0, column=0, sticky=tk.NSEW)
	# Integrate scrollbar in canvas.
	yscrollbar.config(command=canvas.yview)
	xscrollbar.config(command=canvas.xview)
	canvas.xview_moveto(0)
	canvas.yview_moveto(0)

	# Create widgets
	frame = tk.Canvas(None, bg='yellow')
	frame.grid(row=0, column=0, sticky=tk.W)
	width = 40
	ypos = 0
	for i in range(RANGE):
		value = 'Das ist Labelnummer: {}'.format(i)
		var = tk.StringVar(value = value)
		widget = tk.Label(canvas, width = width, textvariable = var)
		widget.grid(row=i, column=0)
		ypos += widget.winfo_reqheight()
		xpos = widget.winfo_reqwidth()
		canvas.create_window(xpos, ypos, anchor='nw', window=frame)
	canvas.update_idletasks()
	x, y, w, h = canvas.bbox(tk.ALL)
	print(x, y, w, h)
	if h > 800:
		h = 800
	root.geometry('{}x{}+{}+{}'.format(x, y, w, h))
	root.mainloop()
scroll_test()
Hoffe, Ihr könnt den Fehler finden und mir damit helfen!

Grüße Nobuddy
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo Nobuddy,
was willst Du? Du kreierst ein Canvas in root. In dieses Canvas platzierst Du noch ein Canvas mit grid. Im zweiten Canvas zeigst Du mehrere Zeilen (Labels) an. Aber Scrollen willst Du das erste Canvas. Wozu das zweite Canvas? Dann beschränkst Du noch die Abmessungen von root. Besser ist, den sichtbaren Teil vom Canvas zu beschränken.
Die Scrollregion sollte auch bestimmt werden. Wenn die untere Ecke gleich der oberen ist, wird nicht viel gescrollt. Wozu wird ttk importiert?
Ausserdem wir mit viel Leerzeichen eingerückt.

Code: Alles auswählen

#!/usr/bin/env python
# _*_ coding: utf_8 _*_
# For Python3.x

import tkinter as tk

RANGE = 145

def scroll_test():
    root = tk.Tk()
    # Create Canvas
    canvas = tk.Canvas(root, bd=0, width=400, height=400)
    canvas.grid(row=0, column=0, sticky=tk.NSEW)
    # Create y- and x-scrollbar.
    yscrollbar = tk.Scrollbar(root, orient=tk.VERTICAL,
            bg='lightgrey', activebackground='lightsteelblue',
            troughcolor='red', command=canvas.yview)
    yscrollbar.grid(row=0, column=1, sticky=tk.NS)
    xscrollbar = tk.Scrollbar(root, orient=tk.HORIZONTAL,
            bg='lightgrey', activebackground='lightsteelblue',
            troughcolor='red', command=canvas.xview)
    xscrollbar.grid(row=1, column=0, sticky=tk.EW)
    # Integrate scrollbar in canvas.
    canvas.config(xscrollcommand=xscrollbar.set)
    canvas.config(yscrollcommand=yscrollbar.set)
    # Create widgets    
    ypos = 0
    for i in range(RANGE):
            value = 4 * ('Das ist Labelnummer: {} '.format(i))
            var = tk.StringVar(value = value)
            widget = tk.Label(canvas, textvariable=var, width=len(value)+10,
                              anchor='w', relief='ridge')            
            ypos += widget.winfo_reqheight()
            xpos = widget.winfo_reqwidth()            
            canvas.create_window(10, ypos, anchor='w', window=widget)           
   
    x, y, w, h = canvas.bbox(tk.ALL)   
    canvas.config(scrollregion=(0, 0, w, h))
    canvas.columnconfigure(1, weight=1)
    canvas.rowconfigure(1, weight=1)       
    root.mainloop()
	
scroll_test()
Gruss Peter
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo Peter,
das mit ttk ist in dem Beispiel, gehört da eigentlich nicht dazu.
Das mit dem zweiten Canvas, hat mich auch gestört. Ohne dies bekam ich aber keine Ausgabe der widgets.

Bin auch kurze vorher, nach weiterem Googeln, auf die Lösung gekommen. Das zweite Canvas, war dabei überflüssig.

Code: Alles auswählen

canvas.configure(scrollregion=canvas.bbox("all"))
Jetzt funktioniert das Ganze, wie gewünscht.

Eine Überlegung ist, welche Möglichkeit es gibt, wenn einer der Scrollbalken nicht benötigt wird? Im Voraus weiß man ja bei größeren Datenmengen nicht, ob beide Scrollbalken benötigt werden. Wird nur, wie in meinem Beispiel, die y-Scrollbar benötigt, wäre ja die x-Scrollbar überflüssig.

Jedenfalls Danke für Deine Hilfe! :wink:

Grüße Nobuddy
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Nobuddy hat geschrieben: Mittwoch 1. Juni 2022, 14:12
Eine Überlegung ist, welche Möglichkeit es gibt, wenn einer der Scrollbalken nicht benötigt wird? Im Voraus weiß man ja bei größeren Datenmengen nicht, ob beide Scrollbalken benötigt werden. Wird nur, wie in meinem Beispiel, die y-Scrollbar benötigt, wäre ja die x-Scrollbar überflüssig.
Das kannst Du zum Beispiel so lösen, indem Du die Scollbar erst fertigstellst, wenn sie benötigt wird..

Code: Alles auswählen

import tkinter as tk

RANGE = 145

def scroll_test():
    root = tk.Tk()
    # Create Canvas
    canvas_breite = 400
    canvas_hoehe = 400
    canvas = tk.Canvas(root, bd=0, width=canvas_breite,
                       height=canvas_hoehe)
    canvas.grid(row=0, column=0, sticky=tk.NSEW)
    # Create y- and x-scrollbar.
    yscrollbar = tk.Scrollbar(root, orient=tk.VERTICAL,
            bg='lightgrey', activebackground='lightsteelblue',
            troughcolor='red', command=canvas.yview)    
    xscrollbar = tk.Scrollbar(root, orient=tk.HORIZONTAL,
            bg='lightgrey', activebackground='lightsteelblue',
            troughcolor='red', command=canvas.xview)    
    # Integrate scrollbar in canvas.
    canvas.config(xscrollcommand=xscrollbar.set)
    canvas.config(yscrollcommand=yscrollbar.set)
    # Create widgets    
    ypos = 0
    for i in range(RANGE):
        value = 4 * ('Das ist Labelnummer: {} '.format(i))
        var = tk.StringVar(value = value)
        widget = tk.Label(canvas, textvariable=var, width=len(value)+10,
                          anchor='w', relief='ridge')            
        ypos += widget.winfo_reqheight()
        xpos = widget.winfo_reqwidth()            
        canvas.create_window(10, ypos, anchor='w', window=widget)
        if xpos > canvas_breite:
            xscrollbar.grid(row=1, column=0, sticky=tk.EW)
        if ypos > canvas_hoehe:
            yscrollbar.grid(row=0, column=1, sticky=tk.NS)         
    x, y, w, h = canvas.bbox(tk.ALL)   
    canvas.config(scrollregion=(0, 0, w, h))
    canvas.columnconfigure(1, weight=1)
    canvas.rowconfigure(1, weight=1)       
    root.mainloop()
	
scroll_test()
Gruss Peter
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo Peter,
Danke für Dein Beispiel!
Habe Dein Beispiel mal in verschiedene Funktionen aufgeteilt.

Code: Alles auswählen

import tkinter as tk


def create_canvas(root):
	# Create Canvas
	canvas = tk.Canvas(root, bd=0)
	canvas.grid(row=0, column=0, sticky=tk.NSEW)
	return canvas


def create_scrollbar(root, canvas, screenx, screeny):
	x, y, w, h = canvas.bbox(tk.ALL)
	# Create y- and x-scrollbar.
	yscrollbar = tk.Scrollbar(root, orient=tk.VERTICAL, bg='lightgrey',
		activebackground='lightsteelblue', troughcolor='red',
		command=canvas.yview)
	xscrollbar = tk.Scrollbar(root, orient=tk.HORIZONTAL, bg='lightgrey',
		activebackground='lightsteelblue', troughcolor='red',
		command=canvas.xview)
	canvas.config(width=w-x, height=h-y)
	scroll_width = 0
	if w > screenx:
		xscrollbar.grid(row=1, column=0, sticky=tk.EW)
		scroll_width = xscrollbar.winfo_screenheight()
		w = screenx
		# Integrate x-scrollbar in canvas.
		canvas.config(width=w, xscrollcommand=xscrollbar.set)
	scroll_height = 0
	if h > screeny:
		yscrollbar.grid(row=0, column=1, sticky=tk.NS)
		scroll_height = yscrollbar.winfo_screenwidth()
		h = screeny - 80	# KDE-Kontrollleiste
		# Integrate y-scrollbar in canvas.
		canvas.config(height=h, yscrollcommand=yscrollbar.set)
	canvas.update_idletasks()
	x, y, w, h = canvas.bbox(tk.ALL)
	canvas.config(scrollregion=(x, y, w, h))
	canvas.columnconfigure(0, weight=1)
	canvas.rowconfigure(0, weight=1)
	return scroll_width, scroll_height

def create_widgets(root, canvas):
	# Create widgets
	width = 40
	ypos = 0
	for i in range(RANGE):
		value = 'Das ist Labelnummer: {}'.format(i)
		var = tk.StringVar(value = value)
		widget = tk.Label(canvas, width = width, textvariable = var,
			anchor=tk.W)
		widget.grid(row=i, column=0)
		ypos += widget.winfo_reqheight()
		xpos = widget.winfo_reqwidth()
		canvas.create_window(xpos, ypos, anchor='nw', window=widget)

RANGE = 45
def start():
	root = tk.Tk()
	root.title('Scrollbar Test')
	# Ermittle die Größe des Bildschirmes
	screenx = root.winfo_screenwidth()
	screeny = root.winfo_screenheight()
	canvas = create_canvas(root)
	create_widgets(root, canvas)
	x, y, w, h = canvas.bbox(tk.ALL)
	if w > screenx or h > screeny:
		scroll_width, scroll_height = create_scrollbar(
			root, canvas, screenx, screeny)
		if w > screenx:
			w = screenx - scroll_height
		if h > screeny:
			h = screeny - 80 - scroll_width
		root.geometry('{}x{}+{}+{}'.format(x, y, w, h))
	else:
		canvas.config(width=w-x, height=h-y, scrollregion=(x, y, w, h))
	root.mainloop()
start()
Grüße Nobuddy
Antworten