1

I've a piece of code in which I've added two sub-items to a QTreeWidget parent item. The sub-items are set to be "editable".

I'm facing two problems here:

  1. There appears an extra row with empty editable items. (I want "Min" and "Max" in the same row)

enter image description here

  1. If I change an editable item to an empty string then it appears as if there is nothing, I would like to have some sort of a highlighter that there is an empty field in here(some sort of a box)

enter image description here

How can I get around these issues?

Code:

import sys
from PyQt5.QtCore import *
from PyQt5 import QtCore
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.FilterList = QTreeWidget()
        self.setCentralWidget(self.FilterList)
        self.setWindowTitle("Form")
        self.setGeometry(50,50,800,500)
        self.generateData()

    def generateData(self):
        self.FilterList.setColumnCount(3)
        self.FilterList.setHeaderLabels(["Filter Questions"])
        DifficultyNode = QTreeWidgetItem(["Difficulty"])
        self.FilterList.addTopLevelItem(DifficultyNode)
        self.FilterList.itemChanged.connect(self.handleItemChanged)
        EasyNode = QTreeWidgetItem(["Easy"])
        EasyNode.setCheckState(0, Qt.Unchecked)
        NormalNode = QTreeWidgetItem(["Normal"])
        NormalNode.setCheckState(0, Qt.Unchecked)
        HardNode = QTreeWidgetItem(["Hard"])
        HardNode.setCheckState(0, Qt.Unchecked)
        HardNode.setFlags(HardNode.flags() | QtCore.Qt.ItemIsEditable)
        MinNode = QTreeWidgetItem()
        MinNode.setText(1, "Min")
        MinNode.setFlags(MinNode.flags() | QtCore.Qt.ItemIsEditable)
        MaxNode = QTreeWidgetItem()
        MaxNode.setText(2, "Max")
        MaxNode.setFlags(MaxNode.flags() | QtCore.Qt.ItemIsEditable)
        
        DifficultyNode.addChild(EasyNode)
        EasyNode.addChild(MinNode)
        EasyNode.addChild(MaxNode)
        DifficultyNode.addChild(NormalNode)
        DifficultyNode.addChild(HardNode)
        

    def handleItemChanged(self, item, column):
        if item.checkState(column) == QtCore.Qt.Checked:
            print('Item Checked', item.text(column))
        elif item.checkState(column) == QtCore.Qt.Unchecked:
            print('Item Unchecked', item.text(column))

def main():
    app = QApplication(sys.argv)
    form = MainWindow()
    form.show()
    app.exec_()

main()
Goku
  • 23
  • 7
  • Typo: `MinNode.setText(2, "Max")` --> `MaxNode.setText(2, "Max")` ? – G.M. Nov 07 '21 at 12:55
  • @G.M. Thanks for pointing out the typo, but the things still looks pretty much the same. – Goku Nov 07 '21 at 13:06
  • It's not only when you edit them, there will also be a box when you delete the "Min" or "Max" text and the item is deselected. – alec Nov 09 '21 at 08:08
  • @alec Yes I've understood that much. Maybe the question wasn't clear enough. I don't want a box in column one. I only want it ```only over the items which are editable``` ("Min" and "Max" in this case) and that too from the beginning. – Goku Nov 09 '21 at 08:14
  • @alec I want the user to actually know where he has to enter/edit the values. The moment I delete the "Min", "Max" in this case, the end user will never be able to know where he has to enter the values. – Goku Nov 09 '21 at 08:17

1 Answers1

1

To get "Min" and "Max" on the same row, use only one QTreeWidgetItem and set the text for both columns.

If you want a permanent box, an option is to set the itemWidget of a QTreeWidgetItem to a QLineEdit and connect its editingFinished to set the item text.

class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.FilterList = QTreeWidget()
        self.setCentralWidget(self.FilterList)
        self.setWindowTitle("Form")
        self.setGeometry(50,50,800,500)
        self.generateData()

    def generateData(self):
        self.FilterList.setColumnCount(3)
        self.FilterList.setHeaderLabels(["Filter Questions"])
        DifficultyNode = QTreeWidgetItem(["Difficulty"])
        self.FilterList.addTopLevelItem(DifficultyNode)
        self.FilterList.itemChanged.connect(self.handleItemChanged)
        EasyNode = QTreeWidgetItem(["Easy"])
        EasyNode.setCheckState(0, Qt.Unchecked)
        NormalNode = QTreeWidgetItem(["Normal"])
        NormalNode.setCheckState(0, Qt.Unchecked)
        HardNode = QTreeWidgetItem(["Hard"])
        HardNode.setCheckState(0, Qt.Unchecked)
        HardNode.setFlags(HardNode.flags() | QtCore.Qt.ItemIsEditable)
        MinNode = QTreeWidgetItem()
        
        DifficultyNode.addChild(EasyNode)
        EasyNode.addChild(MinNode)
        DifficultyNode.addChild(NormalNode)
        DifficultyNode.addChild(HardNode)

        self.setTextBox(MinNode, 1, "Min")
        self.setTextBox(MinNode, 2, "Max")

    def setTextBox(self, item, column, text):
        box = QLineEdit(text)
        box.editingFinished.connect(lambda: item.setText(column, box.text()))
        self.FilterList.setItemWidget(item, column, box)

    def handleItemChanged(self, item, column):
        if item.checkState(column) == QtCore.Qt.Checked:
            print('Item Checked', item.text(column))
        elif item.checkState(column) == QtCore.Qt.Unchecked:
            print('Item Unchecked', item.text(column))
alec
  • 5,799
  • 1
  • 7
  • 20