【问题标题】:Arrange Items in PyQt5 QListWidget?在 PyQt5 QListWidget 中排列项目?
【发布时间】:2021-08-25 17:00:33
【问题描述】:

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

  • 列表项以搜索词开始
  • 列表项包含在搜索词的任意位置,最后。
  • 列表项结束在搜索项中。

例如,在我的程序中,我的搜索词是“I”,我想安排以“I”开头的项目(“India”、“Iceland”、“Iran” ),然后是包含任何地方的项目("America", "China", "Fiji","Russia"),最后项目以搜索词"I" (“文莱”、“马里”)

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

【问题讨论】:

  • 无关,但很重要:不要使用全局变量,使用实例属性。此外,每个逗号后都应该有一个空格。
  • 为什么大多数专业人士,对使用全局变量犹豫不决?任何系列。@musicamante
  • 这不是犹豫,而是知识、经验和意识。使用全局变量可能会导致各种问题,包括难以跟踪的意外行为和错误(甚至崩溃)。大多数情况下,它们的使用不当(例如在您的情况下,您应该使用实例属性:self.item_normal 等),而有经验的程序员只有在他们真正知道他们'正在做,他们非常清楚如何使用它们以及为什么他们需要它们。我建议你做一些研究,从this post开始。

标签: python pyqt pyqt5


【解决方案1】:

对于您想要实现的目标,有几种方法可以做。一种是根据键对列表进行排序。

在你的情况下,它可能是

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

输出:

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

如您所见,这种方法存在一个小问题,即 "Mali" 位于列表的中间,而不是接近末尾。

我现在唯一能想到的方法是使用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())
        

【讨论】:

    猜你喜欢
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    相关资源
    最近更新 更多