- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
几个 Tk 小部件也存在于 Ttk 版本中。通常它们具有相同的一般行为,但使用“样式”和“主题”而不是每个实例的外观属性(例如 bg
等)。这很好,因为 Ttk 小部件默认采用操作系统窗口管理器的“标准外观”,无需配置任何外观。
但是,由于某些原因,ttk.Scale
小部件没有 tk.Scale
小部件的两个非常有用的选项:showvalue
和tickinterval
(参见 reference)。这很奇怪,因为它们更多地是关于行为而不是外观。
在保持 ttk
外观的同时“模仿”这两个选项会很棒。以下代码是我对此的笨拙尝试。问题是:有没有更好的方法? (显然,除了将整个事情封装在一个类中)以及如何合理地获得半自动化的 tickinterval
替代品(而不是像下面的代码那样“手动”完成)。
import tkinter as tk
import tkinter.ttk as ttk
# initial setup
root = tk.Tk()
frame = tk.Frame(root)
#################################################################
# create a tk slider showing current value and ticks
# (showvalue=True is the default)
tkslider = tk.Scale(frame, from_=-4, to=4,
orient=tk.HORIZONTAL, tickinterval=2)
#################################################################
#################################################################
# create a ttk slider showing current value and ticks
# use a ttk frame to get ttk style background
ttkslider = ttk.Frame(frame)
# define a callback function to update the value label
def ttk_slider_callback(value):
# 'value' seems to be a string - bug or feature?
value_label.config(text=round(float(value)))
# 'text' can apparently be an int and gets converted into str
# (...) possibly do other stuff
# decompose frame into two ttk labels and a ttk scale
value_label = ttk.Label(ttkslider, text=0)
actual_slider = ttk.Scale(ttkslider, from_=-4, to=4,
command=ttk_slider_callback)
# (orient=tk.HORIZONTAL is the default)
ticks_label = ttk.Label(ttkslider, text=' -4 -2 0 2 4 ')
# put it all together
value_label.grid()
actual_slider.grid()
ticks_label.grid()
#################################################################
# final setup
tkslider.grid(row=0, column=0)
ttkslider.grid(row=0, column=1)
frame.grid()
root.mainloop()
在实际“滑动”比例尺之前,之前代码的结果可能看起来像这样,左侧是 Tk 比例尺,右侧是 Ttk 比例尺(每个操作系统/窗口管理器会明显不同):
最佳答案
您可以使用 place
及其由公式给出的位置 x(以像素为单位)以自动方式放置刻度和显示值的标签:
x = ((value - start) / extent) * (width - sliderlength) + sliderlength / 2
与:
value
: 报价单的值start
:刻度的起点(即 from
选项)范围
:结束 - 开始width
: 刻度的宽度((value - start)/extent)
以百分比给出位置,然后我只需将它乘以刻度的长度,但要考虑 slider 的长度。
然后打勾:place(in_=self.scale, bordermode='outside', x=x, rely=1, anchor='n')
(使用 rely=0, anchor='s'
作为显示值的标签)
下面是完整的代码。我还添加了对 digits
选项的支持。
import tkinter as tk
import tkinter.ttk as ttk
class TtkScale(ttk.Frame):
def __init__(self, master=None, **kwargs):
ttk.Frame.__init__(self, master)
self.columnconfigure(0, weight=1)
self.showvalue = kwargs.pop('showvalue', True)
self.tickinterval = kwargs.pop('tickinterval', 0)
self.digits = kwargs.pop('digits', '0')
if 'command' in kwargs:
# add self.display_value to the command
fct = kwargs['command']
def cmd(value):
fct(value)
self.display_value(value)
kwargs['command'] = cmd
else:
kwargs['command'] = self.display_value
self.scale = ttk.Scale(self, **kwargs)
# get slider length
style = ttk.Style(self)
style_name = kwargs.get('style', '%s.TScale' % (str(self.scale.cget('orient')).capitalize()))
self.sliderlength = style.lookup(style_name, 'sliderlength', default=30)
self.extent = kwargs['to'] - kwargs['from_']
self.start = kwargs['from_']
# showvalue
if self.showvalue:
ttk.Label(self, text=' ').grid(row=0)
self.label = ttk.Label(self, text='0')
self.label.place(in_=self.scale, bordermode='outside', x=0, y=0, anchor='s')
self.display_value(self.scale.get())
self.scale.grid(row=1, sticky='ew')
# ticks
if self.tickinterval:
ttk.Label(self, text=' ').grid(row=2)
self.ticks = []
self.ticklabels = []
nb_interv = round(self.extent/self.tickinterval)
formatter = '{:.' + str(self.digits) + 'f}'
for i in range(nb_interv + 1):
tick = kwargs['from_'] + i * self.tickinterval
self.ticks.append(tick)
self.ticklabels.append(ttk.Label(self, text=formatter.format(tick)))
self.ticklabels[i].place(in_=self.scale, bordermode='outside', x=0, rely=1, anchor='n')
self.place_ticks()
self.scale.bind('<Configure>', self.on_configure)
def convert_to_pixels(self, value):
return ((value - self.start)/ self.extent) * (self.scale.winfo_width()- self.sliderlength) + self.sliderlength / 2
def display_value(self, value):
# position (in pixel) of the center of the slider
x = self.convert_to_pixels(float(value))
# pay attention to the borders
half_width = self.label.winfo_width() / 2
if x + half_width > self.scale.winfo_width():
x = self.scale.winfo_width() - half_width
elif x - half_width < 0:
x = half_width
self.label.place_configure(x=x)
formatter = '{:.' + str(self.digits) + 'f}'
self.label.configure(text=formatter.format(float(value)))
def place_ticks(self):
# first tick
tick = self.ticks[0]
label = self.ticklabels[0]
x = self.convert_to_pixels(tick)
half_width = label.winfo_width() / 2
if x - half_width < 0:
x = half_width
label.place_configure(x=x)
# ticks in the middle
for tick, label in zip(self.ticks[1:-1], self.ticklabels[1:-1]):
x = self.convert_to_pixels(tick)
label.place_configure(x=x)
# last tick
tick = self.ticks[-1]
label = self.ticklabels[-1]
x = self.convert_to_pixels(tick)
half_width = label.winfo_width() / 2
if x + half_width > self.scale.winfo_width():
x = self.scale.winfo_width() - half_width
label.place_configure(x=x)
def on_configure(self, event):
"""Redisplay the ticks and the label so that they adapt to the new size of the scale."""
self.display_value(self.scale.get())
self.place_ticks()
if __name__ == '__main__':
root = tk.Tk()
root.geometry('400x300')
style = ttk.Style(root)
style.configure('my.Horizontal.TScale', sliderlength=10)
s1 = tk.Scale(root, orient='horizontal', tickinterval=0.2, from_=-1,
to=1, showvalue=True, resolution=0.1, sliderlength=10)
s2 = TtkScale(root, style='my.Horizontal.TScale', orient='horizontal',
tickinterval=0.2, from_=-1, to=1, showvalue=True,
digits=1)
ttk.Label(root, text='tk.Scale').pack()
s1.pack(fill='x')
ttk.Label(root, text='ttk.Scale').pack()
s2.pack(fill='x')
root.mainloop()
此小部件的更完整版本可在 ttkwidgets 中找到。名为 TickScale 的模块。
关于python - 如何让 ttk.Scale 表现得更像 tk.Scale?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47200625/
我有一个功能是转换 ADO Recordset 进入html: class function RecordsetToHtml(const rs: _Recordset): WideString; 该函
经过几天的研究和讨论,我想出了这种方法来收集访客的熵(你可以看到我的研究历史here) 当用户访问时,我运行此代码: $entropy=sha1(microtime().$pepper.$_SERVE
给定一个无序列表 List ,我需要查找是否存在 String与提供的字符串匹配。 所以,我循环 for (String k : keys) { if (Utils.keysM
我已经搜索过这个问题,但没有找到我正在寻找的答案。 基本上,我想将类构造函数包装在 try/except 子句中,以便它忽略构造函数内特定类型的错误(但无论如何都会记录并打印它们)。我发现做到这一点的
我有一组三个数字,我想将一组数字与另一组数字进行比较。即,第一组中的每个数字小于另一组中的至少一个数字。需要注意的是,第一组中的下一个数字必须小于第二组中的不同数字(即,{6,1,6} 对 {8,8,
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 9 年前。 Improve this
首先介绍一下背景: 我正在开发一个带有 EJB 模块和应用程序客户端模块的企业应用程序 (ear)。我还使用 hibernate JPA 来实现持久性,并使用 swingx 来实现 GUI。这些是唯一
我正在尝试在我的上网本上运行 Eclipse 以便能够为 Android 进行开发。 您可能已经猜到了,Eclipse 非常慢,并且不容易有效地开发。 我正在使用 Linux Ubuntu 并且我还有
for row, instrument in enumerate(instruments): for col, value in enumerate(instrument):
return not a and not b ^ 我如何以更好的格式表达它 最佳答案 DeMorgan's Law , 也许? return not (a or b) 我认为在这一点上已经足够简单了
我正在尝试让 Font Awesome 图标看起来更 slim https://jsfiddle.net/cliffeee/7L6ehw9r/1/ . 我尝试使用“-webkit-text-strok
假设我有一个名为 vals 的数据框,如下所示: id…………日期…………min_date…… .........最大日期 1…………2016/01/01…………2017/01/01…………2018/
是否有更 Pythonic 的方式来做到这一点?: if self.name2info[name]['prereqs'] is None: se
我有一个函数可以将一些文本打印到它接收到的 ostream&。如果 ostream 以终端为目标,我想让它适应终端宽度,否则默认为某个值。 我现在做的是: 从 ostream 中获取一个 ofstre
这个问题在这里已经有了答案: Should a retrieval method return 'null' or throw an exception when it can't produce
我有这个 bc = 'off' if c.page == 'blog': bc = 'on' print(bc) 有没有更 Pythonic(和/或更短)的方式在 Python 中编写? 最佳
输入:一个包含 50,000 行的 CSV;每行包含 910 列值 0/1。 输出:运行我的 CNN 的数据框。 我编写了一个逐行读取 CSV 的代码。对于每一行,我将数据分成两部分,称为神经元(90
据我所知,with block 会在您退出 block 后自动调用 close(),并且它通常用于确保不会忘记关闭一个文件。 好像没有技术上的区别 with open(file, 'r+') as f
我有一个使用 Entity Framework V6.1.1 的 MVC 5 网站。 Entity Framework DbContext 类和模型最初都在网站项目中。这个项目有 3 个 DbCont
我是编程新手,在尝试通过将 tableView 和关联 View 的创建移动到单独的类并将委托(delegate)和数据源从 VC 移动到单独的类来精简我的 ViewController 时遇到了一些
我是一名优秀的程序员,十分优秀!