[英]How to justify the characters in drop-down list of a Combobox?
How to justify the values listed in drop-down part of a ttk.Combobox
? 如何证明
ttk.Combobox
的下拉部分中列出的值的ttk.Combobox
? I have tried justify='center'
but that seems to only configure the selected item. 我尝试过
justify='center'
但这似乎只配置所选的项目。 Could use a resource link too if there is, I couldn't find it. 如果有的话,也可以使用资源链接,我找不到它。
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
import tkinter.ttk as ttk
except ImportError:
import Tkinter as tk
import ttk
if __name__ == '__main__':
root = tk.Tk()
cbb = ttk.Combobox(root, justify='center', values=(0, 1, 2))
cbb.pack()
root.mainloop()
(Edit: Note that this solution works for Tcl/Tk versions 8.6.5 and above. @CommonSense notes that some tkinter installations may not be patched yet, and this solution will not work). (编辑:请注意,该解决方案适用于Tcl / Tk版本8.6.5及更高版本。@CommonSense指出,某些tkinter安装可能尚未打补丁,并且该解决方案将不起作用)。
In Tcl ( I don't know python, so one of the python people can edit the question). 在Tcl中(我不了解python,因此其中一个python人员可以编辑问题)。
A combobox is an amalgamation of an 'entry' widget and a 'listbox' widget. 组合框是“条目”小部件和“列表框”小部件的组合。 Sometimes to make the configuration changes you want, you need to access the internal widgets directly.
有时要进行所需的配置更改,您需要直接访问内部窗口小部件。
Tcl: TCL:
% ttk::combobox .cb -values [list a abc def14 kjsdf]
.cb
% pack .cb
% set pd [ttk::combobox::PopdownWindow .cb]
.cb.popdown
% set lb $pd.f.l
.cb.popdown.f.l
% $lb configure -justify center
Python: 蟒蛇:
cb = ttk.Combobox(value=['a', 'abc', 'def14', 'kjsdf'])
cb.pack()
pd = cb.tk.call('ttk::combobox::PopdownWindow', cb)
lb = cb.tk.eval('return {}.f.l'.format(pd))
cb.tk.eval('{} configure -justify center'.format(lb))
Some caveats. 一些警告。 The internals of
ttk::combobox
are subject to change. ttk::combobox
的内部结构可能会发生变化。 Not likely, not anytime soon, but in the future, the hard-coded .fl
could change. 不太可能,不会很快,但是在将来,硬编码的
.fl
可能会更改。
ttk::combobox::PopdownWindow
will force the creation of the listbox when it is called. ttk::combobox::PopdownWindow
将在列表框被调用时强制创建。 A better method is to put the centering adjustment into a procedure and call that procedure when the combobox/listbox is mapped. 更好的方法是将居中调整放入过程中,并在映射组合框/列表框时调用该过程。
This will run for all comboboxes, you will need to check the argument in the proc
to make sure that this is the combobox you want to adjust. 这将在所有组合框上运行,您需要检查
proc
的参数以确保这是您要调整的组合框。
proc cblbhandler { w } {
if { $w eq ".cb" } {
set pd [ttk::combobox::PopdownWindow $w]
set lb $pd.f.l
$lb configure -justify center
}
}
bind ComboboxListbox <Map> +[list ::cblbhandler %W]
Here's one pure Python way that gets close to what you want. 这是一种接近您想要的纯Python方式。 The items in the dropdown list all get justified to fit within the
Combobox
's width (or a default value will be used). 下拉列表中的所有项目都将被证明适合组合
Combobox
的宽度(或将使用默认值)。
Update 更新
Part of the reason the initial version of my answer wasn't quite right was because the code assumed that a fixed-width font was being used. 我的答案的初始版本不太正确的部分原因是因为代码假定正在使用固定宽度的字体。 That's not the case on my test platform at least, so I've modified the code to actually measure the width of values in pixels instead of whole characters, and do essentially what it did originally, but in those units of string-length measure.
至少在我的测试平台上不是这种情况,因此我修改了代码,以实际上以像素而不是整个字符为单位来测量值的宽度,并且基本上执行了它最初的工作,但是以那些字符串长度测量为单位。
import tkinter as tk
import tkinter.font as tkFont
from tkinter import ttk
class CenteredCombobox(ttk.Combobox):
DEFAULT_WIDTH = 20 # Have read that 20 is the default width of an Entry.
def __init__(self, master=None, **kwargs):
values = kwargs.get('values')
if values:
entry = ttk.Entry(None) # Throwaway for getting the default font.
font = tkFont.Font(font=entry['font'])
space_width = font.measure(' ')
entry_width = space_width * kwargs.get('width', self.DEFAULT_WIDTH)
widths = [font.measure(str(value)) for value in values]
longest = max(entry_width, *widths)
justified_values = []
for value, value_width in zip(values, widths):
space_needed = (longest-value_width) / 2
spaces_needed = int(space_needed / space_width)
padding = ' ' * spaces_needed
justified_values.append(padding + str(value))
kwargs['values'] = tuple(justified_values)
super().__init__(master, **kwargs)
root = tk.Tk()
ccb = CenteredCombobox(root, justify='center', width=10, values=('I', 'XLII', 'MMXVIII'))
ccb.pack()
root.mainloop()
I have a one-liner solution. 我有一个一线解决方案。 Use the
.option_add()
method after declaring ttk.Combobox
. 在声明
ttk.Combobox
之后使用.option_add()
方法。 Example: 例:
cbb = ttk.Combobox(root, justify='center', values=(0, 1, 2)) # original
cbb.option_add('*TCombobox*Listbox.Justify', 'center') # new line added
After digging through combobox.tcl
source code I've come up with the following subclass of ttk.Combobox
. 在浏览
combobox.tcl
源代码之后,我提出了ttk.Combobox
的以下子类。 JustifiedCombobox
justifies the pop-down list's items almost precisely after 1 pop-down list's been first created & customized and then displayed. JustifiedCombobox
在首先创建并自定义1个下拉列表然后显示之后,几乎完全可以对下拉列表的项目进行JustifiedCombobox
。 After the pop-down list's been created, setting self.justify
value to a valid one will again, customize the justification almost right after the pop-down list's first been displayed . 创建弹出列表后,将
self.justify
值设置为有效值将再次在弹出列表首次显示后立即自定义对齐。 Enjoy: 请享用:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
from tkinter import ttk
except:
import Tkinter as tk
import ttk
class JustifiedCombobox(ttk.Combobox):
"""
Creates a ttk.Combobox widget with its drop-down list items
justified with self.justify as late as possible.
"""
def __init__(self, master, *args, **kwargs):
ttk.Combobox.__init__(self, master, *args, **kwargs)
self.justify = 'center'
def _justify_popdown_list_text(self):
self._initial_bindtags = self.bindtags()
_bindtags = list(self._initial_bindtags)
_index_of_class_tag = _bindtags.index(self.winfo_class())
# This dummy tag needs to be unique per object, and also needs
# to be not equal to str(object)
self._dummy_tag = '_' + str(self)
_bindtags.insert(_index_of_class_tag + 1, self._dummy_tag)
self.bindtags(tuple(_bindtags))
_events_that_produce_popdown = tuple([ '<KeyPress-Down>',
'<ButtonPress-1>',
'<Shift-ButtonPress-1>',
'<Double-ButtonPress-1>',
'<Triple-ButtonPress-1>',
])
for _event_name in _events_that_produce_popdown:
self.bind_class(self._dummy_tag, _event_name,
self._initial_event_handle)
def _initial_event_handle(self, event):
_instate = str(self['state'])
if _instate != 'disabled':
if event.keysym == 'Down':
self._justify()
else:
_ = self.tk.eval('{} identify element {} {}'.format(self,
event.x, event.y))
__ = self.tk.eval('string match *textarea {}'.format(_))
_is_click_in_entry = bool(int(__))
if (_instate == 'readonly') or (not _is_click_in_entry):
self._justify()
def _justify(self):
self.tk.eval('{}.popdown.f.l configure -justify {}'.format(self,
self.justify))
self.bindtags(self._initial_bindtags)
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == 'justify':
self._justify_popdown_list_text()
def select_handle():
global a
_selected = a['values'][a.current()]
if _selected in ("left", "center", "right"):
a.justify = _selected
if __name__ == '__main__':
root = tk.Tk()
for s in ('normal', 'readonly', 'disabled'):
JustifiedCombobox(root, state=s, values=[1, 2, 3]).grid()
a = JustifiedCombobox(root, values=["Justify me!", "left", "center", "right"])
a.current(0)
a.grid()
a.bind("<<ComboboxSelected>>", lambda event: select_handle())
root.mainloop()
1 It basically makes use of bindtag event queue. 1它基本上利用bindtag事件队列。 This was mostly possible thanks to being able to creating a custom bindtag .
由于能够创建自定义的bindtag ,因此这几乎是可能的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.