首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tkinter滚动条未更新以覆盖扩展画布

Tkinter滚动条未更新以覆盖扩展画布
EN

Stack Overflow用户
提问于 2022-09-06 20:59:06
回答 2查看 60关注 0票数 0

我正在创建的Tkinter GUI有一个滚动条问题。图形用户界面包含一个类Gen_Box,它垂直向下再现一个给定的小部件,其次数与调用小部件add_btn的次数一样多。显然,这很快就离开了窗框。

我已经尝试添加一个滚动条来解释这个运行在框架之外的原因。我知道这些都是相当复杂的添加tkinter,并需要一些黑客。我参考了科迪的这段视频。虽然我可以看到框架右侧的滚动条,但它并不能容纳添加的小部件(见下面的屏幕截图)。我一整天都在摆弄这件事,但却不知所措。

起始框架:

添加第二个Monitor小部件后的帧:

另外,我还使用CustomTkinter对小部件进行了样式化。

当前代码。在Form.__init__()函数中设置滚动条。在这个问题上的任何帮助或在这里的其他投入是非常感谢的。

代码语言:javascript
复制
class Form(tk.Frame):
    def __init__(self, root):
        self.root = root

        self.main_frame = tk.Frame(self.root)
        self.main_frame.grid(sticky='NSEW')
        
        self.canvas = tk.Canvas(self.main_frame, height=750, width=750)
        self.canvas.grid(row=0, column=0, sticky='NSEW')
        self.canvas.grid_rowconfigure(0, weight=1)

        self.scrollbar = tk.Scrollbar(self.main_frame, orient=VERTICAL)
        self.scrollbar.config(command=self.canvas.yview)
        self.scrollbar.grid(row=0, column=1, sticky='NSE')

        self.canvas.config(yscrollcommand=self.scrollbar.set)
        self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox(ALL)))

        self.inner_frame = tk.Frame(self.canvas)
        self.canvas.create_window((0,0), window=self.inner_frame, anchor='nw')        
        self.load()
        

    def load(self):
        self.right = ctk.CTkFrame(self.inner_frame, bg_color='#09275d', fg_color='#09275d', height=750, width=750)
        

        basics_label = ctk.CTkLabel(self.right, text='Setup', text_font=('Helvetica', 24), text_color='#f5d397')
        basics_label.grid(row=0, column=0, sticky='NW', pady=10)
        name_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d')
        name_frame.grid(row=1, columnspan=2, sticky=NW,pady=5)
        name_label = ctk.CTkLabel(name_frame, text='Name', text_font=("MS Sans Serif", 15))
        name_label.grid(row=1, column=0, padx=2, pady=2, sticky=NW)
        name_entry = ctk.CTkEntry(name_frame, width=250, border_width=1, corner_radius=10)
        name_entry.grid(row=1, column=1, padx=2, pady=2)

        start_frame = ctk.CTkFrame(self.right, corner_radius=2, fg_color='#E4E7F1', bg_color='#09275d')
        start_frame.grid(row=2, columnspan=2, sticky=NW,pady=5)
        start_url_label = ctk.CTkLabel(start_frame, text='Start URL', text_font=("MS Sans Serif", 15))
        start_url_label.grid(row=2, column=0, sticky=NW, pady=2, padx=2)
        start_urls_frame = ctk.CTkFrame(start_frame, fg_color='#E4E7F1', bg_color='#09275d')
        start_urls_frame.grid(row=2, column=1, pady=2, padx=2)
        start_urls = Gen_Box(start_urls_frame, Include)

        include_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d', corner_radius=5)
        include_frame.grid(row=3, columnspan=2, sticky=NW,pady=5)
        include_url_label = ctk.CTkLabel(include_frame, text='Include URL', text_font=("Myriad", 15))
        include_url_label.grid(row=3, column=0, sticky=NW, padx=2, pady=2)
        include_url_entry = ctk.CTkFrame(include_frame, fg_color='#E4E7F1', bg_color='#09275d')
        include_url_entry.grid(row=3, column=1, columnspan=2, padx=2, pady=2)
        url_patterns = Gen_Box(include_url_entry, Include)

        depth_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d', corner_radius=5)
        depth_frame.grid(row=4, columnspan=2, sticky=NW, pady=5)
        depth_label = ctk.CTkLabel(depth_frame, text='Max Depth', text_font=("Myriad", 15))
        depth_label.grid(row=4, column=0, sticky=NW, padx=2, pady=2)
        depth_level = ctk.IntVar(depth_frame)
        depth_level.set(1)
        depth_options = ctk.CTkOptionMenu(master=depth_frame, variable=depth_level, values=[str(i) for i in range(1,11)], fg_color='white', button_color='#6AA6DE', width=25, corner_radius=10)
        depth_options.grid(row=4, column=1, sticky=NW, padx=2, pady=2)

        profile_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d', corner_radius=5)
        profile_frame.grid(row=5, columnspan=2, sticky=NW, pady=5)
        profile_label = ctk.CTkLabel(profile_frame, text='Chrome Profile', text_font=("Myriad", 15))
        profile_label.grid(row=5, column=0, sticky=NW, padx=2, pady=2)
        profile_level = ctk.StringVar(profile_frame)
        profile_level.set('False')
        profile_options = ctk.CTkOptionMenu(master=profile_frame, variable=profile_level, values=['True', 'False'], fg_color='white', button_color='#6AA6DE', width=25, corner_radius=10)
        profile_options.grid(row=5, column=1, sticky=NW, padx=2, pady=2)

        headless_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d', corner_radius=5)
        headless_frame.grid(row=6, columnspan=2, sticky=NW, pady=5)
        headless_label = ctk.CTkLabel(headless_frame, text='Headless', text_font=("Myriad", 15))
        headless_label.grid(row=6, column=0, sticky=NW, padx=2, pady=2)
        headless_level = ctk.StringVar(headless_frame)
        headless_level.set('True')
        headless_options = ctk.CTkOptionMenu(master=headless_frame, variable=headless_level, values=['True', 'False'], fg_color='white', button_color='#6AA6DE', width=25, corner_radius=10)
        headless_options.grid(row=6, column=1, sticky=NW, padx=2, pady=2)

        delay_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d', corner_radius=5)
        delay_frame.grid(row=7, columnspan=2, sticky=NW, pady=5)
        delay_label = ctk.CTkLabel(delay_frame, text='Delay', text_font=("Myriad", 15))
        delay_label.grid(row=7, column=0, sticky=NW, padx=2, pady=2)
        delay_level = ctk.IntVar(delay_frame)
        delay_level.set(0)
        delay_options = ctk.CTkOptionMenu(master=delay_frame, variable=delay_level, values=[str(i) for i in range(1,11)], fg_color='white', button_color='#6AA6DE', width=25, corner_radius=10)
        delay_options.grid(row=7, column=1, sticky=NW, padx=2, pady=2)

        download_frame = ctk.CTkFrame(self.right, fg_color='#E4E7F1', bg_color='#09275d')
        download_frame.grid(row=8, columnspan=2, sticky=NW,pady=5)
        download_label = ctk.CTkLabel(download_frame, text='Download Path', text_font=("MS Sans Serif", 15))
        download_label.grid(row=8, column=0, padx=2, pady=2, sticky=NW)
        download_entry = ctk.CTkEntry(download_frame, width=350, border_width=1, corner_radius=10)
        download_entry.grid(row=8, column=1, padx=2, pady=2)

        self.monitors_label = ctk.CTkLabel(self.right, text='Monitors', text_font=('Helvetica', 24), text_color='#f5d397')
        self.monitors_label.grid(sticky='NW', row=9, column=0, pady=10)
        self.monitor_frame = ctk.CTkFrame(self.right, bg_color='#09275d', fg_color='#09275d')
        Gen_Box(self.monitor_frame, Monitor)
        self.monitor_frame.grid(row=10, sticky='NW')

        self.right.grid(row=0)


class Gen_Box:
    def __init__(self, master, gen_obj, existing=None):
        self.master = master
        self.gen_obj = gen_obj
        self.existing = existing
        self.load(existing)

    def load(self, existing=None):
        if existing:
            self.obj_rows = [self.gen_obj(key) for key in existing.keys()]
        else:
            self.obj_rows = [self.gen_obj(0)]

        self.frame = ctk.CTkFrame(self.master, fg_color='#09275d')
        
        for index, obj in enumerate(self.obj_rows):

            add = lambda row=index+1 : self.add(row)
            remove = lambda row=index : self.remove(row)
            obj.row_no = index

            if existing:
                obj.load(self.frame, existing=existing[index])
            else:
                obj.load(self.frame)
            
            obj.add_btn.configure(command=add)
            obj.remove_btn.configure(command=remove)

        self.frame.grid(sticky='NSEW')
        self.master.update()
        

    def add(self, row):
        self.obj_rows.insert(row, self.gen_obj(row))
        existing_entries = self.save_existing()
        self.frame.destroy()
        self.load(existing_entries)


    def remove(self, row):
        self.obj_rows.pop(row)
        existing_entries = self.save_existing()
        self.frame.destroy()
        self.load(existing_entries)
        

    def save_existing(self):
        existing_dict = {}

        for index, object in enumerate(self.obj_rows):
            try:
                existing_dict[index] = object.generate_scheme()
            except AttributeError as e:
                existing_dict[index] = None

        return existing_dict


class Monitor:
    def __init__(self, row_no):
        self.row_no = row_no

    def generate_scheme(self):
        return_dict = {}
        scheme_dict = {
                'output': self.output.get,
                'includes': self.includes.save_existing,
                'selectors': self.selectors.save_existing
        }

        for key, value in scheme_dict.items():
            return_dict[key] = value()

        return return_dict

    
    def load(self, frame, existing=None):
        self.monitor_frame = ctk.CTkFrame(frame, fg_color='#E4E7F1', bg_color='#09275d')
        
        self.button_frame = ctk.CTkFrame(frame, bg_color='#09275d', fg_color='#09275d')
        self.button_frame.grid(row=self.row_no, column=1, sticky='NSEW', pady=10, padx=2)
        
        self.add_btn = ctk.CTkButton(self.button_frame, text='+', corner_radius=2, width=50, height=50, fg_color='#ecae3e')
        self.add_btn.grid(row=self.row_no, column=0, padx=10)
        self.remove_btn = ctk.CTkButton(self.button_frame, text='-', corner_radius=2, width=50, height=50, fg_color='#ecae3e')
        self.remove_btn.grid(row=self.row_no, column=1, padx=10)

        self.top_frame = ctk.CTkFrame(self.monitor_frame)
        self.top_frame.grid(sticky='NSEW', pady=10, padx=10)
        self.include_frame = ctk.CTkFrame(self.top_frame, fg_color='#E4E7F1', bg_color='#E4E7F1')
        self.include_frame.grid(row=0, sticky='NSEW')
        self.include_label = ctk.CTkLabel(self.include_frame, text='Include URLs', text_font=("Myriad", 15))
        self.include_label.grid(row=0, sticky='NW')
        if not existing:
            self.includes = Gen_Box(self.include_frame, Include)
        else:
            self.includes = Gen_Box(self.include_frame, Include, existing=existing['includes'])

        self.selector_frame = ctk.CTkFrame(self.top_frame, fg_color='#E4E7F1', bg_color='#E4E7F1')
        self.selector_frame.grid(row=1, sticky='NSEW')
        self.selector_label = ctk.CTkLabel(self.selector_frame, text='Selectors (Optional)', text_font=("Myriad", 15))
        self.selector_label.grid(row=1, sticky='NW')
        if not existing:
            self.selectors = Gen_Box(self.selector_frame, Include)
        else:
            self.selectors = Gen_Box(self.selector_frame, Include, existing=existing['selectors'])

        self.output_frame = ctk.CTkFrame(self.monitor_frame, fg_color='#E4E7F1', bg_color='#E4E7F1')
        self.output_frame.grid(row=2, pady=5, padx=2, sticky='NSEW', columnspan=2)
        self.output_label = ctk.CTkLabel(self.output_frame, text='Output', text_font=("Myriad", 15))
        self.output_label.grid(row=2, column=0)
        self.output = ctk.StringVar(self.output_frame)
        if existing:
            self.output.set(existing['output'])
        else:
            self.output.set('TXT')
        self.output_options = ['TXT', 'PDF']
        self.output_menu = ctk.CTkOptionMenu(self.output_frame, variable=self.output, values=self.output_options, fg_color='white', button_color='#6AA6DE', width=25, corner_radius=10)
        self.output_menu.grid(row=2, column=1)

        self.actions_frame = ctk.CTkFrame(self.monitor_frame, bg_color='#E4E7F1', fg_color='#E4E7F1')
        self.actions_frame.grid(row=3, pady=5)
        self.add_actions_btn = ctk.CTkButton(self.actions_frame, text='Actions Editor ▼', text_font=("Myriad", 10), fg_color='#3eecae', corner_radius=10)
        self.add_actions_btn.grid(sticky='NSEW')
        self.add_actions_btn.configure(width=self.actions_frame.winfo_width())

        self.monitor_frame.grid(row=self.row_no, pady=10, padx=10)
        frame.update()



class Include:
    def __init__(self, row_no):
        self.row_no = row_no

    def generate_scheme(self):
        return_dict = {}
        scheme_dict = {
            'entry': self.entry.get
        }

        for key, value in scheme_dict.items():
            return_dict[key] = value()

        return return_dict

    def load(self, master, existing=None):
        entry_frame = ctk.CTkFrame(master, bg_color='#E4E7F1', fg_color='#E4E7F1')
        self.entry = ctk.CTkEntry(entry_frame, corner_radius=10, border_width=1, width=300, bg_color='#E4E7F1')
        if existing:
            self.entry.insert(END, existing['entry'])
        self.entry.grid(row=self.row_no, column=0, pady=2, ipadx=2, sticky=NSEW)        
        button_frame = ctk.CTkFrame(master, bg_color='#E4E7F1', fg_color='#E4E7F1')
        self.add_btn = ctk.CTkButton(button_frame, text='+', height=10, width=10, corner_radius=5, text_font=("Helvetica", 12), fg_color='#6AA6DE', bg_color='#E4E7F1', text_color='#E4E7F1')
        self.add_btn.grid(row=self.row_no, column=1, padx=3, pady=5)
        self.remove_btn = ctk.CTkButton(button_frame, text='-', height=10, width=10, corner_radius=5, text_font=("Helvetica", 12), fg_color='#6AA6DE', bg_color='#E4E7F1', text_color='#E4E7F1')
        self.remove_btn.grid(row=self.row_no, column=2, padx=3, pady=5)
        entry_frame.grid(row=self.row_no, column=0, sticky='NSEW')
        button_frame.grid(row=self.row_no, column=1, sticky='NSEW')




            




root = ctk.CTk()
root.configure(bg='#09275d')
root.geometry('1000x650')
Form(root)
root.mainloop()

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-09-07 00:52:40

当添加一个新的监视器部分时,它是内部框架(self.inner_frame)被调整大小,而不是画布(self.canvas)。因此,<Configure>事件应该绑定在内部框架上,而不是画布上:

代码语言:javascript
复制
class Form(tk.Frame):
    def __init__(self, root):
        ...
        self.canvas.config(yscrollcommand=self.scrollbar.set)
        ### ----- don't bind on canvas
        #self.canvas.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox(ALL)))

        self.inner_frame = tk.Frame(self.canvas)
        ### ----- bind on inner frame instead
        self.inner_frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox(ALL)))
        self.canvas.create_window((0,0), window=self.inner_frame, anchor='nw')
        self.load()

    ...
票数 1
EN

Stack Overflow用户

发布于 2022-09-06 21:10:14

尝试修改滚动区域。参见https://dafarry.github.io/tkinterbook/canvas.htm上的示例,该示例使用event.x和event.y来获取大小。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73627693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档