How to QComboBox Items arranged in given order, or reversely giv

ghz 昨天 ⋅ 2 views

How to QComboBox Items arranged in given order, or reversely given order or a to z or z to a in PyQt5?

My aim is to rearrange combo box items in

  1. Alphabetically ascending order (A to Z),
  2. Alphabetically Descending Order(Z to A).
  3. Given Order ( As per the list, no change, that is the first item is America, the Second is Russia and the Last One is India)
  4. Given Order in reverse order (Item in reverse order, that is the First item is India, the second one is France and the Last One is America)

Here is my code. Mouse right-click in combo box will show my option. Based on user selection, items in Qcombo Box will rearrange. How to get it?

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QComboBox, QPushButton, QVBoxLayout,QMenu,QDesktopWidget,QMainWindow
from PyQt5.QtCore import Qt,QPoint,pyqtSignal,QSize

class CheckableComboBox(QComboBox):

    def __init__(self):
        super().__init__()

        self.setEditable(True)
        self.lineEdit().setReadOnly(True)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showMenu)

        self.setStyleSheet("QComboBox QAbstractItemView::item {border: none;padding-left: 5px;}")
        self.lineEdit().installEventFilter(self)
        self.closeOnLineEditClick = True
        self.double_click = None

    def showMenu(self,pos):
        menu = QMenu()
        atoz_action = menu.addAction("A to Z - Ascending Order")
        ztoa_action = menu.addAction(("Z to A - Descending Order"))
        copy_action1 = menu.addSeparator()
        copy_action2 = menu.addAction(("Given Order"))
        copy_action3 = menu.addAction(("Given Order - Reverse"))

        mainwindow_geomentry = QDesktopWidget().screenGeometry()
        widget_qpoint = (self.mapToGlobal(QPoint()))
        widget_qpoint_x = widget_qpoint.x()

        xpos = mainwindow_geomentry.width() - (self.size().width()+menu.sizeHint().width())
        xx =  xpos - widget_qpoint_x

        if xx <= 0 :
            aa = 0-(menu.sizeHint().width())
        else:
            aa = self.size().width()

        action = menu.exec_(self.mapToGlobal(QPoint(aa-2,0)))

        if action == atoz_action:
            self.model().sort(0)
            self.setCurrentIndex(0)
        elif action == ztoa_action:
            print("bbbbbbbbbb")

class MyApp(QWidget):

    def __init__(self):
        super().__init__()

        mainLayout = QVBoxLayout()
        self.setLayout(mainLayout)

        self.data = ['America', 'Russia', 'China', 'Germany', 'France', 'India']

        self.combo = CheckableComboBox()
        self.combo.setMinimumSize(600,40)

        btn = QPushButton('Print Values')
        btn.clicked.connect(self.getValue)

        mainLayout.addWidget(self.combo)
        mainLayout.addWidget(btn)

        self.combo.addItems(self.data)

    def getValue(self):
        print(self.combo.currentData())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet('''QWidget {font-size: 20px;}''')
    myApp = MyApp()
    myApp.show()
    app.exit(app.exec_())

I will try to solve it in ascending order(first case) by self. model().sort(0). Its work. But I was Struck with another three cases. I can't able to solve it.

Answer

To implement the different sorting orders you want for the QComboBox in PyQt, we can break down the logic for each case. Since you've already successfully handled the ascending order (A to Z), we'll use similar techniques for the other three cases:

Plan:

  1. Ascending Order (A to Z) – Already handled by calling self.model().sort(0).
  2. Descending Order (Z to A) – Reverse the list of items.
  3. Given Order – No change, items in the order they were added.
  4. Given Order in Reverse – Reverse the list of items.

Code Updates

You will need to modify the showMenu method to handle these actions and apply the appropriate sorting logic. Below is the updated code to handle all four cases:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QComboBox, QPushButton, QVBoxLayout, QMenu, QDesktopWidget
from PyQt5.QtCore import Qt, QPoint

class CheckableComboBox(QComboBox):

    def __init__(self):
        super().__init__()

        self.setEditable(True)
        self.lineEdit().setReadOnly(True)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showMenu)

        self.setStyleSheet("QComboBox QAbstractItemView::item {border: none;padding-left: 5px;}")
        self.lineEdit().installEventFilter(self)
        self.closeOnLineEditClick = True
        self.double_click = None

    def showMenu(self, pos):
        menu = QMenu()
        # Add actions to the context menu
        atoz_action = menu.addAction("A to Z - Ascending Order")
        ztoa_action = menu.addAction("Z to A - Descending Order")
        menu.addSeparator()
        copy_action2 = menu.addAction("Given Order")
        copy_action3 = menu.addAction("Given Order - Reverse")

        # Display the menu at the mouse position
        action = menu.exec_(self.mapToGlobal(pos))

        # Handling each menu option
        if action == atoz_action:
            self.sortItemsAscending()
        elif action == ztoa_action:
            self.sortItemsDescending()
        elif action == copy_action2:
            self.resetOrder()
        elif action == copy_action3:
            self.reverseOrder()

    def sortItemsAscending(self):
        """Sort items in ascending order (A to Z)."""
        self.model().sort(0)  # Sorts the items alphabetically ascending
        self.setCurrentIndex(0)

    def sortItemsDescending(self):
        """Sort items in descending order (Z to A)."""
        # Get the items, reverse the list and set the model back
        items = [self.itemText(i) for i in range(self.count())]
        items.reverse()
        self.clear()
        self.addItems(items)
        self.setCurrentIndex(0)

    def resetOrder(self):
        """Reset to the original order of items (no change)."""
        # Reset the items in the combo box as they were initially added
        items = ['America', 'Russia', 'China', 'Germany', 'France', 'India']
        self.clear()
        self.addItems(items)
        self.setCurrentIndex(0)

    def reverseOrder(self):
        """Reverse the order of the items."""
        # Reverse the original order of items
        items = ['America', 'Russia', 'China', 'Germany', 'France', 'India']
        items.reverse()
        self.clear()
        self.addItems(items)
        self.setCurrentIndex(0)


class MyApp(QWidget):

    def __init__(self):
        super().__init__()

        mainLayout = QVBoxLayout()
        self.setLayout(mainLayout)

        self.data = ['America', 'Russia', 'China', 'Germany', 'France', 'India']

        self.combo = CheckableComboBox()
        self.combo.setMinimumSize(600, 40)

        btn = QPushButton('Print Values')
        btn.clicked.connect(self.getValue)

        mainLayout.addWidget(self.combo)
        mainLayout.addWidget(btn)

        self.combo.addItems(self.data)

    def getValue(self):
        print(self.combo.currentText())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet('''QWidget {font-size: 20px;}''')
    myApp = MyApp()
    myApp.show()
    app.exit(app.exec_())

Explanation:

  1. Ascending Order (A to Z) – This is handled using self.model().sort(0) which sorts the combo box items in ascending order.

  2. Descending Order (Z to A) – We first fetch all the items using a list comprehension, reverse the list, and then clear and re-add the items in the reversed order.

  3. Given Order – To reset the order to the original state (as it was when the items were initially added), we clear the combo box and re-add the items in their original order.

  4. Given Order in Reverse – Similar to the previous case, we reverse the original list of items and then reset the combo box.

How It Works:

  • The showMenu method shows a context menu when you right-click on the combo box.

  • Based on the user's selection from the context menu, the corresponding function is executed to rearrange the combo box items.

  • The sorting logic is applied to the combo box directly, modifying the order of the items based on the user's choice.

Output:

  • Right-click on the combo box: A context menu will appear with the options "A to Z", "Z to A", "Given Order", and "Given Order - Reverse".
  • Selecting an option will rearrange the items in the combo box as per the logic in the selected option.

This should give you the desired functionality of rearranging the combo box items in the four different orders.