Tkinter 滚动条不填满框架
Tkinter scrollbar doesn't fill frame
我正在尝试制作一个根据用户的分辨率而变化的 GUI。我对 Python 还是很陌生,但我已经设法完成了一些。我正在努力寻找为什么滚动条不使用所有提供给它们的 space 。这导致他们身后的框架可见。
root = Tk()
screen_height = root.winfo_screenheight()
screen_width = root.winfo_screenwidth()
h = (screen_height / 800)
w = (screen_width / 1300)
frame = ['topleft', 'topmid', 'topright',
'bottomleft', 'bottommid']
multiplier = [300, 200, 800, 500, 100]
height = [0,
Decimal(h*(multiplier[0]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[1]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[2]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[3]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP)
]
width = [0,
Decimal(w*(multiplier[0]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[1]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[2]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[3]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
]
topleft = Frame(root,
bg = 'black', bd='3',
height = height[1], width = width[1],
relief='flat'
).grid(row = height[0], column = width[0],
rowspan = height[1], columnspan = width[1])
topmid = Frame(root,
bg = 'yellow', bd='3',
height = height[2], width = width[2],
relief='flat'
).grid(row = height[0], column = width[1],
rowspan = height[2], columnspan = width[2])
bottommid = Frame(root,
bg = 'pink', bd ='3',
height = height[5], width = width[5],
relief='flat'
).grid(row = height[2], column = width[1],
rowspan = height[5], columnspan = width[5])
bottomright = Frame(root,
bg = 'blue', bd='3',
height = height[5], width = width[5],
relief='flat'
).grid(row = height[2], column = width[1]+width[5],
rowspan = height[5], columnspan = width[5])
class file_selector:
def __init__(self):
global fs_scrollbar, fs_listbox, check
bottomleft = Frame(root,
bg = 'white', bd='3',
height = height[4], width = width[4],
relief='flat'
).grid(row= height[1], column= width[0],
rowspan= height[4], columnspan= width[4])
self.fs_scrollbar = Scrollbar(bottomleft,
orient = VERTICAL
)
self.fs_listbox = Listbox(bottomleft,
bg = 'white',
relief = 'flat',
yscrollcommand = self.fs_scrollbar.set
)
self.check = print(self.fs_listbox.curselection())
self.fs_listbox.bind('<ButtonRelease-1>', self.check)
self.fs_scrollbar['command'] = self.fs_listbox.yview
file_selector.widgets(self)
def widgets(self):
self.fs_scrollbar.grid(row = height[1], column = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
rowspan = height[4], columnspan = ((width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky= N+E+S+W
)
for file in os.listdir(os.curdir):
if file.endswith(".txt"):
self.fs_listbox.insert(END, file)
self.fs_listbox.grid(row = height[1], column = width[0],
rowspan = height[4], columnspan = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+E+S+W
)
class text_editor:
def __init__(self):
global te_scrollbar, te_text
topright = Frame(root,
bg = 'red', bd='3',
height = height[3], width = width[3],
relief='flat'
).grid(row=height[0], column= width[4],
rowspan= height[3], columnspan= width[3])
self.te_scrollbar = Scrollbar(topright,
orient = VERTICAL
)
self.te_text = Text(topright,
bg = 'white',
yscrollcommand = self.te_scrollbar.set
)
self.te_scrollbar['command'] = self.te_text.yview
text_editor.widgets(self)
def widgets(self):
with open('test1.txt', 'r') as self.file:
self.file = self.file.read()
self.te_scrollbar.grid(row = height[0], column = (width[4]+width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
rowspan = height[3], columnspan = ((width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+S
)
self.te_text.insert(END, self.file)
self.te_text.grid(row = height[0], column = width[4],
rowspan = height[3], columnspan = (width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+E+S+W
)
file_selector()
text_editor()
提前为糟糕的代码道歉,Tkinter 没有很好的文档记录(我也不是很擅长)。
您不需要进行所有这些计算——tkinter 非常擅长为您计算几何。
您在使用网格时犯了几个非常常见的错误。当容器(例如:Frame)中有额外的space时,grid会分配额外的space给"weight"为正数的行和列。默认情况下,网格行和列的权重为 0(零),这意味着它们不会获得任何额外的 space.
根据经验,内部小部件使用网格的每一帧都需要至少有一行和一列具有正权重。您可以使用 grid_rowconfigure
和 grid_columnconfigure
命令来做到这一点。在您的情况下,您需要至少给一行(可能是最后一行)赋予 1(一)的权重。
您还有另一个很常见的问题。考虑这行代码和其他类似的代码:
topleft = Frame(...).grid(...)
以上将始终将 topleft
设置为 None
,因为那是 grid
returns。因此,您认为进入 topleft
的任何小部件实际上都进入了根 window,因为将 None
指定为父级或主控与提供根 window 相同。
然而,在我看来,你的问题更大。为具有多个小部件的整个应用程序使用一个网格是非常困难的。相反,您需要采取 "divide and conquer" 方法。
例如,您的 GUI 显然有两个主要区域:左侧和右侧。所以我会先制作两个框架,每边一个。这样,右侧的任何网格或打包命令都不会影响左侧的网格或打包命令,反之亦然。
左侧似乎也分为两部分:带有彩色框架的顶部部分,以及包含列表框和滚动条的底部部分。我建议将左侧分成两半。同样,在左下角使用 grid 或 pack 不会影响在左上角使用 grid 或 pack。这将使解决您的布局问题变得非常非常容易。
我正在尝试制作一个根据用户的分辨率而变化的 GUI。我对 Python 还是很陌生,但我已经设法完成了一些。我正在努力寻找为什么滚动条不使用所有提供给它们的 space 。这导致他们身后的框架可见。
root = Tk()
screen_height = root.winfo_screenheight()
screen_width = root.winfo_screenwidth()
h = (screen_height / 800)
w = (screen_width / 1300)
frame = ['topleft', 'topmid', 'topright',
'bottomleft', 'bottommid']
multiplier = [300, 200, 800, 500, 100]
height = [0,
Decimal(h*(multiplier[0]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[1]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[2]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[3]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(h*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP)
]
width = [0,
Decimal(w*(multiplier[0]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[1]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[2]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[3]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
Decimal(w*(multiplier[4]))
.quantize(Decimal('1.'), rounding=ROUND_UP),
]
topleft = Frame(root,
bg = 'black', bd='3',
height = height[1], width = width[1],
relief='flat'
).grid(row = height[0], column = width[0],
rowspan = height[1], columnspan = width[1])
topmid = Frame(root,
bg = 'yellow', bd='3',
height = height[2], width = width[2],
relief='flat'
).grid(row = height[0], column = width[1],
rowspan = height[2], columnspan = width[2])
bottommid = Frame(root,
bg = 'pink', bd ='3',
height = height[5], width = width[5],
relief='flat'
).grid(row = height[2], column = width[1],
rowspan = height[5], columnspan = width[5])
bottomright = Frame(root,
bg = 'blue', bd='3',
height = height[5], width = width[5],
relief='flat'
).grid(row = height[2], column = width[1]+width[5],
rowspan = height[5], columnspan = width[5])
class file_selector:
def __init__(self):
global fs_scrollbar, fs_listbox, check
bottomleft = Frame(root,
bg = 'white', bd='3',
height = height[4], width = width[4],
relief='flat'
).grid(row= height[1], column= width[0],
rowspan= height[4], columnspan= width[4])
self.fs_scrollbar = Scrollbar(bottomleft,
orient = VERTICAL
)
self.fs_listbox = Listbox(bottomleft,
bg = 'white',
relief = 'flat',
yscrollcommand = self.fs_scrollbar.set
)
self.check = print(self.fs_listbox.curselection())
self.fs_listbox.bind('<ButtonRelease-1>', self.check)
self.fs_scrollbar['command'] = self.fs_listbox.yview
file_selector.widgets(self)
def widgets(self):
self.fs_scrollbar.grid(row = height[1], column = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
rowspan = height[4], columnspan = ((width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky= N+E+S+W
)
for file in os.listdir(os.curdir):
if file.endswith(".txt"):
self.fs_listbox.insert(END, file)
self.fs_listbox.grid(row = height[1], column = width[0],
rowspan = height[4], columnspan = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+E+S+W
)
class text_editor:
def __init__(self):
global te_scrollbar, te_text
topright = Frame(root,
bg = 'red', bd='3',
height = height[3], width = width[3],
relief='flat'
).grid(row=height[0], column= width[4],
rowspan= height[3], columnspan= width[3])
self.te_scrollbar = Scrollbar(topright,
orient = VERTICAL
)
self.te_text = Text(topright,
bg = 'white',
yscrollcommand = self.te_scrollbar.set
)
self.te_scrollbar['command'] = self.te_text.yview
text_editor.widgets(self)
def widgets(self):
with open('test1.txt', 'r') as self.file:
self.file = self.file.read()
self.te_scrollbar.grid(row = height[0], column = (width[4]+width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
rowspan = height[3], columnspan = ((width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+S
)
self.te_text.insert(END, self.file)
self.te_text.grid(row = height[0], column = width[4],
rowspan = height[3], columnspan = (width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
sticky = N+E+S+W
)
file_selector()
text_editor()
提前为糟糕的代码道歉,Tkinter 没有很好的文档记录(我也不是很擅长)。
您不需要进行所有这些计算——tkinter 非常擅长为您计算几何。
您在使用网格时犯了几个非常常见的错误。当容器(例如:Frame)中有额外的space时,grid会分配额外的space给"weight"为正数的行和列。默认情况下,网格行和列的权重为 0(零),这意味着它们不会获得任何额外的 space.
根据经验,内部小部件使用网格的每一帧都需要至少有一行和一列具有正权重。您可以使用 grid_rowconfigure
和 grid_columnconfigure
命令来做到这一点。在您的情况下,您需要至少给一行(可能是最后一行)赋予 1(一)的权重。
您还有另一个很常见的问题。考虑这行代码和其他类似的代码:
topleft = Frame(...).grid(...)
以上将始终将 topleft
设置为 None
,因为那是 grid
returns。因此,您认为进入 topleft
的任何小部件实际上都进入了根 window,因为将 None
指定为父级或主控与提供根 window 相同。
然而,在我看来,你的问题更大。为具有多个小部件的整个应用程序使用一个网格是非常困难的。相反,您需要采取 "divide and conquer" 方法。
例如,您的 GUI 显然有两个主要区域:左侧和右侧。所以我会先制作两个框架,每边一个。这样,右侧的任何网格或打包命令都不会影响左侧的网格或打包命令,反之亦然。
左侧似乎也分为两部分:带有彩色框架的顶部部分,以及包含列表框和滚动条的底部部分。我建议将左侧分成两半。同样,在左下角使用 grid 或 pack 不会影响在左上角使用 grid 或 pack。这将使解决您的布局问题变得非常非常容易。