【问题标题】:Graphic glitch ttk widgets图形故障 ttk 小部件
【发布时间】:2021-02-18 07:56:39
【问题描述】:

这一切都始于一个正常的tk.Scale 没有被正确地担心(我使用的是自定义主题)。
然后我切换到ttk.Scale,但是当我更改它时它没有显示滑块上方的值。
然后我发现了 ttkwidget,它似乎可以工作,但有图形故障。有人有什么想法可以解决吗?
代码:https://pastebin.com/bxgvsjSF
截图:https://ibb.co/tLdjLrx
附言此外,有问题的小部件加载小部件非常慢

编辑:解决方案在最佳答案的评论中

【问题讨论】:

  • 我们是否应该假设ttkwidgets 是什么?是来自tkinter 库吗?
  • 抱歉造成误会。 This is ttkwidgets
  • 问题是由来自ttkwidgets的小部件引起的对吧?
  • 这个问题在这里实际上不太有效,因为错误不是由于标准tkinter小部件引起的。您可能应该在issues 上问同样的问题,这样开发人员就无法直接与您联系。
  • 请不要链接到其他网站上的代码。花点时间在您的问题中直接嵌入minimal reproducible example

标签: python tkinter ttk ttkwidgets


【解决方案1】:

我找到了消除ttk.LabeledScale 中的故障的方法。我认为问题在于重绘整个 Label 小部件,所以我改用了 Canvas。使用Canvas,当文字移动时,不需要重绘背景,动画更流畅。

以下代码基于ttk.LabeledScale的源代码(来自Python 3.9.1,您可以在tkinter/ttk.py中找到它)。但是小部件现在基于Canvas,其中添加了create_window()ćreate_text() 的比例和文本。我修改了__init__()_adjust() 方法,并添加了一个_on_theme_change() 方法,该方法在主题更改时调用以更新画布的样式并调整元素的位置。

import tkinter as tk
from tkinter import ttk


class LabeledScale(tk.Canvas):

    def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
        self._label_top = kw.pop('compound', 'top') == 'top'

        tk.Canvas.__init__(self, master, **kw)
        self._variable = variable or tk.IntVar(master)
        self._variable.set(from_)
        self._last_valid = from_

        # use style to set the Canvas background color
        self._style = ttk.Style(self)
        self.configure(bg=self._style.lookup('Horizontal.TScale', 'background'))
        # create the scale
        self.scale = ttk.Scale(self, variable=self._variable, from_=from_, to=to)
        self.scale.bind('<<RangeChanged>>', self._adjust)

        # put scale in canvas
        self._scale = self.create_window(0, 0, window=self.scale, anchor='nw')
        # put label in canvas (the position will be updated later)
        self._label = self.create_text(0, 0, text=self._variable.get(),
                                       fill=self._style.lookup('TLabel', 'foreground'),
                                       anchor='s' if self._label_top else 'n')
        # adjust canvas height to fit the whole content
        bbox = self.bbox(self._label)
        self.configure(width=self.scale.winfo_reqwidth(),
                       height=self.scale.winfo_reqheight() + bbox[3] - bbox[1])
        # bindings and trace to update the label
        self.__tracecb = self._variable.trace_variable('w', self._adjust)
        self.bind('<Configure>', self._adjust)
        self.bind('<Map>', self._adjust)
        # update sizes, positions and appearances on theme change
        self.bind('<<ThemeChanged>>', self._on_theme_change)

    def destroy(self):
        """Destroy this widget and possibly its associated variable."""
        try:
            self._variable.trace_vdelete('w', self.__tracecb)
        except AttributeError:
            pass
        else:
            del self._variable
        super().destroy()
        self.label = None
        self.scale = None

    def _on_theme_change(self, *args):
        """Update position and appearance on theme change."""
        def adjust_height():
            bbox = self.bbox(self._label)
            self.configure(height=self.scale.winfo_reqheight() + bbox[3] - bbox[1])

        self.configure(bg=self._style.lookup('Horizontal.TScale', 'background'))
        self.itemconfigure(self._label, fill=self._style.lookup('TLabel', 'foreground'))
        self._adjust()
        self.after_idle(adjust_height)

    def _adjust(self, *args):
        """Adjust the label position according to the scale."""
        def adjust_label():
            self.update_idletasks() # "force" scale redraw
            x, y = self.scale.coords()
            if self._label_top:
                y = 0
            else:
                y = self.scale.winfo_reqheight()
            # avoid that the label goes off the canvas
            bbox = self.bbox(self._label)
            x = min(max(x, 0), self.winfo_width() - (bbox[2] - bbox[0])/2)
            self.coords(self._label, x, y)  # move label
            self.configure(scrollregion=self.bbox('all'))
            self.yview_moveto(0)  # make sure everything is visible

        self.itemconfigure(self._scale, width=self.winfo_width())
        from_ = ttk._to_number(self.scale['from'])
        to = ttk._to_number(self.scale['to'])
        if to < from_:
            from_, to = to, from_
        newval = self._variable.get()
        if not from_ <= newval <= to:
            # value outside range, set value back to the last valid one
            self.value = self._last_valid
            return

        self._last_valid = newval
        self.itemconfigure(self._label, text=newval)
        self.after_idle(adjust_label)

    @property
    def value(self):
        """Return current scale value."""
        return self._variable.get()

    @value.setter
    def value(self, val):
        """Set new scale value."""
        self._variable.set(val)

root = tk.Tk()
style = ttk.Style(root)
style.theme_use('alt')

scale = LabeledScale(root, from_=0, to=100, compound='bottom')
scale.pack(expand=True, fill='x')

root.mainloop()

【讨论】:

  • 谢谢你,但我终于想出了如何创建我想要的东西。在ttkwidgets.Tickscale 我设置了digits=0 现在下面的标签消失了,滑动的值是一个整数
猜你喜欢
  • 2015-10-26
  • 2014-06-24
  • 1970-01-01
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多