在tkinter文本小部件上,双击的默认行为是选择鼠标下的文本。
该事件将选择“”(空格)字符之间的所有字符。
所以 - 假设文本小部件有:
1111111 222222
双击第一个单词(所有1
)将仅选择它(双击2
单词将选择它)
我希望有类似的行为,但添加额外的字符作为工作分隔符(例如.
,(
,)
)
目前,如果文字有111111.222222
- 双击文字的任何地方都会突出显示所有字符(不会按.
分隔字词)
有办法吗?
答案 0 :(得分:2)
The double click is defined to select the 'word' under the cursor. If you are wanting to change the default behavior for all text widgets, tkinter has a way to tell it what is a "word" character. If you change what tkinter thinks is a "word", you change what gets selected with a double-click. This requires that we directly call the built-in tcl interpreter upon which tkinter is based.
Note: this will affect other aspects of the widget as well, such as key bindings for moving the cursor to the beginning or ending of a word.
Here's an example:
import tkinter as tk
def set_word_boundaries(root):
# this first statement triggers tcl to autoload the library
# that defines the variables we want to override.
root.tk.call('tcl_wordBreakAfter', '', 0)
# this defines what tcl considers to be a "word". For more
# information see http://www.tcl.tk/man/tcl8.5/TclCmd/library.htm#M19
root.tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_.,]')
root.tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_.,]')
root = tk.Tk()
set_word_boundaries(root)
text = tk.Text(root)
text.pack(fill="both", expand=True)
text.insert("end", "foo 123.45,678 bar")
root.mainloop()
If you do not want to affect any widget except one, or do not want to affect other aspects of tkinter that depend on the definition of a 'word', you can create your own binding to select whatever you want.
The important thing to remember is that your binding should return the string "break"
in order prevent the default behavior for double-click:
def handle_double_click(event):
<your code for selecting whatever you want>
return "break"
...
text.bind("<Double-1>", handle_double_click)
To facilitate this, the text widget has a search
method that makes it possible to search backwards and forwards through the text for a given string or regular expression.
答案 1 :(得分:0)
有办法吗?
当然,甚至没有一种方式。但无论如何 - 我们需要为@timestamp
小部件设置一个自定义类,所以让我们开始吧:
Text
可选的class CustomText(tk.Text):
def __init__(self, parent, delimiters=[]):
tk.Text.__init__(self, parent)
# test text
self.insert('1.0', '1111111 222222'
'\n'
'1111111.222222'
'\n'
'1111111.222222,333333'
'\n'
'444444444444444444')
# binds
self.bind('<Double-1>', self.on_dbl_click)
self.bind('<<Selection>>', self.handle_selection)
# our delimiters
self.delimiters = ''.join(delimiters)
# stat dictionary for double-click event
self.dbl_click_stat = {'clicked': False,
'current': '',
'start': '',
'end': ''
}
会导致两个选项:
如果出现分隔符,我们可以依赖RegEx search
作为分隔符。
如果省略分隔符,我们可以依赖内置表达式,尤其是那两个(类似RegEx的词边界):delimiters
和wordstart
。根据{{3}}:
wordend
和wordstart
将索引移动到当前单词的开头(结尾)。单词是字母,数字和下划线的序列,或单个非空格字符。
逻辑很简单 - 当双击发生时 - 我们跟踪此事件并将索引存储在字典中。之后我们处理选择的更改,并相应地采取选择的选项(见上文)。
这是一个完整的代码段:
wordend
总之,如果你真的不关心分隔符,而是关于单词 - 第二种选择是好的,否则 - 第一种选择。
更新
非常感谢@Bryan Oakley指出try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class CustomText(tk.Text):
def __init__(self, parent, delimiters=[]):
tk.Text.__init__(self, parent)
# test text
self.insert('1.0', '1111111 222222'
'\n'
'1111111.222222'
'\n'
'1111111.222222,333333'
'\n'
'444444444444444444')
# binds
self.bind('<Double-1>', self.on_dbl_click)
self.bind('<<Selection>>', self.handle_selection)
# our delimiters
self.delimiters = ''.join(delimiters)
# stat dictionary for double-click event
self.dbl_click_stat = {'clicked': False,
'current': '',
'start': '',
'end': ''
}
def on_dbl_click(self, event):
# store stats on dbl-click
self.dbl_click_stat['clicked'] = True
# clicked position
self.dbl_click_stat['current'] = self.index('@%s,%s' % (event.x, event.y))
# start boundary
self.dbl_click_stat['start'] = self.index('@%s,%s wordstart' % (event.x, event.y))
# end boundary
self.dbl_click_stat['end'] = self.index('@%s,%s wordend' % (event.x, event.y))
def handle_selection(self, event):
if self.dbl_click_stat['clicked']:
# False to prevent a loop
self.dbl_click_stat['clicked'] = False
if self.delimiters:
# Preserve "default" selection
start = self.index('sel.first')
end = self.index('sel.last')
# Remove "default" selection
self.tag_remove('sel', '1.0', 'end')
# search for occurrences
occurrence_forward = self.search(r'[%s]' % self.delimiters, index=self.dbl_click_stat['current'],
stopindex=end, regexp=True)
occurrence_backward = self.search(r'[%s]' % self.delimiters, index=self.dbl_click_stat['current'],
stopindex=start, backwards=True, regexp=True)
boundary_one = occurrence_backward + '+1c' if occurrence_backward else start
boundary_two = occurrence_forward if occurrence_forward else end
# Add selection by boundaries
self.tag_add('sel', boundary_one, boundary_two)
else:
# Remove "default" selection
self.tag_remove('sel', '1.0', 'end')
# Add selection by boundaries
self.tag_add('sel', self.dbl_click_stat['start'], self.dbl_click_stat['end'])
root = tk.Tk()
text = CustomText(root)
text.pack()
root.mainloop()
- 字符串阻止了默认行为,因此代码可以缩短为只有一个回调,不再需要'break'
:
<<Selection>>