Как установить максимальное значение для Scrollbar?
Делаю простой log viewer на python, использую tkinter. Код:
def insert_text():
text.delete(1.0, END)
file_name = fd.askopenfilename()
global f
f = open(file_name, 'r')
f.seek(0, 0)
text_value = f.read(text_height)
text.insert("end", text_value)
def move(change):
text.delete(1.0, END)
global f
if int(change) > 0:
text_value = f.read(text_height*int(change))
text_value = text_value[text_height*-1:-1]
else:
f.seek(f.tell() + text_height * int(change) - text_height, 0)
text_value = f.read(text_height)
text.insert("end", text_value)
window = Tk()
btn_open = Button(window, text="Открыть файл", command=insert_text)
btn_open.grid(column=3, row=0)
text = Text(window, width=200, height=40)
text.grid(column=1, row=1)
scrolly = Scrollbar(command=move)
scrolly.grid(column=2, row=1)
window.mainloop()
Все работает, при прокрутке с помощью колесика мыши читается следующие куски кода, отображаются в Text. Однако, сама полоса прокрутки остается на месте (на самой верхушке scrollbar), а значит, я могу прокручивать свой лог только колесом мыши. Перепрыгнуть на самый конец файла невозможно.
Есть ли возможность задать максимальное значение для scrollbar, чтобы прыгнуть сразу в конец, перетащив его мышью?
Ответы (1 шт):
При привязке текстового поля к скролбару нужно чтобы и скролбар управлял текстовым полем (в вашем случае - подгружался нужный кусок файла), и текстовое поле управляло скролбаром - устанавливалась позиция начала и конца ползунка через метод set. В обычной привязке этот метод передается в текстовое поле через параметр yscroll, например text = Text(..., yscroll=vscroll.set) или text['yscroll'] = vscroll.set (в зависимости от того, какой объект создан раньше - текстовое поле или скролбар), и объект текстового поля вызывает этот метод когда нужно. В вашем случае этот метод нужно вызывать принудительно, чтобы обновлять состояние ползунка.
Другие комментарии:
moveдолжно принимать два параметра (это видно по ошибкам, которые кидает интерпретатор в консоль), за позицию отвечает второй параметр, и его нужно приводить вfloatа неint, и это позиция ползунка от 0.0 до 1.0 (от 0% до 100%), а не изменение позиции.Позиция, куда нужно переместиться в файле, определяется как позиция ползунка (от 0.0 до 1.0) умноженная на размер файла, никакой сложной логики тут не нужно.
f.read(...)подгружает указанное количество символов, но логичнее подгружать нужное количество строк через[file.readline() for _ in range(text_height)]Размер ползунка фиксированный - 10% от общего размера полосы прокрутки (0.1 в строках
scrolly.set(0.0, 0.1)иscrolly.set(position, position + 0.1)). Можно сделать установку размера в зависимости от того какая часть (доля) файла загружена, но мне было лень - и так работает :) Но в принципе ничего не мешает это сделать.
Остальное смотрите в комментариях в коде.
from tkinter import *
import tkinter.filedialog as fd
import os
text_height = 40
file = None
file_size = None
def open_file():
global file, file_size
file_name = fd.askopenfilename()
file_size = os.path.getsize(file_name)
if file:
file.close()
file = open(file_name, 'r')
text_lines = [file.readline() for _ in range(text_height)]
text.delete(1.0, END)
text.insert(END, ''.join(text_lines))
# Метод set устанавливает позицию начала и конца ползунка
# Первоначальная позиция ползунка - в самом верху,
# конец ползунка - на 10% (от общей высоты скролбара) ниже
scrolly.set(0.0, 0.1)
def move(command, position=0):
# command - обычно строка "moveto", position - значение от "0.0" до "1.0"
# Файл открыт?
if file is None:
return
position = float(position)
# Не давать прокрутить выше или ниже границ файла
# (если продолжать тянуть вниз или вверх после того как ползунок уперся в край,
# в функцию будут приходить значения position меньше 0 или больше 1)
if position < 0.0:
position = 0.0
if position > 1.0:
position = 1.0
file.seek(file_size*position)
if position > 0.0:
# Если не начало файла, то считать что попали на середину строки, пропускаем ее
try:
file.readline()
except UnicodeDecodeError:
# Кидает это исключение, если переход на середину utf-8 символа
# Чтобы корректно обрабатывать такие ситуации, нужно файл открывать в бинарном режиме,
# и в процессе чтения текст декодировать
pass
text_lines = [file.readline() for _ in range(text_height)]
text.delete(1.0, END)
text.insert(END, ''.join(text_lines))
scrolly.set(position, position + 0.1) # Обновить позицию "ползунка"
window = Tk()
btn_open = Button(window, text="Открыть файл", command=open_file)
btn_open.grid(column=3, row=0)
text = Text(window, width=200, height=text_height+1)
text.grid(column=1, row=1)
scrolly = Scrollbar(command=move)
scrolly.grid(column=2, row=1, sticky=NS)
scrolly.set(0.0, 1.0) # Устанавливаем первоначальную высоту "ползунка" полосы прокрутки на 100%
window.mainloop()