Get previous and newly selected item on activation in QComboBox
Asked Answered
P

2

9

In my program some comboboxes (QComboBox) were used to make several settings. Sometimes its necessary not only to know the item the user selected but also the item which was selected previously in the combobox. Well, transferring the new selection is quite easy:

self.MyCombobox.activated[str].connect(self.ComboChange)

But how do i manage to not only passing the newly selected but also the previous item to a function when the index changed?

My compromise solution would be to manually set a variable for every combobox which stores the last selected value so that it can be accessed when the selction has changed. But considering that i have a lot of Comboboxes this would be quite prone to errors until some boxes could be updated on different ways.

Thanks in advance for your help

A minimal working example:

import sys

from PyQt5.QtWidgets import (   QApplication, QWidget, QGridLayout, QComboBox,
                                QLabel)

class BaseWidget(QWidget):
    def __init__(self):
        super(BaseWidget, self).__init__()
        self.setGeometry(300, 300, 300, 200)

        # 2 Labels to display the new and the old item after selection
        self.LabelOldItem = QLabel(self)
        self.LabelNewItem = QLabel(self)

        self.MyCombobox = QComboBox(self)
        self.MyCombobox.addItems(['Item 1', 'Item 2', 'Item 3', 'Item 4'])
        self.MyCombobox.activated[str].connect(self.ComboChange)


        grid = QGridLayout()
        grid.addWidget(self.MyCombobox, 0, 0, 1, 1)
        grid.addWidget(self.LabelOldItem, 1, 0, 1, 1)
        grid.addWidget(self.LabelNewItem, 2, 0, 1, 1)

        self.setLayout(grid)

    def ComboChange(self, newitem):
        self.LabelOldItem.setText('Previous Selection: ') # <- crucial point
        # How can i transfer both, not only the new item but also the previous
        # item of the combobox when it gets activated?
        self.LabelNewItem.setText('New Selection: <b>' + newitem + '</b>')


if __name__ == '__main__':

    app = QApplication(sys.argv)

    pyqtComboExample = BaseWidget()
    pyqtComboExample.show()
    sys.exit(app.exec_())

Minimal working example

Pozsony answered 11/9, 2018 at 7:34 Comment(0)
C
6

A possible solution is to create a custom QComboBox:

import sys
from PyQt5 import QtCore, QtWidgets


class ComboBox(QtWidgets.QComboBox):
    new_signal = QtCore.pyqtSignal(str, str)

    def __init__(self, parent=None):
        super(ComboBox, self).__init__(parent)
        self.lastSelected = ""
        self.activated[str].connect(self.onActivated)

    def onActivated(self, text):
        self.new_signal.emit(self.lastSelected, text)
        self.lastSelected = text


class BaseWidget(QtWidgets.QWidget):
    def __init__(self):
        super(BaseWidget, self).__init__()
        self.setGeometry(300, 300, 300, 200)

        # 2 Labels to display the new and the old item after selection
        self.LabelOldItem = QtWidgets.QLabel()
        self.LabelNewItem = QtWidgets.QLabel()

        self.MyCombobox = ComboBox()
        self.MyCombobox.addItems(['Item 1', 'Item 2', 'Item 3', 'Item 4'])
        self.MyCombobox.new_signal.connect(self.ComboChange)

        grid = QtWidgets.QGridLayout(self)
        grid.addWidget(self.MyCombobox, 0, 0, 1, 1)
        grid.addWidget(self.LabelOldItem, 1, 0, 1, 1)
        grid.addWidget(self.LabelNewItem, 2, 0, 1, 1)

    def ComboChange(self, lastitem, newitem):
        self.LabelOldItem.setText('Previous Selection: <b>{}</b>'.format(lastitem))
        self.LabelNewItem.setText('New Selection: <b>{}</b>'.format(newitem))


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    pyqtComboExample = BaseWidget()
    pyqtComboExample.show()
    sys.exit(app.exec_())

Another possible solution is to use sender() to get the QComboBox used, and save the old item in a property:

import sys
from PyQt5 import QtCore, QtWidgets


class BaseWidget(QtWidgets.QWidget):
    def __init__(self):
        super(BaseWidget, self).__init__()
        self.setGeometry(300, 300, 300, 200)

        # 2 Labels to display the new and the old item after selection
        self.LabelOldItem = QtWidgets.QLabel()
        self.LabelNewItem = QtWidgets.QLabel()

        self.MyCombobox = QtWidgets.QComboBox()
        self.MyCombobox.addItems(['Item 1', 'Item 2', 'Item 3', 'Item 4'])
        self.MyCombobox.activated[str].connect(self.ComboChange)

        grid = QtWidgets.QGridLayout(self)
        grid.addWidget(self.MyCombobox, 0, 0, 1, 1)
        grid.addWidget(self.LabelOldItem, 1, 0, 1, 1)
        grid.addWidget(self.LabelNewItem, 2, 0, 1, 1)

    def ComboChange(self, newitem):
        combo = self.sender()
        lastitem = combo.property("lastitem")
        self.LabelOldItem.setText('Previous Selection: <b>{}</b>'.format(lastitem))
        self.LabelNewItem.setText('New Selection: <b>{}</b>'.format(newitem))
        combo.setProperty("lastitem", newitem)


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    pyqtComboExample = BaseWidget()
    pyqtComboExample.show()
    sys.exit(app.exec_())
Chirrup answered 11/9, 2018 at 7:51 Comment(1)
Exactly what I was looking for. Creating an custom QComboBox was one thing what i've already considered before, but somehow i did not manage to get it working. Thank you for your help!Pozsony
H
0

Adding to eyllanesc answer

For the custom combobox use:

self.textActivated[str].connect(self.onActivated)

instead of:

self.activated[str].connect(self.onActivated)

if you want to use PyQt6

Hudgins answered 15/4 at 1:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.