自动滚动 canvas 以显示屏幕 tk 条目

Auto scrolling canvas to show off screen tk Entries

我将此 post 分为四个部分,即我要实现的目标、重现问题的最少代码量、我已经尝试过的事情以及结论。提供的代码看起来 like this.

目标:

使用 Python Tkinter,设置 canvas 以便能够滚动 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()

我尝试过的事情:


结论

我已经在 Tkinter 中进行了一些动画制作练习,所以如果我能让它移动一英寸,我相信我就能让它自动滚动。我现在的主要重点实际上只是让框架向下移动。可以有 2 到 500 或更多条目,所以我已经以非常 O.O.P 的风格重新创建了它,但它有点大 post 它。

好的!所以,在一个周末没看代码之后,我回来意识到了一些事情。首先,我了解 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()



此代码应 produce this

希望这可以帮助任何人在不使用 Treeview、列表框或 canvas 的情况下尝试制作类似于可滚动文本的内容。