Уведомления

Группа в Telegram: @pythonsu

#1 Март 16, 2015 10:45:50

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Добрый день.

У меня есть задача: обеспечить навигацию в окне Tkinter по тексту. При этом стрелка влево выделяет слово, стоящее до текущего, соответственно, стрелка вправо выделяет слово, стоящее после текущего. Вот упрощенный код:

#!/usr/bin/python3
import tkinter as tk
elem='тест'
max_elems=1001
text=(elem+' ')*max_elems
text=text[:-1]
pos_lst=[]
pos2=-2
for i in range(max_elems):
	pos1=pos2+2
	pos2=pos1+len(elem)-1
	pos_lst+=[[pos1,pos2]]
def move_right(event):
	if res[0] < len(pos_lst)-1:
		res[0]+=1
		select_term()
		
def move_left(event):
	if res[0] > 0:
		res[0]-=1
		select_term()
def select_term():
	if len(pos_lst) > 0:
		pos1=pos_lst[res[0]][0]
		pos1='1.'+str(pos1)
		pos2=pos_lst[res[0]][1]
		pos2='1.'+str(pos2+1)
		txt.tag_remove('cur_term','1.0','end')
		txt.tag_add('cur_term',pos1,pos2)
		txt.mark_set('insert',pos2)
		txt.tag_config('cur_term',background='cyan',font='Sans 14')
		txt.yview('insert')
root=tk.Tk()
res=[0]
frame=tk.Frame(root)
frame.pack()
txt=tk.Text(frame)
txt.focus_set()
txt.insert('end',text)
txt.mark_set('insert','1.0')
txt.yview('1.0')
txt.config(state='disabled')
txt.pack(expand=1)
select_term()
txt.bind('<Left>',move_left)
txt.bind('<Right>',move_right)
root.wait_window()
root.mainloop()
Однако, если текста много, и он выходит за рамки окна Tkinter, то выделение оказывается вне поля видимости (если не вставлять ‘insert’ и далее не делать yview). Но, если все же делать yview, то получается не совсем удобно: 1-й строчкой становится текущее выделение. А мне хотелось бы, чтобы выделять текст можно было в границах всего экрана, затем, если выделение оказывается вне границ экрана, то переходить на 1-ю строчку нового текста и разрешать выделять текст в рамках экрана, т.е. чтобы это больше напоминало навигацию в текстовом редакторе.
Я так понимаю, задача решается, если определить, сколько символов помещается на экране. Но как это определить?

Отредактировано vanvanov (Март 16, 2015 10:47:45)

Офлайн

#2 Март 16, 2015 14:45:23

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Если я правильно понял, то Вам необходимо определить на сколько проматывать виджет при переходе на следующую строчку?

P.S. Для упрощения можно еще рассмотреть вариант с отображением скрытой строки. В этом случае просто используем метод .see(index)…

Офлайн

#3 Март 16, 2015 16:19:15

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Если я правильно понял, то Вам необходимо определить на сколько проматывать виджет при переходе на следующую строчку?
В принципе, да. Я не могу понять, как определить, сколько строк/символов умещается на экране.
4kpt_III
P.S. Для упрощения можно еще рассмотреть вариант с отображением скрытой строки. В этом случае просто используем метод .see(index)…
Это в какой-то мере решает задачу (хотя на очень длинных строках see все равно уходит за пределы экрана, пока не понял, почему). Но мне хотелось бы, чтобы смещался не экран/текст, а выделение, а экран сменялся бы новым экраном только если выделение оказывается за границами видимости. Т.е., например, если на экране помещается 45 строк, то пусть выделение скачет между этими строками, а сам текст не смещается. А если вдруг выделение оказывается на строке 46, то пусть на экран выводится новый текст со строками 46-91 и выделение скачет уже между ними.

Офлайн

#4 Март 16, 2015 16:58:52

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Понял. Тогда придется просчитывать. По высоте: всегда фиксированное значение. Или то, которое Вы внесете сами. Или фиксированное системой. Явно предложить ничего не могу. Нужно писать ручками. Механизм скользящего окна. А насчет размеров. Нужно смотреть в сторону

 text["height"]
(предварительно сделав update()). Если возвращает не в символах, а в пикселях, то придется высчитывать самостоятельно.

Вообще адский оверхед, если честно. Вот что странно. Среди методов не вижу метода, который показывал бы - находится индекс в видимой зоне или нет. Может уже старею

Отредактировано 4kpt_III (Март 16, 2015 16:59:16)

Офлайн

#5 Март 21, 2015 19:53:11

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

А можно ли как-то вычислить координаты x, y в пикселях по координатам Tkinter типа ‘5.10’? Нашел event.x, event.y, но это касается мышки.

Офлайн

#6 Март 21, 2015 21:34:35

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Можно глянуть в сторону .bbox(index). Но предварительно не забудьте обновить характеристики Text атрибутом .update_idletasks().

Отредактировано 4kpt_III (Март 21, 2015 21:37:48)

Офлайн

#7 Март 21, 2015 21:46:26

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Вот кусочек кода. Он все пояснит. Ну только это если я Вас правильно понял

import Tkinter
#
root = Tkinter.Tk()
#
def call(event):
    event.widget.update_idletasks()
    print event.widget.bbox("current")
#
text = Tkinter.Text(root, width=20, height=20)
text.pack()
text.bind("<Return>", call)
#
root.mainloop()

P.S. Будут вопросы - пишите…

Офлайн

#8 Март 24, 2015 20:06:59

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Подскажите, пожалуйста, как пролистать текст в виджете Text так, чтобы нужная строка/метка оказалась первой строкой виджета. Пробовал txt.yview('80.0'), но нужная строка оказывается пятой.

И еще, где мне найти дельные примеры, например, по yview, scroll, moveto, dragto, scanto? Каждый раз рою гугл, и там в 121 раз цитируется офиц. руководство, которое все равно без конкретных примеров малополезно.

Отредактировано vanvanov (Март 24, 2015 20:08:57)

Офлайн

#9 Март 24, 2015 22:18:49

4kpt_III
Зарегистрирован: 2014-12-22
Сообщения: 999
Репутация: +  39  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Я явно так только один раз высчитывал. Вообще в 90% случаев мне хватало какого-нибудь метода типа .see(pos). Могу поискать, если уж очень надо…

Офлайн

#10 Март 24, 2015 23:39:08

vanvanov
Зарегистрирован: 2013-03-31
Сообщения: 252
Репутация: +  4  -
Профиль   Отправить e-mail  

Пролистывание экрана в Tkinter

Мне достаточно будет понять, как сделать произвольную строку первой без удаления или разделения текста. Остальное я уже накостылял.

Возможно, я плохо знаю tkinter, но у меня реально больше всего времени уходит на интерфейс. Я выбрал tkinter, потому что прочитал, что у него самая подробная документация и его не нужно доустанавливать, что он хорош для начинающих и т.д. и т.п.

А что в итоге мы имеем? Да, документация подробная, но примеры извольте искать на stackoverflow (если еще найдете). На никсах интерфейс еще куда ни шло, а на винде лучше этого не видеть. Убогая система координат в виде ‘1.2’, ‘2.5’ и пр. Если мне понадобится манипулировать текстом, придется писать костыли, чтобы это расшифровывать (и костыли весьма и весьма объемные). Привязка к главному окну. А теперь еще и выясняется, что невозможно определить, находится ли текст в виджете Text в поле видимости (!) и для этого нужны очередные костыли, а некоторые методы как будто живут сами по себе и срабатывают непредсказуемым образом (see, yview).

Извините, накипело.

Отредактировано vanvanov (Март 24, 2015 23:40:34)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version