【问题标题】:Auto scrolling canvas to show off screen tk Entries自动滚动画布以显示屏幕 tk 条目
【发布时间】:2020-07-23 18:17:09
【问题描述】:

我将这篇文章分为四个部分,我试图实现的目标,重现问题的最少代码量,我已经尝试过的事情,以及一个结论。提供的代码看起来像like this

目标:

使用 Python Tkinter,设置一个画布,使其能够在不使用滚动条的情况下滚动屏幕外的 tk.Entry 小部件。这个想法是最终导致能够设置 root.after 以自动为滚动设置动画,而无需用户输入。我尽量不使用滚动条,因为最终结果将是比赛的结果列表,所以它纯粹是为了查看而不是交互。

重新创建的最小代码量:

(当几何为 1920x1080 时,测试数据的长度刚好足以让最后几个 Entries 不在屏幕上)
# 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()

我尝试过的事情:

  • Tried modifying self.Tree to be a Listbox in order to follow Volting's advice. 当使用 Volting 的代码时,它并没有产生想要的结果,相反,它更像是一个“跟随”滚动而不是我想要的效果。此外,它还添加了一个滚动条,这不是我设计的一部分。
  • 我尝试创建一个名为“scroll”的方法,该方法与示例代码中的按钮执行相同的操作,并在填充表格后调用它。结果与按钮相同,没有任何反应。
  • 将 self.Tree 修改为 Listbox(再次...),然后使用 Listbox.see 方法尝试将视图移动到列表框的末尾。 Similar to this question and answer.
  • 将 Canvas.yview_moveto() 和 yview_scroll() 设置为按钮和方法,类似于 to this question。它产生了与当前最小代码量相同的效果,没有发生任何事情。

结论

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

【问题讨论】:

  • 您正在创建 Treeview,但实际上并未使用 Treeview 的功能。您无法滚动浏览使用grid 添加的项目。您真的需要每个单元格的条目小部件,还是仅用于显示?如果只是为了显示,为什么不用Treeview的insert方法呢?
  • Bryan,为了扩展您的意思,您是否建议我格式化每一行测试数据,然后使用 ~~~insert~~~ 将每一行插入到 Treeview 中?如果是这样,请阅读文档
  • 是的,您必须使用树视图方法将数据插入树视图(假设您实际上不需要条目小部件)。列表框、画布或任何其他支持滚动的小部件也是如此。

标签: python tkinter autoscroll


【解决方案1】:

好的!所以,在一个周末不看代码之后,我回来并意识到了一些事情。首先,我了解 Bryan 的意图,我决定放弃使用 Treeview。我希望它看起来好像在滚动,而不是实际滚动。我实际上并没有在这里滚动任何东西,就像在《星球大战》中,文本在开始时“滚动”到屏幕上。

对于任何未来遇到这种情况的人,他们想要类似于星球大战的内容,其中文本似乎漂浮在屏幕上,或向上滚动屏幕,或任何其他类型的关键字,归结为从顶部移动的文本to bottom or bottom to top 这是我的实现。它涉及动画。以下是您在 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、列表框或画布的情况下制作类似于可滚动文本的内容的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多