如何使用换行符显示单个Tkinter Listbox元素?

时间:2017-03-08 22:52:38

标签: python string user-interface tkinter listbox

我有一个工作Tkinter.Listbox对象,但是我想设置它以使其元素可以有回车而不必以某种方式设置多个链接项。

例如,如果我想生成一个包含看起来像这样的项目的选择窗格..

    # Here are four elements for the selector Listbox..
lb_items = ('mama', 'luigi', 'my birds', \
            'this is a single element\n spanning two lines!')
    # This generates and displays the selector window..
tk_selector = SingleSelect(lb_items, "TEST SELECTOR")
tk_selector.run_selector()

..如果我能让输出看起来像这个模型那就太棒了。

n.b.: this is just a mockup

..而不是实际生成的,这就是..

you can't see it, but that's all one line.

列表框似乎忽略了'\n'并且三重引用带有换行符的字符串;如果使用\n,则不会出现字符和换行符。

是否可以使单个可选择的列表框元素显示换行符?

我也会对自动换行选项感到满意,但经过一番查看后,我无法在ListboxTk中找到任何此类选项。

我可能通过将多行字符串变成多个元素然后将其设置为返回整行(如果其中任何一个被调用)来伪造效果,但感觉就像是一个可以有一个简单解决方案的折磨。

2 个答案:

答案 0 :(得分:2)

列表框项目不可能分布在多个行或行中。

答案 1 :(得分:2)

就像布莱恩·奥克利所说的那样,Listbox没有本地支持回程,所以我尝试建立假冒的#39;我在问题中提到的版本,事实证明它并不是那么难。

我的解决方案是解析每个&#39; raw&#39;在将它们插入Listbox之前使用字符串,使用splitlines将字符串分成单独的行,记录行数和列表框元素卷中的哪些索引对应于哪个未完整的输入字符串,然后每当列表框的选择使用Listbox.bind('<<ListboxSelect>>', self._reselection_fxn)更改时选择所有部分。

class Multiline_Single_Selector(object):
      ## Go ahead and choose a better class name than this, too. :/
    def __init__(self, itemlist, ..):
              # ..
        lb_splitlines = self._parse_strings(itemlist) 
          # ^ splits the raw strings and records their indices.
          #  returns the split strings as a list of Listbox elements.
        self.my_Listbox.insert(0, *lb_splitlines) 
          # ^ put the converted strings into the Listbox..

        self.my_Listbox.bind('<<ListboxSelect>>', self._reselect)
          # ^ Whenever the Listbox selection is modifed, it triggers the
          #  <<ListboxSelect>> event. Bind _reselect to it to determine
          #  which lines ought to be highlighted when the selection updates.
              # ..

    def _parse_strings(self, string_list):
        '''Accepts a list of strings and breaks each string into a series of lines,
logs the sets, and stores them in the item_roster and string_register attributes.
Returns the split strings to be inserted into a Listbox.'''

        self.index_sets = index_sets = []
          # ^ Each element in this list is a tuple containing the first and last
          #  Listbox element indices for a set of lines. 

        self.string_register = register = {}
          # ^ A dict with a whole string element keyed to the index of the its
          #  first element in the Listbox.

        all_lines = [] 
          # ^ A list of every Listbox element. When a string is broken into lines,
          #  the lines go in here.

        line_number = 0
        for item in string_list: 
            lines = item.splitlines()

            all_lines.extend(lines) # add the divided string to the string stack
            register[line_number] = item
                # ^ Saves this item keyed to the first Listbox element it's associated
                #  with. If the item is selected when the Listbox closes, the original 
                #  (whole) string is found and returned based on this index number.

            qty = len(lines)
            if qty == 1: # single line item..
                index_sets.append((line_number, line_number))
            else: # multiple lines in this item..
                element_range = line_number, line_number + qty - 1 
                  # ^ the range of Listbox indices..
                index_sets.extend([element_range] * qty) 
                  # ^ ..one for each element in the Listbox.

            line_number += qty # increment the line number.
        return all_lines

    def _reselect(self, event=None):
        "Called whenever the Listbox's selection changes."
        selection = self.my_Listbox.curselection() # Get the new selection data.
        if not selection: # if there is nothing selected, do nothing.
            return

        lines_st, lines_ed = self.index_sets[selection[0]]
            # ^ Get the string block associated with the current selection.
        self.my_Listbox.selection_set(lines_st, lines_ed) 
            # ^ select all lines associated with the original string.

    def _recall(self, event=None):
        "Get the complete string for the currently selected item."
        selection = self.my_Listbox.curselection()
        if selection: # an item is selected!
            return self.string_register[selection[0]]
        return None   # no item is selected.

如果您调整此代码以匹配您自己的代码并将其放入现有的列表框设置中,则应该让您模拟回车。它与\n中的原生换行或Listbox - 解析函数不同,但它的作用基本相同。

要获取与当前选择对应的整个字符串,只需将_recall绑定到要返回的任何输入或事件。在这种情况下,当没有选择任何项目时,它会返回None

考虑到所需效果的复杂性,这也是一项很多工作,并且可能并不适用于所有情况。但至少你可以做到。