Jad*_*win 18 python user-interface tkinter
根据问题标题:是否可以在不使用画布小部件的情况下在 Tkinter 文本小部件中的单词下方出现红色波浪线?(与拼错单词时相同的波浪线)
我要做这样的事情:
如果是这样,我会从哪里开始?
acw*_*668 16
这只是使用用户定义的 XBM 作为小部件bgstipple内文本的一部分Text来模拟波浪线效果的示例:
squiggly.xbm,如下所示:一个 10x20 像素的 XBM
Text使用上面的 XBM 图像文件在小部件中配置一个标记,如bgstipple红色:# config a tag with squiggly.xbm as bgstipple in red color
textbox.tag_config("squiggly", bgstipple="@squiggly.xbm", background='red')
Run Code Online (Sandbox Code Playgroud)
Text小部件内的文本部分:textbox.insert("end", "hello", "squiggly") # add squiggly line
Run Code Online (Sandbox Code Playgroud)
下面是一个示例代码:
import tkinter as tk
root = tk.Tk()
textbox = tk.Text(root, width=30, height=10, font=('Courier New',12), spacing1=1)
textbox.pack()
# config a tag with squiggly.xbm as bgstipple in red color
textbox.tag_config("squiggly", bgstipple="@squiggly.xbm", background='red')
textbox.insert("end", "hello", "squiggly") # add squiggly line
textbox.insert("end", " world! ")
textbox.insert("end", "Python", "squiggly") # add squiggly line
textbox.insert("end", "\nthis is second line")
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
和输出:
请注意,XBM 图像的高度需要与字体大小和行间距相匹配。
我定制了一个框架,它的布局(只是一个想法,需要改进):
当用户输入“Enter”时,它会生成一个新条目和一个新标签(波浪线小部件)。
如果用户键入“Backspace”并且此条目为空,它将同时删除此条目和标签(波浪线小部件)。
当用户键入“向上”箭头时,它将使上一个条目小部件成为焦点。
....
代码:
import tkinter
class CustomText(tkinter.Frame):
def __init__(self,master):
super(CustomText,self).__init__()
self.last_line = 0
self.index_line = 0
self.master = master
self['background'] = 'white'
self.check_func = self.master.register(self.check)
first_line = tkinter.Entry(self,font=("",16),relief="flat",validate="key",validatecommand=(self.check_func,'%W','%P'))
first_line.pack(fill="x")
first_underline = tkinter.Label(self,background="white",fg="red",font=("",4))
first_underline.pack(anchor="nw")
self.widget_dict = {
first_line:first_underline # a dict which save the squiggly line widget(as a value) and entry widget(as a key)
}
# bind event:
first_line.bind("<Return>",self.create_new_line)
first_line.bind("<Up>",self.to_previous_line)
first_line.bind("<Down>",self.to_next_line)
first_line.bind("<FocusIn>",self.focused)
def focused(self,event): # when one entry widget is focused,change the index_line number
self.index_line = list(self.widget_dict.keys()).index(event.widget)
def create_new_line(self,event): # when user input enter,generate an entry and a label
self.index_line += 1
self.last_line += 1
new_line = tkinter.Entry(self,font=("",14),relief="flat",validate="key",validatecommand=(self.check_func,'%W','%P'))
new_line.pack(fill='x')
new_underline = tkinter.Label(self, background="white", fg="red", font=("", 4))
new_underline.pack(anchor="nw")
# also bind an event
new_line.bind("<Return>", self.create_new_line)
new_line.bind("<Up>",self.to_previous_line)
new_line.bind("<Down>",self.to_next_line)
new_line.bind("<FocusIn>",self.focused)
# the difference between the first line:when user delete all the words in this widget and he input "backspace" again, it will delete the entry and label widget,
new_line.bind("<BackSpace>",self.delete_this_line)
new_line.focus_set()
self.widget_dict[new_line] = new_underline
def to_next_line(self,event): # when user type "Down",go to the previous line
if self.index_line != self.last_line:
self.index_line += 1
to_widget = tuple(self.widget_dict.keys())[self.index_line]
to_widget.focus_set()
if event: # to the same index of next entry widget.
to_widget.icursor(event.widget.index("insert"))
def to_previous_line(self,event): # when user type "Up",go to the previous line
if self.index_line:
self.index_line -= 1 # the number of index minus 1
to_widget = tuple(self.widget_dict.keys())[self.index_line]
to_widget.focus_set()
if event:
to_widget.icursor(event.widget.index("insert"))
def delete_this_line(self,event):
if not event.widget.get():
self.last_line -= 1
self.widget_dict[event.widget].destroy() # delete it in visual
del self.widget_dict[event.widget] # delete reference in the self.widget_dict
event.widget.destroy()
del event.widget
self.to_previous_line(None)
def check(self,widget_str,input_str): # this is an error-check function
widget = self.nametowidget(widget_str) # convert the widgetname to a widget object
# an example
error_str = "abc"
if input_str == error_str: # now is to check the grammar
underline_widget = self.widget_dict[widget]
underline_widget['text'] = "?"*len(error_str)*2 # add a squiggly line visually
return True
root = tkinter.Tk()
t = CustomText(root)
t.pack()
root.mainloop()
Run Code Online (Sandbox Code Playgroud)
示例图像(当用户输入“abc”时显示波浪线):
需要改进的地方: