2014-02-19 2 views
4

Я хочу использовать tkinter text widget в качестве виджета readonly. Он должен действовать как область transcript. Моя идея состоит в том, чтобы сохранить эту расшифровку в file и всякий раз, когда пользователь что-либо пишет, просто удалите все содержимое виджета и перезапишите его снова.Текстовый виджет readonly tkinter

код будет выглядеть следующим образом:

transcript_entry = SimpleEditor() # SimpleEditor is inherited from ScrolledText 
transcript_entry.text.delete("1.0", END) 

# this is just a test string, it should be the contents of the transcript file 
transcript_entry.text.insert("1.0", "This is test transcript") 
transcript_entry.text.bind("<KeyPress>", transcript_entry.readonly) 

И readonly функция будет выглядеть следующим образом:

def readonly(self, event): 
    self.text.delete("1.0", END) 
    # this is just a test string, it should be the contents of the transcript file 
    self.text.insert("1.0", "This is test transcript") 

Исправлена ​​ошибка в том, что последний символ, введенный пользователем добавляется к протоколу. Я подозреваю, что причина в том, что функция readonly называется, then пользовательский ввод записывается в виджет. Как отменить этот порядок & позволить функции readonly быть вызванной after пользовательский ввод записывается в виджет?

Любые подсказки?

+0

Что такое виджет ScrolledText ? Я не знаком с этим ... – mgilson

+0

Как насчет просто установки 'state = DISABLED'? – mgilson

+0

Он похож на «текстовый виджет tkinter» со строкой прокрутки http://docs.python.org/2/library/scrolledtext.html – yassin

ответ

5

Причина, по которой вставлен последний символ, заключается в том, что привязки по умолчанию (что вызывает вставку) происходит после после пользовательских привязок, которые вы помещаете в виджет. Таким образом, ваши привязки сначала стреляют, а - - привязка по умолчанию вставляет символы. Здесь есть другие вопросы и ответы, которые обсуждают это более подробно. Например, см. https://stackoverflow.com/a/11542200/

Однако есть лучший способ выполнить то, что вы пытаетесь сделать. Если вы хотите создать текстовый виджет только для чтения, вы можете установить атрибут state на номер "disabled". Это предотвратит все вставки и удаляет (и означает, что вам нужно вернуть состояние, когда вы хотите программно ввести данные).

На некоторых платформах кажется, что вы не можете выделить и скопировать текст, но это связано только с тем, что по умолчанию виджет не будет фокусироваться на щелчке мыши. Добавив привязку для установки фокуса, пользователь может выделить и скопировать текст, но они не смогут вырезать или вставить.

Вот пример использования python 2.x; для 3.x вам просто нужно изменить импорт:

import Tkinter as tk 
from ScrolledText import ScrolledText 

class Example(tk.Frame): 
    def __init__(self, parent): 
     tk.Frame.__init__(self, parent) 
     t = ScrolledText(self, wrap="word") 
     t.insert("end", "Hello\nworld") 
     t.configure(state="disabled") 
     t.pack(side="top", fill="both", expand=True) 

     # make sure the widget gets focus when clicked 
     # on, to enable highlighting and copying to the 
     # clipboard. 
     t.bind("<1>", lambda event: t.focus_set()) 

if __name__ == "__main__": 
    root = tk.Tk() 
    Example(root).pack(fill="both", expand=True) 
    root.mainloop() 
1

Пожалуйста, не удаляйте и вставьте текст:

  • Это огромная проблема производительности.
  • Это удалит все тегам и знаки, установленные на тексте
  • Это будет видно пользователю, и пользователи не любят мелькать интерфейсы
  • Это не является необходимым, Tkinter достаточно настраиваемый просто не позволяют пользователь меняет содержимое.

Лучший способ, по которому я нашел создание только для чтения, - это отключить все привязки, ведущие к изменению текста.

Мое решение - создать новую карту привязки виджета, содержащую только «команды только для чтения». Затем, просто перенастроить виджет для использования нового RO привязки карты вместо установленного по умолчанию:

from Tkinter import * 

# This is the list of all default command in the "Text" tag that modify the text 
commandsToRemove = (
"<Control-Key-h>", 
"<Meta-Key-Delete>", 
"<Meta-Key-BackSpace>", 
"<Meta-Key-d>", 
"<Meta-Key-b>", 
"<<Redo>>", 
"<<Undo>>", 
"<Control-Key-t>", 
"<Control-Key-o>", 
"<Control-Key-k>", 
"<Control-Key-d>", 
"<Key>", 
"<Key-Insert>", 
"<<PasteSelection>>", 
"<<Clear>>", 
"<<Paste>>", 
"<<Cut>>", 
"<Key-BackSpace>", 
"<Key-Delete>", 
"<Key-Return>", 
"<Control-Key-i>", 
"<Key-Tab>", 
"<Shift-Key-Tab>" 
) 


class ROText(Text): 
    tagInit = False 

    def init_tag(self): 
     """ 
     Just go through all binding for the Text widget. 
     If the command is allowed, recopy it in the ROText binding table. 
     """ 
     for key in self.bind_class("Text"): 
      if key not in commandsToRemove: 
       command = self.bind_class("Text", key) 
       self.bind_class("ROText", key, command) 
     ROText.tagInit = True 


    def __init__(self, *args, **kwords): 
     Text.__init__(self, *args, **kwords) 
     if not ROText.tagInit: 
      self.init_tag() 

     # Create a new binding table list, replace the default Text binding table by the ROText one 
     bindTags = tuple(tag if tag!="Text" else "ROText" for tag in self.bindtags()) 
     self.bindtags(bindTags) 

text = ROText() 

text.insert("1.0", """A long text with several 
lines 
in it""") 


text.pack() 

text.mainloop() 

Обратите внимание, что только переплеты меняются. Все команды Text (как insert, delete, ...) все еще пригодны для использования.

+0

Почему бы просто не установить атрибут 'state' виджета' 'disabled ''? –

+0

«Отключить» состояние отключить много вещей. Все операции, которые изменяют содержание текста, отключены. команды вставки/удаления больше не будут работать. Точно так же текст не будет отвечать на «<>», связывающий – mgautierfr

-1

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

def read_only(self, event): 
    if event.char is not '': # delete only if the key pressed 
           # corresponds to an actual character 
     self.text.delete('insert-1c') 

и просто привязать его к любому событию:

root.bind('<Key>', self.read_only) 
+0

Это не сработает, если в виджет вы попали более одного символа. И, конечно же, это не мешает вам _deleting_ символов. Кроме того, он выдает ошибку, если в фокусе есть ничего, кроме текстового виджета. –

+0

Истинное, но все же полезное решение, если все, что вам нужно, это возможность захвата ключевых событий без записи захваченных символов в виджеты. – glep

Смежные вопросы