Создание прокручиваемого, обертываемого Toplevel с Python tkinter - PullRequest
2 голосов
/ 10 октября 2019

Я просто хочу начать с того, что я довольно новичок в программировании с использованием tkinter и Python. Надеюсь, вы мне поможете.

Я пытаюсь создать приложение с разделом справки, который должен открываться как Toplevel с tkinter при нажатии кнопки. Toplevel должен быть прокручиваемым И переносить текст по мере изменения размера окна Toplevel.

Ниже приведен рабочий код, который дает мне хорошее окно с прокруткой, но не переносит текст. Expl (300, 300) внизу находится в исходной настройке, вызванной из другого файла Python, который имеет главное окно tk.Tk (). Кто-нибудь может дать мне совет о том, как работает функция переноса, и что я делаю не так прямо сейчас?

import tkinter as tk

WIDTH = 500
HEIGHT = 500
BG = '#fff'

class Expl(tk.Frame):
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.width = round(WIDTH/2)
        self.height = round(HEIGHT/1.8)

        self.window = tk.Toplevel()

        self.window.wm_geometry('%dx%d+%d+%d' % (self.width, self.height, max(0, self.x - (WIDTH/2 - WIDTH/2/2)), max(0, self.y - (HEIGHT/2 - HEIGHT/1.8/2))))
        self.window.title('Förklaringar')
        self.window.configure(background=BG)
        #self.window.iconbitmap(default=ICON_PATH)

        tk.Frame.__init__(self, self.window)
        myframe=tk.Frame(self.window, width=self.width, height=self.height, bd=1, background=BG)
        myframe.place(x=10,y=10)

        self.canvas = tk.Canvas(self.window, borderwidth=0, background=BG)        
        self.frame = tk.Frame(self.canvas, background=BG)
        self.vsb = tk.Scrollbar(self.window, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)
        self.canvas.bind_all("<MouseWheel>", self.onmousewheel)

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

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

        self.window.grid_rowconfigure(0, weight=1)
        self.window.grid_columnconfigure(0, weight=1)

        self.draw()

    def myfunction(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def onmousewheel(self, event):
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")

    def onFrameConfigure(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def draw(self):
        # Titles
        tk.Label(self.frame, text='TEST 1').grid(row=0, column=0, sticky='SW', padx=10, pady=(5, 0))
        tk.Label(self.frame, text='TEST 2').grid(row=1, column=0, sticky='SW', padx=10, pady=(5, 0))
        tk.Label(self.frame, text='TEST 3').grid(row=2, column=0, sticky='SW', padx=10, pady=(5, 0))

        texxt = WrappingLabel(self.frame, text="TESTTTTTT TTTTTTTT T IN RSG RSG SRG RSG")
        texxt.grid(row=3, column=0, sticky='SW', padx=10, pady=(5, 0))

class WrappingLabel(tk.Label):
    def __init__(self, master=None, **kwargs):
        tk.Label.__init__(self, master, **kwargs)
        self.bind('<Configure>', lambda _: self.config(wraplength=master.winfo_width()))

Expl(300, 300)

1 Ответ

0 голосов
/ 10 октября 2019

Комментарий : кажется, работает как минимум с одной строкой текста.

Если вы используете only class WrappingLabel, вы должны сделать это навсегда .children в Frame.

        # self.texxt.on_configure(event)
        w = self.frame
        for c in w.children:
            w.children[c].on_configure(event)

Комментарий : Единственное, что он центрирует 2-ю строку текста вместо регулировки по левому краю.

Измените на:

class WrappingLabel(tk.Label):
    def __init__(self, master=None, **kwargs):
        tk.Label.__init__(self, master, justify='left', anchor='nw', **kwargs)

Вопрос : перенести текст по мере изменения размера окна Toplevel.

Необходимо выполнить привязку к событию <Configure> виджета Canvas, посколькуразмер этого виджета синхронизируется с Toplevel.


     on startup                   resized large                resized small 

on startup resized large resized small

Примечание : для демонстрации: self.frame = tk.Frame(..., bg='blue', Label(..., bg='yellow'


Примечание : Наследовать от tk.Toplevel вместо tk.Frame.
Вы используете:

class Expl(tk.Frame):
    def __init__(self, x, y):
        self.window = tk.Toplevel()
        tk.Frame.__init__(self, self.window)

, если вы знаете, что делаете, это нормально, но по умолчанию должно читаться:

class Expl(tk.Toplevel):
    def __init__(self, parent, x, y):
        super().__init__(parent)
        self.title('Förklaringar')

Перенос текста по мере изменения размера окна Toplevel :

class Expl(tk.Frame):
    def __init__(self, x, y):
        self.window = tk.Toplevel()
        ...
        self.canvas = tk.Canvas(self.window, borderwidth=0, background=BG)
        self.canvas.bind("<Configure>", self.on_canvas_configure)

    def on_canvas_configure(self, event):
        # Here goes other configure for Scrollbar
        self.texxt.on_configure(event)

    def draw(self):
        ...
        self.texxt = WrappingLabel(self.frame, 
                                   text="TESTTTTTT TTTTTTTT T IN RSG RSG SRG RSG", 
                                   bg='yellow')
        ...


class WrappingLabel(tk.Label):
    def __init__(self, master=None, **kwargs):
        tk.Label.__init__(self, master, **kwargs)
        # No bind here: self.bind('<Configure>'

    def on_configure(self, event):
        widget = event.widget
        # Only on Canvas event set 'wraplength'
        if isinstance(widget, tk.Canvas):
            width = widget.winfo_width()
            # print('on_configure({})'.format((event.widget, width)))
            border = 4
            scrollbar = 12
            self.config(wraplength=width - (border + scrollbar))

Протестировано с Python: 3,5 - 'TclVersion': 8,6 'TkVersion ': 8,6

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...