【问题标题】:How can you mark a portion of a text widget as readonly?如何将文本小部件的一部分标记为只读?
【发布时间】:2012-06-26 03:57:51
【问题描述】:

如何将 tkinter 文本小部件的一部分标记为只读?也就是说,我希望能够只允许在小部件的某些部分进行编辑。例如,我想只允许在提示之后而不是之前进行编辑,以模拟控制台。

【问题讨论】:

    标签: python tkinter text-widget


    【解决方案1】:

    最安全的解决方案是拦截低级插入和删除命令,并在其中放置逻辑以根据某种标准防止插入和删除。例如,您可以禁止在任何带有“只读”标签的文本范围内进行编辑。

    这是这种技术的一个例子。它利用了所有插入和删除最终调用底层 tk widget 命令的insertdelete 子命令的事实,以及 widget 命令可以替换为 Tcl proc 的事实。

    try:
        # python 2.x
        import Tkinter as tk
    except ImportError:
        # python 3.x
        import tkinter as tk
    
    class Example(tk.Frame):
        def __init__(self, parent):
            tk.Frame.__init__(self, parent)
    
            text = ReadonlyText(self)
            sb = tk.Scrollbar(self, orient="vertical", command=text.yview)
            text.configure(yscrollcommand=sb.set)
            sb.pack(side="left", fill="y")
            text.pack(side="right", fill="both", expand=True)
    
            text.insert("end", "You can edit this line\n")
            text.insert("end", "You cannot edit or delete this line\n", "readonly")
            text.insert("end", "You can edit this, too.")
    
            text.tag_configure("readonly", foreground="darkgray")
    
    class ReadonlyText(tk.Text):
        '''A text widget that doesn't permit inserts and deletes in regions tagged with "readonly"'''
        def __init__(self, *args, **kwargs):
            tk.Text.__init__(self, *args, **kwargs)
    
            # this code creates a proxy that will intercept
            # each actual insert and delete. 
            self.tk.eval(WIDGET_PROXY)
    
            # this code replaces the low level tk widget 
            # with the proxy
            widget = str(self)
            self.tk.eval('''
                rename {widget} _{widget}
                interp alias {{}} ::{widget} {{}} widget_proxy _{widget} 
            '''.format(widget=widget))
    
    WIDGET_PROXY = '''
    if {[llength [info commands widget_proxy]] == 0} {
        # Tcl code to implement a text widget proxy that disallows
        # insertions and deletions in regions marked with "readonly"
        proc widget_proxy {actual_widget args} {
            set command [lindex $args 0]
            set args [lrange $args 1 end]
            if {$command == "insert"} {
                set index [lindex $args 0]
                if [_is_readonly $actual_widget $index "$index+1c"] {
                    bell
                    return ""
                }
            }
            if {$command == "delete"} {
                foreach {index1 index2} $args {
                    if {[_is_readonly $actual_widget $index1 $index2]} {
                        bell
                        return ""
                    }
                }
            }
            # if we passed the previous checks, allow the command to 
            # run normally
            $actual_widget $command {*}$args
        }
    
        proc _is_readonly {widget index1 index2} {
            # return true if any text in the range between
            # index1 and index2 has the tag "readonly"
            set result false
            if {$index2 eq ""} {set index2 "$index1+1c"}
            # see if "readonly" is applied to any character in the
            # range. There's probably a more efficient way to do this, but
            # this is Good Enough
            for {set index $index1} \
                {[$widget compare $index < $index2]} \
                {set index [$widget index "$index+1c"]} {
                    if {"readonly" in [$widget tag names $index]} {
                        set result true
                        break
                    }
                }
            return $result
        }
    }
    '''
    
    def main():
        root = tk.Tk()
        Example(root).pack(fill="both", expand=True)
        root.mainloop()
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

      猜你喜欢
      • 2013-05-20
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2014-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多