繁体   English   中英

如何调整组合框下拉列表中的字符?

[英]How to justify the characters in drop-down list of a Combobox?

如何证明ttk.Combobox的下拉部分中列出的值的ttk.Combobox 我尝试过justify='center'但这似乎只配置所选的项目。 如果有的话,也可以使用资源链接,我找不到它。

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()

(编辑:请注意,该解决方案适用于Tcl / Tk版本8.6.5及更高版本。@CommonSense指出,某些tkinter安装可能尚未打补丁,并且该解决方案将不起作用)。

在Tcl中(我不了解python,因此其中一个python人员可以编辑问题)。

组合框是“条目”小部件和“列表框”小部件的组合。 有时要进行所需的配置更改,您需要直接访问内部窗口小部件。

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

蟒蛇:

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))

一些警告。 ttk::combobox的内部结构可能会发生变化。 不太可能,不会很快,但是在将来,硬编码的.fl可能会更改。

ttk::combobox::PopdownWindow将在列表框被调用时强制创建。 更好的方法是将居中调整放入过程中,并在映射组合框/列表框时调用该过程。

这将在所有组合框上运行,您需要检查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]

这是一种接近您想要的纯Python方式。 下拉列表中的所有项目都将被证明适合组合Combobox的宽度(或将使用默认值)。

更新

我的答案的初始版本不太正确的部分原因是因为代码假定正在使用固定宽度的字体。 至少在我的测试平台上不是这种情况,因此我修改了代码,以实际上以像素而不是整个字符为单位来测量值的宽度,并且基本上执行了它最初的工作,但是以那些字符串长度测量为单位。

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()

我有一个一线解决方案。 在声明ttk.Combobox之后使用.option_add()方法。 例:

cbb = ttk.Combobox(root, justify='center', values=(0, 1, 2)) # original
cbb.option_add('*TCombobox*Listbox.Justify', 'center')       # new line added

在浏览combobox.tcl源代码之后,我提出了ttk.Combobox的以下子类。 JustifiedCombobox在首先创建并自定义1个下拉列表然后显示之后,几乎完全可以对下拉列表的项目进行JustifiedCombobox 创建弹出列表后,将self.justify值设置为有效值将再次在弹出列表首次显示后立即自定义对齐。 请享用:

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它基本上利用bindtag事件队列。 由于能够创建自定义的bindtag ,因此这几乎是可能的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM