Автоматическая прокрутка холста, чтобы показать экранные записи tk

Я разделил этот пост на четыре части: цель, которую я пытаюсь достичь, минимальное количество кода для воссоздания проблемы, вещи, которые я уже пробовал, и заключение. Предоставленный код будет выглядеть подобно этому.

Цель:

Using Python Tkinter, set up a canvas to be able to scroll through tk.Entry widgets that are off-screen without the use of a scrollbar. The idea is to eventually lead up to being able to set a root.after to animate the scroll automatically without user input. I'm trying my best not to use a scrollbar as the end result will be a results list for a competition, so it's purely for viewing rather than interaction.

Минимальный объем кода для воссоздания:

(The test data is just long enough to have the last few Entries be off-screen when the geometry is 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, чтобы он был списком в чтобы следовать совету Вольтинга. При использовании кода Вольтинга он не дал желаемого результата, поскольку вместо этого это скорее следующая прокрутка, а не мой желаемый эффект. Кроме того, он добавляет полосу прокрутки, которая не является частью моего дизайна.
  • Я попытался создать метод прокрутки, который делает то же самое, что и кнопка в моем примере кода, и вызывает его после заполнения таблицы. Те же результаты, что и с кнопкой, ничего не произошло.
  • Изменение self.Tree в Listbox (снова...), а затем использование метода Listbox.see, поэтому попробуйте переместить представление в конец списка. Аналогично этому вопросу и ответу.
  • Установка Canvas.yview_moveto() и yview_scroll() для кнопки и метода, аналогично этому вопросу. Это произвело тот же эффект, что и текущее минимальное количество кода, ничего не произошло.

Вывод

I've had some practice in animating in Tkinter, so if I can get it to move just an inch, I'm sure I'll be able to get it to auto-scroll. My main focus right now is literally just to get the frame to move down. There can be anywhere from 2 to 500 or more entries, so I've already recreated this in a very O.O.P style, but it's a little large to post it.

person Jjaxs    schedule 23.07.2020    source источник
comment
Вы создаете Treeview, но фактически не используете функции Treeview. Вы не можете прокручивать элементы, добавленные с помощью grid. Вам действительно нужны виджеты ввода для каждой ячейки, или это только для отображения? Если это только для отображения, почему вы не используете метод insert Treeview?   -  person Bryan Oakley    schedule 23.07.2020
comment
Брайан, в дополнение к тому, что вы говорите, вы предлагаете мне форматировать каждую строку тестовых данных, а затем вставлять каждую строку в Treeview с помощью ~~~insert~~~? Если да, читайте документацию   -  person Jjaxs    schedule 23.07.2020
comment
Да, вы должны вставить свои данные в древовидную структуру, используя методы древовидной структуры (при условии, что вам на самом деле не нужны виджеты ввода). То же самое верно для списка, холста или любого другого виджета, который поддерживает прокрутку.   -  person Bryan Oakley    schedule 23.07.2020


Ответы (1)


Хорошо! Итак, после выходных, когда я не смотрел код, я вернулся и понял несколько вещей. Прежде всего, я понял, к чему ведет Брайан, и решил отказаться от использования 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()



Этот код должен выдавать это.

Надеюсь, это поможет любому, кто пытается сделать что-то похожее на прокручиваемый текст, без использования Treeview, списка или холста.

person Jjaxs    schedule 27.07.2020