[英]Why tkinter grid, columnconfigure and rowconfigure value not changing dynamically?
請幫助任何人您可以閱讀所有詳細信息作為內聯評論。
我創建了三個類LeftFrame
, RightFrame
, DynamicWindow
在 DynamicWindow 我繼承 RightFrame
LeftFrame,在第 0 列,最小尺寸為 350
RightFrame,在第 1 列,權重為 1,捕獲所有可用空間
DynamicWindow, ingering RightFrame, 這是主要問題,請閱讀代碼。
import tkinter as tk
from win32api import GetMonitorInfo, MonitorFromPoint
root = tk.Tk()
monitor_info = GetMonitorInfo(MonitorFromPoint((0, 0)))['Work']
root.geometry(f'{monitor_info[2]}x{monitor_info[3]}')
root.state('zoomed')
root.columnconfigure(0, minsize=350) # Width of left frame
root.columnconfigure(1, weight=1) # All available space for right frame
root.rowconfigure(0, weight=1) # Full screen height for both frame
class LeftFrame(tk.Frame):
"""
Left Frame
"""
def __init__(self, container):
super().__init__(container)
self.config(bg='red')
self.grid(row=0, column=0, sticky='nsew')
class RightFrame(tk.Frame):
"""
Right Frame:
Divided into three section head frame, middle frame and bottom frame
head frame contains button
middle frame contains dynamically changeable frame. Here I am facing problem,
frame not able to take actual size according to weight and minsize that I given.
"""
def __init__(self, container):
super().__init__(container)
self.columnconfigure(0, weight=1)
self.rowconfigure(0, minsize=30)
self.rowconfigure(1, weight=1)
self.rowconfigure(2, minsize=30)
self.config(bg='green')
self.grid(row=0, column=1, sticky='nsew')
self.head_frame = tk.Frame(self, bg='orange')
self.head_frame.grid(row=0, column=0, sticky='nsew')
self.head_frame.rowconfigure(0, weight=1)
self.first_screen_button = tk.Button(self.head_frame, text='First Screen')
self.first_screen_button.grid(row=0, column=0, sticky='nsew', ipadx=20)
self.second_screen_button = tk.Button(self.head_frame, text='Second Screen')
self.second_screen_button.grid(row=0, column=1, sticky='nsew', ipadx=20)
self.middle_frame = tk.Frame(self, bg='green')
self.middle_frame.grid(row=1, column=0, sticky='nsew')
self.bottom_frame = tk.Frame(self, bg='orange')
self.bottom_frame.grid(row=2, column=0, sticky='nsew')
class DynamicWindow(RightFrame):
def __init__(self, container):
super().__init__(container)
self.first_screen_button.config(command=self.first_screen)
self.second_screen_button.config(command=self.second_screen)
self.first_screen() # I am calling this here becuase on first click on first screen button
# window don't appear. You can check by comment this code.
# Can anyone please tell me why first screen not appear on first click.
def first_screen(self):
"""
First screen that I want to appear when I click on button
It has two frame
"""
for widget in self.middle_frame.winfo_children():
# Want to destroy all available widget in middle frame
widget.destroy()
self.middle_frame.columnconfigure(0, weight=1)
# Configuring size and weight but this is not working properly
self.middle_frame.columnconfigure(1, minsize=30)
self.middle_frame.rowconfigure(0, weight=1)
self.middle_frame.rowconfigure(1, weight=0)
main_chart_window = tk.Frame(self.middle_frame, bg='#4d4d4d')
main_chart_window.grid(row=0, column=0, sticky='nsew')
toolbar = tk.Frame(self.middle_frame, bg='red')
toolbar.grid(row=0, column=1, sticky='nsew')
def second_screen(self):
"""
This is not working in proper way
I am not able to reconfigure weight of middle frame
I want this window in full screen in middle frame
Here you will notice column 1 taking minsize 30, can anyone solve this
"""
for widget in self.middle_frame.winfo_children():
widget.destroy()
self.middle_frame.columnconfigure(0, weight=1)
self.middle_frame.rowconfigure(0, weight=1)
second_screen_window = tk.Frame(self.middle_frame, bg='purple')
second_screen_window.grid(row=0, column=0, sticky='nsew')
left_frame = LeftFrame(root)
dynamic_window = DynamicWindow(root)
root.mainloop()
我讓這一切都為你工作。 我對使用您的代碼/方法失去了興趣,因此,我從頭開始完全重寫了代碼並設計了一種不同的方法。 您強調的所有問題都已解決。 我的代碼結構應該更容易使用。 主要問題是你正在摧毀孩子,但你沒有摧毀孩子所在的column
和/或row
。你基本上不能。 即使與destroy()
或grid_remove()
grid_forget()
也不會刪除網格單元。
變化:
command
中使用lambda
將所需的“主顯示”傳遞給進行交換的方法super()
來實例化 class。 我們專門通過類名來引用superargs
和kwargs
都被維護了,所以我們可以把我們的自定義小部件當作他們的超級import
我們需要的東西(我的偏好)評論應該告訴你rest,但如果有混淆,請在評論部分指出,我會做出更詳細的解釋。
小部件.py
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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.