programing

Tkinter의 위젯 그룹에 스크롤바 추가

nasanasas 2021. 1. 7. 08:03
반응형

Tkinter의 위젯 그룹에 스크롤바 추가


저는 Python을 사용하여 로그 파일에서 항목을 구문 분석하고 Tkinter를 사용하여 항목 내용을 표시하고 있으며 지금까지 훌륭했습니다. 출력은 레이블 위젯의 그리드이지만 때때로 화면에 표시 할 수있는 것보다 더 많은 행이 있습니다. 매우 쉬울 것 같은 스크롤바를 추가하고 싶지만 알아낼 수 없습니다.

문서는 목록, 텍스트 상자, 캔버스 및 항목 위젯 만 스크롤바 인터페이스를 지원함을 의미합니다. 이들 중 어느 것도 위젯 그리드를 표시하는 데 적합하지 않은 것 같습니다. Canvas 위젯에 임의의 위젯을 넣을 수 있지만 절대 좌표를 사용해야하는 것 같아서 그리드 레이아웃 관리자를 사용할 수 없습니까?

위젯 그리드를 프레임에 넣으려고했지만 스크롤바 인터페이스를 지원하지 않는 것 같아서 작동하지 않습니다.

mainframe = Frame(root, yscrollcommand=scrollbar.set)

누구든지이 제한에 대한 방법을 제안 할 수 있습니까? 스크롤바를 추가하기 위해 PyQt에서 다시 작성하고 실행 가능한 이미지 크기를 너무 많이 늘려야하는 것을 싫어합니다!


개요

스크롤바는 몇 개의 위젯 및 루트 위젯에만 연결할 수 있으며 해당 위젯 Frame그룹의 일부가 아닙니다.

가장 일반적인 해결책은 캔버스 위젯을 만들고 스크롤바를 해당 위젯과 연결하는 것입니다. 그런 다음 해당 캔버스에 레이블 위젯이 포함 된 프레임을 임베드하십시오. 프레임의 너비 / 높이를 결정하고 scrollregion스크롤 영역이 프레임의 크기와 정확히 일치하도록 캔버스 옵션에 공급합니다 .

캔버스에 직접 텍스트 항목을 그리는 것은 그리 어렵지 않으므로 프레임에 포함 된 캔버스 솔루션이 너무 복잡해 보이는 경우 해당 접근 방식을 재고 할 수 있습니다. 그리드를 생성하기 때문에 각 텍스트 항목의 좌표는 계산하기가 매우 쉽습니다. 특히 각 행이 동일한 높이 (단일 글꼴을 사용하는 경우) 인 경우 더욱 그렇습니다.

캔버스에 직접 그리려면 사용중인 글꼴의 선 높이를 알아 내면됩니다 (그에 대한 명령이 있습니다). 그런 다음 각 y 좌표는 row*(lineheight+spacing)입니다. x 좌표는 각 열에서 가장 넓은 항목을 기준으로 고정 된 숫자입니다. 모든 항목에 해당 열에 대한 태그를 지정하면 단일 명령으로 열에있는 모든 항목의 x 좌표와 너비를 조정할 수 있습니다.

객체 지향 솔루션

다음은 객체 지향 접근 방식을 사용하는 캔버스에 프레임 포함 솔루션의 예입니다.

import tkinter as tk

class Example(tk.Frame):
    def __init__(self, root):

        tk.Frame.__init__(self, root)
        self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
        self.frame = tk.Frame(self.canvas, background="#ffffff")
        self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((4,4), window=self.frame, anchor="nw", 
                                  tags="self.frame")

        self.frame.bind("<Configure>", self.onFrameConfigure)

        self.populate()

    def populate(self):
        '''Put in some fake data'''
        for row in range(100):
            tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1", 
                     relief="solid").grid(row=row, column=0)
            t="this is the second column for row %s" %row
            tk.Label(self.frame, text=t).grid(row=row, column=1)

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    root=tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

절차 적 솔루션

다음은 객체를 사용하지 않는 솔루션입니다.

import tkinter as tk

def populate(frame):
    '''Put in some fake data'''
    for row in range(100):
        tk.Label(frame, text="%s" % row, width=3, borderwidth="1", 
                 relief="solid").grid(row=row, column=0)
        t="this is the second column for row %s" %row
        tk.Label(frame, text=t).grid(row=row, column=1)

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))

root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")

frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

populate(frame)

root.mainloop()

참고 : Python 2.x에서이 작업을 수행 하려면 import 문 Tkinter대신 사용 tkinter하십시오.


스크롤 가능하게 만들기

이 편리한 클래스를 사용하여 위젯이 포함 된 프레임을 스크롤 가능하게 만드십시오. 이 단계를 따르세요:

  1. 프레임 만들기
  2. 표시 (팩, 그리드 등)
  3. 스크롤 가능하게
  4. 그 안에 위젯 추가
  5. update () 메서드 호출

import tkinter as tk
from tkinter import ttk

class Scrollable(tk.Frame):
    """
       Make a frame scrollable with scrollbar on the right.
       After adding or removing widgets to the scrollable frame, 
       call the update() method to refresh the scrollable area.
    """

    def __init__(self, frame, width=16):

        scrollbar = tk.Scrollbar(frame, width=width)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=False)

        self.canvas = tk.Canvas(frame, yscrollcommand=scrollbar.set)
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar.config(command=self.canvas.yview)

        self.canvas.bind('<Configure>', self.__fill_canvas)

        # base class initialization
        tk.Frame.__init__(self, frame)         

        # assign this obj (the inner frame) to the windows item of the canvas
        self.windows_item = self.canvas.create_window(0,0, window=self, anchor=tk.NW)


    def __fill_canvas(self, event):
        "Enlarge the windows item to the canvas width"

        canvas_width = event.width
        self.canvas.itemconfig(self.windows_item, width = canvas_width)        

    def update(self):
        "Update the canvas and the scrollregion"

        self.update_idletasks()
        self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))

사용 예

root = tk.Tk()

header = ttk.Frame(root)
body = ttk.Frame(root)
footer = ttk.Frame(root)
header.pack()
body.pack()
footer.pack()

ttk.Label(header, text="The header").pack()
ttk.Label(footer, text="The Footer").pack()


scrollable_body = Scrollable(body, width=32)

for i in range(30):
    ttk.Button(scrollable_body, text="I'm a button in the scrollable frame").grid()

scrollable_body.update()

root.mainloop()

참조 URL : https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter

반응형