python - 自动滚动画布以显示屏幕 tk 条目
问题描述
我将这篇文章分为四个部分,我试图实现的目标,重现问题的最少代码量,我已经尝试过的事情,以及一个结论。提供的代码将如下所示。
目标:
使用 Python Tkinter,设置一个画布,以便能够在不使用滚动条的情况下滚动屏幕外的 tk.Entry 小部件。这个想法是最终导致能够设置 root.after 以自动为滚动设置动画,而无需用户输入。我尽量不使用滚动条,因为最终结果将是比赛的结果列表,所以它纯粹是为了查看而不是交互。重新创建的最少代码量:
(当几何为 1920x1080 时,测试数据的长度足以让最后几个条目不在屏幕上)# Python program to create a table
import tkinter as tk
from tkinter import ttk
from ESTDisplayEntity import ESTDisplayEntity
root = tk.Tk()
root.geometry("1920x1080")
class Table():
def __init__(self, root, lst):
self.Tree = ttk.Treeview(root)
# find total number of rows and
# columns in list
total_rows = len(lst)
total_columns = len(lst[0])
maxWidth = 125
# code for creating table
for i in range(total_rows):
for j in range(total_columns):
if j == 0:
width = int(maxWidth*.05)
elif j == 1:
width = int(maxWidth*.25)
elif j == 2:
width = int(maxWidth*0.15)
else:
width = int(maxWidth*(.15/total_columns-3))
e = tk.Entry(self.Tree, width=width, fg='Black',
font=('Arial',16,'bold'))
e.grid(row=i, column=j, sticky = "EW")
e.insert(tk.END, lst[i][j])
e.configure(state="readonly")
self.Tree.grid_columnconfigure(0, weight=0)
self.Tree.grid_columnconfigure(1, weight=3)
self.Tree.grid_columnconfigure(2, weight=2)
for i in range(total_columns-3):
self.Tree.grid_columnconfigure(i+3, weight = 1)
# test data
lest = [
(1,'Raj Mumbai'," Rifle",19,15,250,400),
(2,'Aaryan Pune'," Rifle",18,100,300,500),
(3,'Vaishnavi Mumbai'," Rifle",20,155,300,560),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(13,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(18,'Shubham Delhi'," Rifle",21,122,300,741),
(18,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741)
]
topframe = tk.Frame(root)
topframe.pack(fill=tk.X)
scrollingFrame = tk.Canvas(root)
scrollingFrame.pack(fill=tk.BOTH)
t = Table(scrollingFrame, lest)
t.Tree.pack(fill=tk.BOTH)
# SB = tk.Button(topframe, command=t.Tree.yview_moveto(fraction=50), text= "TWSTF")
SB = tk.Button(topframe, command=scrollingFrame.yview_moveto(fraction=50), text= "TWSTF")
SB.pack()
root.mainloop()
我尝试过的事情:
- 尝试将 self.Tree 修改为 Listbox 以遵循 Volting 的建议。当使用 Volting 的代码时,它并没有产生想要的结果,相反,它更像是一个“跟随”滚动而不是我想要的效果。此外,它还添加了一个滚动条,这不是我设计的一部分。
- 我尝试创建一个名为“scroll”的方法,它与示例代码中的按钮执行相同的操作,并在填充表格后调用它。与按钮相同的结果,没有发生任何事情。
- 将 self.Tree 修改为 Listbox(再次...),然后使用 Listbox.see 方法尝试将视图移动到列表框的末尾。类似于这个问答。
- 将 Canvas.yview_moveto() 和 yview_scroll() 设置为按钮和方法,类似于此问题。它产生了与当前最小代码量相同的效果,没有发生任何事情。
结论
我在 Tkinter 中进行过一些动画制作的练习,所以如果我能让它移动一英寸,我相信我就能让它自动滚动。我现在的主要焦点实际上只是让框架向下移动。可以有 2 到 500 个或更多条目,所以我已经以非常 OOP 的风格重新创建了这个,但是发布它有点大。解决方案
好的!所以,在一个周末不看代码之后,我回来并意识到了一些事情。首先,我了解 Bryan 的意图,我决定放弃使用 Treeview。我希望它看起来好像在滚动,而不是实际滚动。我实际上并没有在这里滚动任何东西,就像在《星球大战》中,文本在开始时“滚动”到屏幕上。
对于任何未来遇到这种想要类似于星球大战的东西的人,其中文本似乎漂浮在屏幕上,或向上滚动屏幕,或任何其他类型的关键字,归结为文本从上到下或从下到上移动这是我的实现。它涉及动画。以下是您在 Python 3.X 中自行运行和测试所需的所有代码
# Python program to create a table
import tkinter as tk
from tkinter import ttk
from ESTDisplayEntity import ESTDisplayEntity
class Table():
def __init__(self, root):
#This is the base frame that all Labels will be nested inside of
self._movingFrame = tk.Frame(root)
def populateTable(self, lst):
# find total number of rows and
# columns in list
total_rows = len(lst)
total_columns = len(lst[0])
#Magic number alert: This maxWidth is a magic number that just so happens to let the columns fill up the space needed for a 1920x1080 monitor
#It has something to do with tkinter using character units as a measurement of width when text is involved.
maxWidth = 200
# code for creating table. Simple nested for loop for accessing all parts of a 2D array.
# our data is in the form of [[],[],[],[]]
for i in range(total_rows):
for j in range(total_columns):
#Creating an anchor variable depending on what column we are inside of.
#Will look like this: [ 1|Some Name Here |Some club here | 20 | 34 | 44 | total |]
if j == 0:
width = int(maxWidth*.03)
anchor = 'e'
elif j == 1:
width = int(maxWidth*.40)
anchor = 'w'
elif j == 2:
width = int(maxWidth*0.25)
anchor = 'w'
else:
width = int(maxWidth*(.30/(total_columns-3)))
anchor = 'center'
e = tk.Label(self._movingFrame, width=width, fg='Black',
font=('Arial',16,'bold'),bd=1, relief='solid', text=lst[i][j], anchor=anchor)
e.grid(row=i, column=j)
#This adjusts how quickly each column adjusts. Currently the second and third row are important.
# as their weights are higher, so they will adjust faster. The first column does not adjust
# all columns after the club column will be lower than the club column but higher than the rank column
# so the score will be able to shrink and expand as needed. In the off chance numbers get ridicuously high.
self._movingFrame.grid_columnconfigure(0, weight=0)
self._movingFrame.grid_columnconfigure(1, weight=3)
self._movingFrame.grid_columnconfigure(2, weight=2)
for i in range(total_columns-3):
self._movingFrame.grid_columnconfigure(i+3, weight = 1)
# This is setting up and initializing the aniamtion variable
self._rely_loc = 0.0
def Start(self):
self._rankedListAnimate()
def _rankedListAnimationUpdate(self):
#This is how much the frame will move given the next frame update, the smaller the better
# though it will slow down the animation the smaller you make it.
# Since we are using the "rely" option of .place everything is in percentage of the parent window.
self._rely_loc += -0.001
#Checks and balances to reset system when text scrolls off screen.
if self._rely_loc >= 1.0:
self._rely_loc = 0.0
#Need to fix hard coded variable for larger lists
elif self._movingFrame.winfo_rooty() < -900:
self._rely_loc=0.999
#Brains of operation, this .place method is where and how the text scrolls up the screen
# Using relwidth of 1.0, the widget will expand the whole screen, similar to .pack(fill=BOTH)
self._movingFrame.place(anchor= tk.NW,relx=0, rely=self._rely_loc, relwidth= 1.0)
#updating the frame just to be safe.
self._movingFrame.update()
#Recursive style function that calls itself with a .after method
def _rankedListAnimate(self):
self._rankedListAnimationUpdate()
#This is the heart of the operation, without the .after method, there is no animation
# the first variable is how often the second variable (usually a method) gets called in milliseconds
# setting this to be smaller makes the animation faster, making it slower makes the animation choppy.
self._movingFrame.master.after(10, self._rankedListAnimate)
# test data
lest = [
(1,'Raj Mumbai'," Rifle",19,15,250,400),
(2,'Aaryan Pune'," Rifle",18,100,300,500),
(3,'Vaishnavi Mumbai'," Rifle",20,155,300,560),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(4,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(5,'Rachna Mumbai'," Rifle",21,125,300,450),
(13,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(14,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(15,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(16,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(17,'Shubham Delhi'," Rifle",21,122,300,741),
(18,'Shubham Delhi'," Rifle",21,122,300,741),
(18,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741),
(19,'Shubham Delhi'," Rifle",21,122,300,741)
]
resolutionWidth = 1920
resolutionHeight = 1080
root = tk.Tk()
root.geometry("{}x{}".format(resolutionWidth, resolutionHeight))
t= Table(root)
t.populateTable(lest)
t.Start()
root.mainloop()
此代码应生成 this。
希望这可以帮助任何人尝试制作类似于可滚动文本的内容,而无需使用 Treeview、列表框或画布。
推荐阅读
- android - 从服务发送 KeyEvent
- android - 如何获得响应吐司
- r - 安装 R 4.1.0 后,R 控制台工具栏和菜单中的字体不再正确
- css - bootsrap 5 内容重叠的粘性侧边栏问题
- cocoapods - 无法安装 cocoapods MacBook Air m1
- java - Windows 10 UDP 缓冲区大小/多播接收
- c# - MSB6006“csc.exe”退出代码-1073741819?
- javascript - iOS 上网络中的语音到文本
- flutter - 使用 gitlab 在 Fastlane 中需要帮助(Android 的自动化部署)
- javascript - 未捕获的 SyntaxError:标识符“源”已被声明