如何解决图形故障 ttk 小部件
这一切都始于正常 tk.Scale
没有被正确恐惧的事实(我使用的是自定义主题)。
然后我切换到 ttk.Scale
但是当我改变它时它没有显示滑块上方的值。
然后我发现了 ttkwidget,它似乎可以工作,但有图形故障。有人有什么想法要解决吗?
代码:https://pastebin.com/bxgvsjSF
截图:https://ibb.co/tLdjLrx
附注此外,有问题的小部件加载小部件的速度非常慢
解决方法
我找到了一种方法来消除 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,window=self.scale,anchor='nw')
# put label in canvas (the position will be updated later)
self._label = self.create_text(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,'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,to=100,compound='bottom')
scale.pack(expand=True,fill='x')
root.mainloop()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。