Search code examples
pythonpython-3.xpyqtqlistwidgetqlabel

Connect a QLabel with a QListWidget selection


(I'm an absolute PyQt beginner.)

I would like to update a QLabel with the description of a software option whenever the user uses the arrow keys to scroll down a very long list of options displayed in a QListWidget or clicks on an option in the QListWidget. I've already to managed to connect the click option to do what I want to do, but I can't figure out how to detect arrow key presses.

This is what I have so far:

main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>341</width>
    <height>244</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QWidget" name="verticalLayoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>321</width>
     <height>231</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QListWidget" name="lwOptions"/>
    </item>
    <item>
     <widget class="QLabel" name="lbDescription">
      <property name="text">
       <string>TextLabel</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="standardButtons">
       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>Dialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>170</x>
     <y>228</y>
    </hint>
    <hint type="destinationlabel">
     <x>170</x>
     <y>121</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from PyQt5 import uic, QtWidgets
from PyQt5.Qt import QMessageBox

class GUI(QtWidgets.QDialog):
    listOptions = []
    dicDescriptions = {}
    for x in range(0, 100):
        option = 'Option ' + str(x)
        description = 'Description for ' + option
        listOptions.append(option)
        dicDescriptions[option] = description

    def __init__(self):
        super(GUI, self).__init__()
        uic.loadUi('C:/Users/User/Desktop/main.ui', self)
        self.accepted.connect(self.ReadValue)
        self.lwOptions.addItems(self.listOptions)
        self.lwOptions.itemClicked.connect(self.UpdateDescription)
        self.lbDescription.setText(self.dicDescriptions[self.listOptions[0]])

    def UpdateDescription(self):
        currentItem = self.lwOptions.currentItem().text()
        self.lbDescription.setText(self.dicDescriptions[currentItem])

    def ReadValue(self):
        currentItem = self.lwOptions.currentItem().text()
        QMessageBox.information(self, "Selection", "You've selected: " + currentItem)

app = QtWidgets.QApplication(sys.argv)
window = GUI()
window.show()
sys.exit(app.exec_())
  1. How do detect the arrow key presses and update the QLabel.
  2. How do I use uic.loadUi with relative paths? I've tried uic.loadUi('main.ui', self) and uic.loadUi('./main.ui', self), but it didn't work even though both files are in the same folder.

Solution

  • it is not necessary to use itemClicked() if you want to obtain the current item, you must use the signal itemSelectionChanged() that is issued every time a new item is selected. The problem of the path is caused because the path depends on where you execute the script, it does not depend on where the script is, for these cases the recommendable thing is that the code recognizes the full path of the file. The implementation is in the following section:

    import os
    import sys
    from PyQt5 import uic, QtWidgets
    from PyQt5.Qt import QMessageBox
    
    class GUI(QtWidgets.QDialog):
        listOptions = []
        dicDescriptions = {}
        for x in range(0, 100):
            option = 'Option ' + str(x)
            description = 'Description for ' + option
            listOptions.append(option)
            dicDescriptions[option] = description
    
        def __init__(self):
            super(GUI, self).__init__()
            dirname = os.path.dirname(os.path.abspath(__file__))
            uic.loadUi(os.path.join(dirname,'main.ui'), self)
            self.accepted.connect(self.read_value)
            self.lwOptions.addItems(self.listOptions)
            self.lbDescription.setText(self.dicDescriptions[self.listOptions[0]])
            self.lwOptions.itemSelectionChanged.connect(self.update_description)
    
        def update_description(self):
            currentItem = self.lwOptions.currentItem().text()
            self.lbDescription.setText(self.dicDescriptions[currentItem])
    
        def read_value(self):
            currentItem = self.lwOptions.currentItem().text()
            QMessageBox.information(self, "Selection", "You've selected: " + currentItem)
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        window = GUI()
        window.show()
        sys.exit(app.exec_())