【问题标题】:Creating scrollable, wrap-able Toplevel with Python tkinter使用 Python tkinter 创建可滚动、可包装的 Toplevel
【发布时间】:2020-02-07 21:52:46
【问题描述】:

我只想首先说我对使用 tkinter 和 Python 进行编码非常陌生。希望你能帮帮我。

我正在尝试创建一个带有帮助部分的应用程序,该部分应该在单击按钮时使用 tkinter 作为顶层打开。 Toplevel 需要可滚动并在我调整 Toplevel 窗口大小时包装文本。

下面是一个工作代码,它为我提供了一个很好的可滚动窗口,但不会换行文本。底部的 Expl(300, 300) 位于从另一个具有主 tk.Tk() 窗口的 Python 文件调用的原始设置中。谁能给我关于包装功能如何工作的建议,以及我现在做错了什么?

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)

【问题讨论】:

  • 如果您想要换行文本,为什么不使用Text 小部件而不是标签?
  • 问题不在于标签没有换行,问题在于它们所在的框架在您调整窗口大小时没有改变大小。

标签: python python-3.x tkinter


【解决方案1】:

评论:似乎至少可以处理一行文本。

假设您仅使用 class WrappingLabel,您必须在Frame 中永远使用.children

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

评论:唯一的问题是它使第二行文本居中而不是左调整。

改为:

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

问题:在我调整顶层窗口大小时换行。

您必须绑定到Canvas 小部件的&lt;Configure&gt; 事件,因为该小部件的大小调整与Toplevel 同步。


     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

【讨论】:

  • 这个解决方案让我有点困惑,只有经过一些修改后,我才让它的工作有点令人满意。肯定有更简单的方法来获取可换行的文本和使用 Python 最常见的 GUI 包的滚动功能?
  • @eligolf:“经过一些修改”:正如您在屏幕截图中看到的,这是一个工作示例。告诉缺失的部分,我很高兴相应地修复代码。
  • @eligolf:“获取可换行文本和滚动功能的更简单方法”:您的问题代码可以简化,例如你有 2 Frame 很多。您说的是“可换行文本”,但使用的是Label。编辑您的问题并详细解释为什么您选择了Label 而不是Text 小部件。?
  • 我复制了代码(并将 Expl(300,300) 与 tkinter 导入一起添加到末尾),但它只显示了 2 个没有文本的灰色小窗口。
  • @eligolf:“我复制了代码”:这解释了你的困惑,你必须使用 your 问题代码并添加并替换为我的答案中的部分。三个点... 是代码中未显示的部分。表示添加self.canvas.bind(...def on_canvas_configure,替换整个class WrappingLabel
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
  • 2011-07-02
  • 1970-01-01
  • 2015-07-13
  • 2021-04-13
  • 2018-06-28
  • 1970-01-01
相关资源
最近更新 更多