Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么tkinter grid、columnconfigure和rowconfigure值不动态更改?_Python_Python 3.x_Tkinter - Fatal编程技术网

Python 为什么tkinter grid、columnconfigure和rowconfigure值不动态更改?

Python 为什么tkinter grid、columnconfigure和rowconfigure值不动态更改?,python,python-3.x,tkinter,Python,Python 3.x,Tkinter,请帮助任何人 您可以以内联注释的形式阅读所有详细信息 我创建了三个类LeftFrame,RightFrame,DynamicWindow 在DynamicWindow中,我继承了RightFrame 第一步 LeftFrame,在第0列中,使用minsize 350 步骤2 RightFrame,在第1列中,权重为1,捕获所有可用空间 步骤3 DynamicWindow,ingeriting RightFrame,这里是主要问题,请阅读代码 将tkinter作为tk导入 从win32api导入G

请帮助任何人 您可以以内联注释的形式阅读所有详细信息

我创建了三个类
LeftFrame
RightFrame
DynamicWindow

在DynamicWindow中,我继承了RightFrame

第一步 LeftFrame,在第0列中,使用minsize 350

步骤2 RightFrame,在第1列中,权重为1,捕获所有可用空间

步骤3 DynamicWindow,ingeriting RightFrame,这里是主要问题,请阅读代码

将tkinter作为tk导入
从win32api导入GetMonitorInfo、MonitorFromPoint
root=tk.tk()
monitor_info=GetMonitorInfo(MonitorFromPoint((0,0))['Work']
几何体(f'{monitor\u info[2]}x{monitor\u info[3]})
root.state('缩放')
root.columnconfigure(0,minsize=350)#左帧宽度
root.columnconfigure(1,weight=1)#右框架的所有可用空间
root.rowconfigure(0,weight=1)#两帧的全屏高度
类LeftFrame(tk.Frame):
"""
左框
"""
定义初始化(自身,容器):
super().\uuuu init\uuuu(容器)
self.config(bg='red')
self.grid(行=0,列=0,sticky='nsew')
类RightFrame(传统框架):
"""
右框:
分为三节头架、中间架和底部架
头部框架包含按钮
中间帧包含动态可变帧。我现在面临的问题是,
框架无法根据我给出的重量和尺寸来确定实际尺寸。
"""
定义初始化(自身,容器):
super().\uuuu init\uuuu(容器)
self.columnconfigure(0,权重=1)
self.rowconfigure(0,minsize=30)
self.rowconfigure(1,权重=1)
self.rowconfigure(2,minsize=30)
self.config(bg='green')
self.grid(行=0,列=1,sticky='nsew')
self.head\u frame=tk.frame(self,bg='orange')
self.head\u frame.grid(行=0,列=0,sticky='nsew')
self.head\u frame.rowconfigure(0,权重=1)
self.first\u screen\u button=tk.button(self.head\u框架,text='first screen')
self.first\u screen\u button.grid(行=0,列=0,sticky='nsew',ipadx=20)
self.second\u screen\u button=tk.button(self.head\u框架,text='second screen')
self.second\u screen\u button.grid(行=0,列=1,sticky='nsew',ipadx=20)
self.middle_frame=tk.frame(self,bg='green')
self.middle_frame.grid(行=1,列=0,sticky='nsew')
self.bottom_frame=tk.frame(self,bg='orange')
self.bottom\u frame.grid(行=2,列=0,sticky='nsew')
类DynamicWindow(右框架):
定义初始化(自身,容器):
super().\uuuu init\uuuu(容器)
self.first\u screen\u button.config(命令=self.first\u screen)
self.second\u screen\u button.config(命令=self.second\u screen)
self.first_screen()#我在这里打电话是因为第一次点击第一个屏幕按钮
#窗口不显示。您可以通过注释检查此代码。
#谁能告诉我为什么第一次点击时第一个屏幕没有出现。
def第一屏幕(自):
"""
单击按钮时要显示的第一个屏幕
它有两个框架
"""
对于self.middle_frame.winfo_children()中的小部件:
#要销毁中间帧中所有可用的小部件吗
widget.destroy()
self.middle\u frame.columnconfigure(0,权重=1)
#正在配置大小和重量,但无法正常工作
self.middle\u frame.columnconfigure(1,minsize=30)
self.middle\u frame.rowconfigure(0,权重=1)
self.middle_frame.rowconfigure(1,权重=0)
主图表窗口=tk.Frame(self.middle_Frame,bg='#4d')
main\u chart\u window.grid(行=0,列=0,sticky='nsew')
工具栏=tk.Frame(self.middle\u Frame,bg='red')
toolbar.grid(行=0,列=1,sticky='nsew')
def第二屏幕(自身):
"""
这是不正确的工作方式
我无法重新配置中间框架的重量
我想让这个窗口在中间的全屏幕上
在这里,你会注意到第1列使用minsize 30,有人能解决这个问题吗
"""
对于self.middle_frame.winfo_children()中的小部件:
widget.destroy()
self.middle\u frame.columnconfigure(0,权重=1)
self.middle\u frame.rowconfigure(0,权重=1)
第二个屏幕窗口=tk.Frame(self.middle\u Frame,bg='purple')
第二个\u screen\u window.grid(行=0,列=0,sticky='nsew')
左框架=左框架(根)
动态窗口=动态窗口(根)
root.mainloop()

我为你做了一切。我对使用您的代码/方法失去了兴趣,因此,我完全从头重写了代码,并设计了一种不同的方法。您强调的所有问题都已解决。我的代码结构应该更易于使用。主要问题是您正在销毁子项,但没有销毁子项所在的
和/或
。你基本上不能。使用
grid\u-forget()
即使与
destroy()
grid\u-remove()
结合使用,似乎也无法删除网格单元

更改:

  • 每个主要的小部件都被划分为自己的类
  • 名称已更改,以反映每个小部件的实际用途(根据您的示例,尽我所能)
  • 我们通过删除/重新安装整个小部件来交换“主显示”小部件,而不是销毁/重新创建它的所有子部件
  • 按钮
    命令中使用
    lambda
    将所需的“主显示”传递给执行交换的方法
  • 我们从不使用
    super()
    实例化类。我们通过类名专门引用super
  • 所有的
    args
    kwargs
    都是维护的,因此我们可以像对待超级用户一样对待我们的定制小部件
  • from tkinter import Frame, Button
    from typing import List, Dict, Callable
    from dataclasses import dataclass
    
    
    #a simple "typedef" for storing menu button data
    @dataclass
    class MenuData_t:
        func:Callable        #method the command lambda will call
        buttons:List[Dict]   #Button(**kwargs)
        targets:List[Frame]  #'main display' to switch to
        griddata:List[Dict]  #.grid(**kwargs)
    
    
    '''
    this replaces your 'head_frame'
    it also provides an interface to concoct all of the buttons that will swap 'main displays'
    if you need other types of buttons you will need to manually create them in __init__
    considerations have been made in init_displayswap_menu for existing buttons
    '''
    class MenuFrame(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
        def init_displayswap_menu(self, md:MenuData_t):
            c = len(self.winfo_children())
            for i, (b, t, g) in enumerate(zip(md.buttons, md.targets, md.griddata)):
                self.__dict__[f'swap_btn{i+1}'] = Button(self, command=lambda m=t: md.func(m), **b)
                self.__dict__[f'swap_btn{i+1}'].grid(row=0, column=i+c, **g)
    
    
    #this replaces your "bottom_frame"
    class Footer(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
    
    #this replaces your "first_screen"
    class PrimaryFrame(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
            self.chart   = Frame(self, bg='#4d4d4d')
            self.chart.grid(row=0, column=0, sticky='nswe')
    
            self.toolbar = Frame(self, bg='red')
            self.toolbar.grid(row=0, column=1, sticky='nswe')
    
            self.grid_columnconfigure(0, weight=1)
            self.grid_columnconfigure(1, minsize=30)
            self.grid_rowconfigure(0, weight=1)
    
    
    #this replaces your "second_screen"
    class SecondaryFrame(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
    
    #this replaces your "LeftFrame"
    class Sidebar(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
    
    #this replaces your "RightFrame" AND "DynamicWindow"
    class MainFrame(Frame):
        def __init__(self, master, *args, **kwargs):
            Frame.__init__(self, master, *args, **kwargs)
    
            ##INSTANTIATE
            #menu
            self.menu = MenuFrame(self, bg='orange')
            self.menu.grid(row=0, column=0, sticky='nsew')
    
            #main display
            self.current   = None #for storing currently used 'main display'
    
            self.primary   = PrimaryFrame(self, bg='green')
            self.secondary = SecondaryFrame(self, bg='purple')
    
            #footer
            self.footer = Footer(self, bg='orange')
            self.footer.grid(row=2, column=0, sticky='nsew')
    
            ##UTILIZE
            #concoct main display swap menu
            '''    
            append accordingly to the 3 lists to create more buttons that will switch frames
            done this way so button creation can remain in MenuFrame but use remote data
            row, column and command are managed in MenuFrame
            '''
            self.menu.init_displayswap_menu(MenuData_t(
                self.main_display,              #method the command lambda will call
                [{'text':'Primary'},            #Button(**kwargs)
                 {'text':'Secondary'},
                ],
                [self.primary,                  #'main display' to switch to
                 self.secondary,
                ],
                [{'sticky':'nswe','ipadx':20},  #.grid(**kwargs)
                 {'sticky':'nswe','ipadx':20},
                ]
            ))
    
            #init main display
            '''
            I could have called main_display directly but this illustrates 2 things
            1: how to virtually click a button
            2: how to access the buttons that MenuFrame created in it's __dict__
            '''
            self.menu.swap_btn1.invoke()
    
            #configure grid
            self.grid_columnconfigure(0, weight=1)
            self.grid_rowconfigure(0, minsize=30)
            self.grid_rowconfigure(1, weight=1)
            self.grid_rowconfigure(2, minsize=30)
    
        #replaces your 'first_screen' AND 'second_screen' methods
        def main_display(self, frame):
            if self.current is not frame:       #only swap if we aren't requesting the current 'main display'
                if self.current: 
                    self.current.grid_remove()  #remove current from the grid, instead of destroy
        
                self.current = frame            #set new current and add it to the grid
                self.current.grid(row=1, column=0, sticky='nsew')
     
    
    from win32api import GetMonitorInfo, MonitorFromPoint
    from widgets import Sidebar, MainFrame
    from tkinter import Tk
    
    
    #This is your "root"
    class Application(Tk):
        def __init__(self, *args, **kwargs):
            Tk.__init__(self, *args, **kwargs)
    
            Sidebar(self, bg='red').grid(row=0, column=0, sticky='nswe')
            MainFrame(self, bg='black').grid(row=0, column=1, sticky='nswe')
    
            #configure grid
            self.grid_columnconfigure(0, minsize=350)
            self.grid_columnconfigure(1, weight=1)
            self.grid_rowconfigure(0, weight=1)
    
    
    #kick off the entire app with proper PEP8
    if __name__ == '__main__':
        monitor_info = GetMonitorInfo(MonitorFromPoint((0, 0)))['Work']
    
        app = Application()
        app.title("Manish Pushpam's Bad-Ass Application")
        app.geometry(f'{monitor_info[2]}x{monitor_info[3]}')
        app.minsize(800, 600)
        app.mainloop()