Python-tk。使用tab键时设置小部件焦点

Python-tk。使用tab键时设置小部件焦点,python,tkinter,Python,Tkinter,我有一个GUI,左侧有一列按钮,右侧有文本输入框,页脚有一些通用GUI按钮(新建/删除/保存/退出)。左侧的按钮分别向右侧的文本输入小部件提供一组单词。我希望能够在文本输入小部件中使用control tab或control shift tab,并将焦点返回到输入文本输入小部件的按钮。我在谷歌上搜索过,也做过实验,但在使用tab键组合后,我找不到一种方法来强制聚焦某个特定的按钮 from tkinter import * import decimal class category_rule():

我有一个GUI,左侧有一列按钮,右侧有文本输入框,页脚有一些通用GUI按钮(新建/删除/保存/退出)。左侧的按钮分别向右侧的文本输入小部件提供一组单词。我希望能够在文本输入小部件中使用control tab或control shift tab,并将焦点返回到输入文本输入小部件的按钮。我在谷歌上搜索过,也做过实验,但在使用tab键组合后,我找不到一种方法来强制聚焦某个特定的按钮

from tkinter import *
import decimal

class category_rule():
    def __init__(self,hi_range,low_range,word_list,rule,row):
        self.hi_range = decimal.Decimal(hi_range)
        self.low_range = decimal.Decimal(low_range)
        self.word_list = sorted(word_list)
        self.rule = rule
        self.button_row = row
        self.rule_button = None
        self.rule_entry_window=None

def build_rules():
    rule_dict = {}
    rule_index = {}
    words = []

    rule='Fruit'
    words=['Apple','Banana','Strawberry']
    row=0 
    rule_dict[rule] = category_rule('9999.99','0.00',words,rule,row)
    rule_index[row] = rule

    rule = 'Vegetable'
    words=['Asparagus','Brussel Sprouts','Kale','Tomato','Spinach']
    row=1
    rule_dict[rule] = category_rule('9999.99','0.00',words,rule,row)
    rule_index[row] = rule

    rule = 'Dessert'
    words=['Cake','Pudding','Cookies','Pie']
    row=2
    rule_dict[rule] = category_rule('9999.99','0.00',words,rule,row)
    rule_index[row] = rule

    return rule_dict, rule_index


class rule_entry_window:
    active_index = 0
    active_rule = None
    first_rule=None
    button_row=0
    rule_dict = {}
    rule_index = {}


    ''' methods to create the window, build the frames add the widgets '''
    def init_window_and_frames(self):   
        self.win = Tk()
        self.bg_color = '#134E9C'
        self.text_entry_frame = Frame(self.win, width=150, height=380, bg='#DDDECE', padx=1, pady=1, borderwidth=1)
        self.button_frame_outer = Frame(self.win, width=150, height=300, bg=self.bg_color, padx=3, pady=3, borderwidth=1)
        self.button_frame = Frame(self.button_frame_outer, width=150, height=300, bg = self.bg_color, padx=3, pady=3, borderwidth=1)
        self.range_entry_frame = Frame(self.win, width=150, height=40, bg=self.bg_color, padx=3, pady=3, borderwidth=1)
        self.footer_frame = Frame(self.win, width=480, height=30, bg=self.bg_color, padx=3, pady=3, borderwidth=1)

        self.button_frame.grid(row=0,column=0,sticky='nesw')
        self.button_frame_outer.grid(rowspan=2,column=0,sticky='nsew')
        self.text_entry_frame.grid(row=1,column=1,sticky='s')

        self.range_entry_frame.grid(row=0,column=1,sticky='new')
        self.footer_frame.grid(row=2,columnspan=2,sticky='ew')
        self.button_frame_outer.columnconfigure(0, minsize=200, weight=1)
        self.button_frame_outer.rowconfigure(0, weight=1)

    def init_rule_widgets(self):
        self.scrollbar = Scrollbar(self.text_entry_frame)
        self.text_entry = Text(self.text_entry_frame, width=40, height=33, wrap="word",
                   yscrollcommand=self.scrollbar.set, bg='#DDDECE',
                   borderwidth=0, highlightthickness=0)
        self.text_entry.delete('1.0', END)
        self.text_entry.grid(row=0,column=0,padx=2,pady=2)

        self.text_entry.bind('<Control-Tab>',self.text_tab)
        self.text_entry.bind('<Control-Shift-Tab>',self.text_tab)

        self.scrollbar.grid(row=0,column=1,sticky='ns')

        self.low_range_label = Label(self.range_entry_frame, text='Low Range',background=self.bg_color,fg='#ffffff')
        self.low_range_label.grid(row=0, column=0,sticky='e')
        self.low_range_entry = Entry(self.range_entry_frame, background='#DDDECE')
        self.low_range_entry.grid(row=0,column=1)

        self.hi_range_label = Label(self.range_entry_frame, text='High Range',background=self.bg_color,fg='#ffffff')
        self.hi_range_label.grid(row=1, column=0,sticky='e')
        self.hi_range_entry = Entry(self.range_entry_frame, background='#DDDECE')
        self.hi_range_entry.grid(row=1,column=1)        

    def init_footer_buttons(self):
        self.new_rule_button = Button(self.footer_frame, width=10, height=1, padx=2, pady=1, name='new button',
                                 bg=self.bg_color, fg='#ffffff', bd=1, text='New', command=self.new_rule)
        self.footer_frame.grid_columnconfigure(2, weight=0)
        self.new_rule_button.grid(row=0,column=0,sticky='w')

        self.delete_rule_button = Button(self.footer_frame, width=10, height=1, padx=2, pady=1, name='delete button',
                                 bg=self.bg_color, fg='#ffffff', bd=1, text='Delete', command=self.delete_rule)
        self.footer_frame.grid_columnconfigure(2, weight=0)
        self.delete_rule_button.grid(row=0,column=1,sticky='w')

        self.exit_button = Button(self.footer_frame, width=10, height=1, padx=2, pady=1, name='exit_button',
                                 bg=self.bg_color, fg='#ffffff', bd=1, text='Exit', command=self.exit)
        self.footer_frame.grid_columnconfigure(2, weight=1)
        self.exit_button.grid(row=0,column=3,sticky='e')

        self.save_button = Button(self.footer_frame, width=10, height=1, padx=2, pady=1, name='save button',
                                 bg=self.bg_color, fg='#ffffff', bd=1, text='Save', command=self.save_rule)
        self.footer_frame.grid_columnconfigure(2, weight=1)
        self.save_button.grid(row=0,column=4,sticky='e')

    def add_rule_button(self,rule):
        self.rule_dict[rule].rule_button = Button(self.button_frame, name='b'+rule, width=30, height=1, justify=LEFT, padx=0, pady=2,
                                                  font=('Arial', 9), fg='#ffffff',bg='#134E9C', bd=0, anchor='nw',text=rule,
                                                  highlightcolor='#134E9C',command=lambda r=rule: self.fill_text_entry_window(r))
        self.rule_dict[rule].rule_button.grid(row=self.rule_dict[rule].button_row,column=0,sticky='n')

        self.rule_dict[rule].rule_button.bind('<Tab>',self.button_tab)
        self.rule_dict[rule].rule_button.bind('<Shift-Tab>',self.button_tab)
        self.rule_dict[rule].rule_button.bind('<Return>',self.focus_text_entry)
        self.rule_dict[rule].rule_button.bind('<Right>',self.focus_text_entry)
        self.rule_dict[rule].rule_button.bind('<Up>',self.button_uparrow)
        self.rule_dict[rule].rule_button.bind('<Down>',self.button_downarrow)


    ''' init.  call the methods to build the window, set the active button and call mainloop '''
    def __init__(self):      

        self.init_window_and_frames()
        self.init_rule_widgets()
        self.init_footer_buttons()

        self.rule_dict,self.rule_index = build_rules()
        for rule in self.rule_dict:
            self.add_rule_button(rule)

        self.active_index = 0
        self.active_rule = None
        self.fill_text_entry_window(self.rule_index[self.active_index])

        self.win.mainloop()

    ''' methods to process activity from the widgets '''
    @classmethod
    def new_rule(cls):
        print('new rule - Not written yet')

    @classmethod
    def delete_rule(cls):
        print('delete rule - Not written yet')

    @classmethod
    def exit(cls):
        print('exit - Not written yet')

    @classmethod
    def save_rule(cls):
        print('save - Not written yet')

    ''' process keyboard events'''
    def button_uparrow(self,event):
        if self.active_index==0:
            next_rule=self.rule_index[len(self.rule_index)-1]
        else:
            next_rule=self.rule_index[self.active_index-1]
        self.fill_text_entry_window(next_rule)

    def button_downarrow(self,event):
        if self.active_index+1==len(self.rule_index):
            next_rule=self.rule_index[0]
        else:
            next_rule=self.rule_index[self.active_index+1]
        self.fill_text_entry_window(next_rule)

    def button_tab(self,event):
        '''
        make the next button active
        event.state == 9 means the <shift> key is pressed.  8 is shift key is not pressed
        '''
        if event.state == 9:
            if self.active_index==0:
                next_rule=self.rule_index[len(self.rule_index)-1]
            else:
                next_rule=self.rule_index[self.active_index-1]
        else:
            if self.active_index==self.active_index==len(self.rule_index)-1:
                next_rule=self.rule_index[0]
            else:
                next_rule=self.rule_index[self.active_index+1]

        self.fill_text_entry_window(next_rule)

    def focus_text_entry(self,event):
        self.text_entry_frame.focus_set()
        self.text_entry.focus()

    def text_tab(self,event):
        '''
        process control-tab, control-shift-tab key combinations from text_entry widget.  
        Attempts to set focus back to the active button
         *** doesn't work
        '''
        self.update_rule()

        self.win.focus_set()
        active_rule=self.rule_index[self.active_index]
        self.footer_frame.tkraise()
        self.range_entry_frame.tkraise()
        ''' self.button_frame_outer.tkraise() '''
        self.button_frame.focus_force()
        self.button_frame.tkraise()
        self.button_frame_outer.tkraise()
        self.button_frame.focus_force()
        self.rule_dict[active_rule].rule_button.focus_force()
        self.rule_dict[active_rule].rule_button.focus_set()
        self.rule_dict[active_rule].rule_button.focus()
        self.fill_text_entry_window(active_rule)

    def fill_text_entry_window(self,selected_rule):
        if self.active_rule is None:
            self.active_rule = selected_rule
        elif self.active_rule is not selected_rule:
            self.update_rule()

        ''' remove highlight from the old button.  Add highlight to the new one '''
        self.rule_dict[self.active_rule].rule_button.config(bg='#134E9C',fg='#ffffff')
        self.active_rule = self.rule_dict[selected_rule].rule
        self.active_index = self.rule_dict[selected_rule].button_row
        self.rule_dict[self.active_rule].rule_button.config(bg='#ffffff',fg='#134E9C')

        ''' clear the entry widgets and add the information for the new button '''
        self.low_range_entry.delete(0,END)
        self.low_range_entry.insert(0,self.rule_dict[self.active_rule].low_range)
        self.hi_range_entry.delete(0,END)
        self.text_entry.delete('1.0', END)
        self.hi_range_entry.insert(0,self.rule_dict[self.active_rule].hi_range)
        for word in self.rule_dict[self.active_rule].word_list:
            self.text_entry.insert('insert', word+'\n')

        ''' *** attempt to set the focus on the new button. '''
        self.rule_dict[self.active_rule].rule_button.focus()
        self.rule_dict[self.active_rule].rule_button.focus_set()
        self.rule_dict[self.active_rule].rule_button.focus_force()

    def update_rule(self):
        ''' save any changes made to the active rule before changing to the next one '''
        self.rule_dict[self.active_rule].word_list = sorted(self.text_entry.get(1.0,END).rstrip().split('\n'))
        self.rule_dict[self.active_rule].hi_range = decimal.Decimal(self.hi_range_entry.get())
        self.rule_dict[self.active_rule].low_range = decimal.Decimal(self.low_range_entry.get())


if __name__ == '__main__':    
    rule_entry_window()
从tkinter导入*
输入小数
类类别规则():
定义初始(自身、高范围、低范围、单词列表、规则、行):
self.hi\u范围=十进制.decimal(hi\u范围)
self.low\u范围=十进制.decimal(low\u范围)
self.word\u list=已排序(word\u list)
自治
self.button_row=行
self.rule_按钮=无
self.rule\u entry\u window=None
def build_规则():
规则_dict={}
规则_索引={}
单词=[]
规则‘水果’
单词=[“苹果”、“香蕉”、“草莓”]
行=0
规则[规则]=类别规则('9999.99','0.00',单词,规则,行)
规则\索引[行]=规则
规则=‘蔬菜’
单词=[‘芦笋’、‘布鲁塞尔芽’、‘甘蓝’、‘西红柿’、‘菠菜’]
行=1
规则[规则]=类别规则('9999.99','0.00',单词,规则,行)
规则\索引[行]=规则
规则=‘甜点’
单词=[‘蛋糕’、‘布丁’、‘饼干’、‘馅饼’]
行=2
规则[规则]=类别规则('9999.99','0.00',单词,规则,行)
规则\索引[行]=规则
返回规则目录,规则索引
类规则\u条目\u窗口:
活动索引=0
活动规则=无
第一条规则=无
按钮行=0
规则_dict={}
规则_索引={}
''创建窗口、构建框架和添加小部件的方法''
def初始窗口和框架(自):
self.win=Tk()
self.bg_color='#134E9C'
self.text_entry_frame=frame(self.win,width=150,height=380,bg='#DDDECE',padx=1,pady=1,borderwidth=1)
self.button\u frame\u outer=frame(self.win,宽度=150,高度=300,bg=self.bg\u颜色,padx=3,pady=3,borderwidth=1)
self.button\u frame=frame(self.button\u frame\u外部,宽度=150,高度=300,bg=self.bg\u颜色,padx=3,pady=3,borderwidth=1)
self.range\u entry\u frame=frame(self.win,宽度=150,高度=40,bg=self.bg\u颜色,padx=3,pady=3,borderwidth=1)
self.footer\u frame=frame(self.win,宽度=480,高度=30,bg=self.bg\u颜色,padx=3,pady=3,borderwidth=1)
self.button\u frame.grid(行=0,列=0,sticky='nesw')
self.button\u frame\u outer.grid(行span=2,列=0,sticky='nsew')
self.text\u entry\u frame.grid(行=1,列=1,sticky='s')
self.range\u entry\u frame.grid(行=0,列=1,sticky='new')
self.footer\u frame.grid(行=2,列span=2,sticky='ew')
self.button\u frame\u outer.columnconfigure(0,minsize=200,weight=1)
self.button\u frame\u outer.rowconfigure(0,权重=1)
def init_rule_小部件(自):
self.scrollbar=滚动条(self.text\u entry\u frame)
self.text\u entry=text(self.text\u entry\u框架,宽度=40,高度=33,wrap=“word”,
yscrollcommand=self.scrollbar.set,bg='#DDDECE',
borderwidth=0,highlightthickness=0)
self.text\u entry.delete('1.0',END)
self.text_entry.grid(行=0,列=0,padx=2,pady=2)
self.text\u entry.bind(“”,self.text\u选项卡)
self.text\u entry.bind(“”,self.text\u选项卡)
self.scrollbar.grid(行=0,列=1,sticky='ns')
self.low_range_label=label(self.range_entry_frame,text='low range',background=self.bg_color,fg='#ffffffff')
self.low\u range\u label.grid(行=0,列=0,sticky='e')
self.low_range_entry=entry(self.range_entry_frame,background='#DDDECE')
self.low\u range\u entry.grid(行=0,列=1)
self.hi_range_label=label(self.range_entry_frame,text='High range',background=self.bg_color,fg='#ffffffff')
self.hi\u range\u label.grid(行=1,列=0,sticky='e')
self.hi_range_entry=entry(self.range_entry_frame,background='#DDDECE')
self.hi\u range\u entry.grid(行=1,列=1)
def初始页脚按钮(自身):
self.new\u rule\u button=button(self.footer\u框架,宽度=10,高度=1,padx=2,pady=1,name='new button',
bg=self.bg_颜色,fg='#ffffff',bd=1,text='New',command=self.New_规则)
self.footer\u frame.grid\u column配置(2,权重=0)
self.new\u rule\u button.grid(行=0,列=0,sticky='w')
self.delete\u rule\u button=按钮(self.footer\u框架,宽度=10,高度=1,padx=2,pady=1,name='delete button',
bg=self.bg_color,fg='#ffffff',bd=1,text='Delete',command=self.Delete_规则)
self.footer\u frame.grid\u column配置(2,权重=0)
self.delete\u rule\u button.grid(行=0,列=1,sticky='w')
self.exit_button=按钮(self.footer_框架,宽度=10,高度=1,padx=2,pady=1,name='exit_button',
bg=self.bg_color,fg='#ffffff',bd=1,text='Exit',command=self.Exit)
self.footer\u frame.grid\u column配置(2,权重=1)
self.exit_button.grid(行=0,列=3,粘滞=e')
self.save_button=按钮(self.footer_框架,宽度=10,高度=1,padx=2,pady=1,name='save button',
bg=self.bg_颜色,fg='#ffffff',bd=1,text='Save',command=self.Save_规则)
self.footer\u frame.grid\u column配置(2,权重=1)
self.save_button.grid(行=0,列=4,sticky='e')
def添加规则按钮(自身、规则):
self.rule\u dict[rule].rule\u button=button(self.button\u框架,name='b'+规则,宽度=30,高度=1,对齐=LEFT,padx=0,pady=2,
font=('Arial',9),fg='ffffff',bg='134E9C',bd=0,anchor='nw',text=rule,
highlightcolor='#134E9C',command=lambda r=rule:self.fill\u text\u en
 def text_tab(self, event):

     # ... code ...

     return "break"