首页 > 解决方案 > 自动滚动画布以显示屏幕 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()

我尝试过的事情:


结论

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

标签: pythontkinterautoscroll

解决方案


好的!所以,在一个周末不看代码之后,我回来并意识到了一些事情。首先,我了解 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、列表框或画布。


推荐阅读