在 PyQt5 QListWidget 中排列项目?

Arrange Items in PyQt5 QListWidget?

如何按以下顺序排列过滤后的 QListwidget 项,

例如,在我的程序中,我的搜索词是 "I",我想排列以 "I" 开头的项目 ("India", “冰岛”、“伊朗”),然后项目包含任何地方 (“美国”、“中国”、“斐济”、“俄罗斯”),最后项目以搜索字词 "I" ("Brunei", "Mali")

import sys
from PyQt5.QtWidgets import QApplication,QWidget,QListWidget,QLineEdit,QVBoxLayout
from PyQt5.QtCore import Qt,QEvent

items = ["America","canada","Mali","India","Russia", "Fiji","Nepal","Iran","China","Japan","IceLand","Brunei"]

class Listwidget(QWidget):
    def __init__(self):
        super(). __init__()
        self.setWindowTitle("List Box Samples")

        self.le = QLineEdit()
        self.le.textChanged.connect(self.func_textchanged)
        self.lb_master = QListWidget()
        self.lb_search = QListWidget()
        vbox = QVBoxLayout(self)
        vbox.addWidget(self.le)
        vbox.addWidget(self.lb_search)

        self.lb_master.addItems(items)
        self.lb_search.addItems(items)
        self.le.setFocus()

        self.le.installEventFilter(self)

    def eventFilter(self, source,event):
        if event.type() == QEvent.KeyPress and source is self.le:
            if event.key() == Qt.Key_Backspace:
                if len(self.le.text()) == 0:
                    self.fun_normal()
        return super(Listwidget,self).eventFilter(source,event)


    def fun_normal(self):
        self.lb_search.clear()
        if normal_count > 0:
            for item in item_normal:
                self.lb_search.addItem(item.text())

    def func_search(self):
        self.lb_search.clear()
        if search_count > 0:
            for item in item_anywhere:
                self.lb_search.addItem(item.text())

    def func_textchanged(self):
        global item_normal,item_anywhere,search_count,normal_count

        item_normal = self.lb_master.findItems("*",Qt.MatchWildcard)
        item_anywhere = self.lb_master.findItems(self.le.text(), Qt.MatchContains)

        normal_count = len(item_normal)
        search_count = len(item_anywhere)

        self.func_search()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Listwidget()
    win.show()
    sys.exit(app.exec_())

实现您想要实现的目标的方法很少。一种是根据键对列表进行排序。

你的情况可能是

item_anywhere.sort(key=lambda item: item.text().lower().find(self.le.text()))

输出:

['India', 'Iran', 'IceLand', 'Fiji', 'China', 'Mali', 'America', 'Russia', 'Brunei']

如您所见,这种方法存在一个小问题,即“马里”在列表的中间,而不是最后。

我现在唯一能想到的方法是使用 filter 函数。

以下是我遵循的步骤:

  1. 使用 find 方法查找字符串(您已经完成了这部分)。
  2. 现在使用该列表并根据以 I 开头的单词或任何搜索文本对其进行过滤。
  3. 根据包含搜索字母的单词过滤列表,然后按上面所示对该列表进行排序。
  4. 根据以 I 结尾的单词过滤列表。
  5. 连接列表
    def func_textchanged(self):

        search_text = self.le.text().lower()
        item_anywhere = self.lb_master.findItems(search_text, Qt.MatchContains)

        start_list = list(filter(lambda item: item.text().lower().startswith(search_text), item_anywhere))
        start_text = [x.text().lower() for x in start_list]

        def bw_filter(item):
            # checks if the letter is between the start and end letter, then checks if it already exists in start_list
            item_text = item.text().lower()
            return search_text in item_text[1:-1] and item_text not in start_text

        bw_lst = list(filter(bw_filter, item_anywhere))
        bw_lst.sort(key=lambda item: item.text().lower().find(search_text))  # sort it based on index
        bw_text = [x.text().lower() for x in bw_lst]

        def end_filter(item):
            # checks if the string ends with search string, then checks if it already exists in
            # start_list and between list
            item_text = item.text().lower()
            return item_text.endswith(search_text) and item_text.lower() not in start_text and item_text not in bw_text

        end_lst = list(filter(end_filter, item_anywhere))

        self.lb_search.clear()
        for item in start_list + bw_lst + end_lst:  # concatenate list
            self.lb_search.addItem(item.text())