简体   繁体   中英

Arrange Items in PyQt5 QListWidget?

How to arrange the filtered QListwidget items in the following order,

  • List item starting with the search term.
  • List item containing anywhere in the search term and finally.
  • List item ends in the search item.

For example, In My Program, my search term is "I" , I want to arrange item starts with "I" ("India", "Iceland", "Iran") , then item containing anywhere ("America", "China", "Fiji","Russia") , finally items end with search term "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_())

There are few ways to do go about what you are trying to acheive. One is to sort the list based on a key.

In your case, it could be

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

Output:

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

As you can see there is a small problem with this approach, that is, "Mali" is in the middle of the list and not towards the end.

The only approach I could think of right now is to use filter function.

Below are the steps I followed:

  1. use the find method to find the strings (you have already done this part).
  2. Now use that list and filter it based on words starting with I or whatever the search text is.
  3. filter the list based on words that contain the search letter between them, then use sort as shown above on this list.
  4. filter the list based on words ending with I .
  5. concatenate the list
    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())
        

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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