Уведомления

Группа в Telegram: @pythonsu

#1 Март 1, 2015 13:02:06

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Tkinter виджет Text "выбрать все"

Всем доброго времени суток. При изучении библиотеки tkinter (Python 3*) столкнулся с непонятным мне поведением.
Первое, когда я пытался реализовать функционал “выбрать все” по нажатию клавиш Ctrl+a:

from tkinter import *
root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def select_all(e):
    e.widget.tag_add(SEL, '1.0', END)
text.bind('<Control-a>', select_all)
root.mainloop()

Первая же ссылка впоиске гугла по запросу: http://stackoverflow.com/questions/5870561/re-binding-select-all-in-text-widget
где из второго ответа я понял что нужно либо использовать …bind_class но это не есть гуд т.к. определит поведение для всех виджетов класса; либо можно вернуть из обработчика события строку ‘break’ я сделал второе и о чудо - оно заработало:

from tkinter import *
root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def select_all(e):
    e.widget.tag_add(SEL, '1.0', END)
    return 'break'    # ЭТО ДАЛО НУЖНЫЙ ЭФФЕКТ!
text.bind('<Control-a>', select_all)
root.mainloop()

Второе, когда я делал поиск слова по виджету Text у меня получались странные глюки при находжении нужного слова оно должно выделиться и если оно за пределами экрана должна произвестись прокрутка. Но это происходило через раз! Я решил ради интереса добавить в обработчик return ‘break’ - и оно заработало!

from tkinter import *
from tkinter.simpledialog import *

root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def find_text(e):
    target = askstring('Find text', 'Search String?')
    if target:
        where = e.widget.search(target, INSERT, END)
        if where:
            print(where)
            pastit = where + ('+%dc' % len(target))
            e.widget.tag_remove(SEL, '1.0', END)
            e.widget.tag_add(SEL, where, pastit)
            e.widget.mark_set(INSERT, pastit)
            e.widget.see(INSERT)
            e.widget.focus()
    return 'break'    # РЕШИЛО ПРОБЛЕМУ!!!
text.bind('<Control-f>', find_text)
root.mainloop()

Там же на stackoverflow была приведена ссылка: http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm где поясняются какие то моменты при работе с событиями, и поиск по странице по слову ‘break’ указал мне на нужный параграф. Там даже примеры кода даются. Но у меня не очень хорошо с английским и я как не бился не смог понять толком о чём там говорится. Объясните пожалуйста, кто “в теме” что тут вообще происходит? Почему return ‘break’ - решило обе проблемы?

Офлайн

#2 Март 1, 2015 20:19:34

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

Tkinter виджет Text "выбрать все"

Кучу лет уже работаю с tkinter, но никогда такого не видел. Попробуйте просто вернуть None или приведите полный код, чтобы можно было протестировать.

moskitos80
Первое, когда я пытался реализовать функционал “выбрать все” по нажатию клавиш Ctrl+a:

Приведите код и что было не так. Очень и очень сумбурно.

P.S. У меня никаких проблем с выделением не было. Правда я не маркировал текст тегами (не было таких задач). Такой подход к обработке события мне кажется сомнительным, если честно… Понятие “всплывание” события здесь хоть и есть, но не такой как в jquery.

Офлайн

#3 Март 1, 2015 20:38:12

terabayt
От: Киев
Зарегистрирован: 2011-11-26
Сообщения: 1099
Репутация: +  103  -
Профиль   Отправить e-mail  

Tkinter виджет Text "выбрать все"

4kpt_III
или приведите полный код, чтобы можно было протестировать
from Tkinter import *
root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def find_text(e):
    target = "a" # текст который нужно найти
    if target:
        where = e.widget.search(target, INSERT, END)
        if where:
            print(where)
            pastit = where + ('+%dc' % len(target))
            e.widget.tag_remove(SEL, '1.0', END)
            e.widget.tag_add(SEL, where, pastit)
            e.widget.mark_set(INSERT, pastit)
            e.widget.see(INSERT)
            e.widget.focus()
    return 'break'    # РЕШИЛО ПРОБЛЕМУ!!!
text.bind('<Control-f>', find_text)
root.mainloop()
вот пример
http://dmych.org/post/1351354709



————————————————
-*- Simple is better than complex -*-

Офлайн

#4 Март 1, 2015 20:38:51

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Tkinter виджет Text "выбрать все"

4kpt_III
Кучу лет уже работаю с tkinter, но никогда такого не видел. Попробуйте просто вернуть None или приведите полный код, чтобы можно было протестировать.

Я же привел примеры кода. Можно запустить и проверить. Вот это не работает:

from tkinter import *
root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def select_all(e):
    e.widget.tag_add(SEL, '1.0', END)
text.bind('<Control-a>', select_all)
root.mainloop()

А вот так работает (я привел комментарий там где добавил код):

from tkinter import *
root = Tk()
text = Text(root)
text.pack(expand=YES, fill=BOTH)
def select_all(e):
    e.widget.tag_add(SEL, '1.0', END)
    return 'break'    # ЭТО ДАЛО НУЖНЫЙ ЭФФЕКТ!
text.bind('<Control-a>', select_all)
root.mainloop()

Офлайн

#5 Март 1, 2015 21:34:28

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

Tkinter виджет Text "выбрать все"

Все правильно работает…

break не нужен

P.S. Подсказка. Поменяйте <Control-a> на <Control-m>…

P.S.S. Тут имеет место дележка вызванного события.

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

Офлайн

#6 Март 1, 2015 22:43:16

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Tkinter виджет Text "выбрать все"

4kpt_III
P.S.S. Тут имеет место дележка вызванного события.
Вот! Вот про это можно по подробнее? Именно этот момент я смутно представляю себе и хочу разобраться. Я предполагал, точнее все что я смог понять со своим плохим английским на иностранных сайтах это то, что после моего обработчика вызываются какие то еще обработчики. Но я же не вешал больше ни каких обработчиков. Делаю вывод, что библиотека вызывает какие то свои обработчики т.н. действия по-умолчанию, а возвращение строки ‘break’ предотвращает их выполнение. Но что это за обработчики по умолчанию? И для чего они нужны? Зачем они сделаны? Можно пожалуйста подробнее рассказать?

Офлайн

#7 Март 1, 2015 22:50:15

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

Tkinter виджет Text "выбрать все"

Объясню. Но с одним условием. Никогда больше вы не будете использовать конструкцию

from tkinter import*

Договорились?

Офлайн

#8 Март 2, 2015 09:45:54

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Tkinter виджет Text "выбрать все"

4kpt_III
Никогда больше вы не будете использовать конструкцию… Договорились?
Без проблем. Я её использую только в учебных целях. Я представляю все плюсы и минусы этой конструкции. В реальном коде я себе такого не позволю

Офлайн

#9 Март 2, 2015 11:55:24

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

Tkinter виджет Text "выбрать все"

Тогда держите. Этот код ответит Вам на все вопросы.

import Tkinter
#
root = Tkinter.Tk()
#
#
def call(who):
    print who
#
but = Tkinter.Button(root, text="ops", width=30, height=3)
but.bind("<Button-1>", lambda e: call("but"))
but.pack()
root.bind_class("Button", "<Button-1>", lambda e: call("class"))
root.bind("<Button-1>", lambda e: call("root"))
root.bind_all("<Button-1>", lambda e: call("all"))
#
root.mainloop()

Офлайн

#10 Март 2, 2015 15:08:00

moskitos80
От: Luna
Зарегистрирован: 2015-01-28
Сообщения: 18
Репутация: +  0  -
Профиль  

Tkinter виджет Text "выбрать все"

Да-да этот код я понимаю. В вашем примере на одно событие явно “повешено” несколько обработчиков и событие “всплывает” через них всех. Но в моей то ситуации:

import tkinter as tk
#
root = tk.Tk()
text = tk.Text(root)
text.pack(expand=tk.YES, fill=tk.BOTH)
#
def select_all(e):
    e.widget.tag_add(tk.SEL, '1.0', tk.END)
#
text.bind('<Control-a>', select_all)
root.mainloop()

на событие <Control-a> “повешен” только один, мой обработчик!? А почему тогда происходит вызов каких то еще обработчиков?

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version