2

To this question I am referring to the answer from @Andy PyQt Tree Widget, adding check boxes for dynamic removal

There @Andy shows how to add CheckBox into the QTreeWidget, which works perfect.

I would like ask here, how to add RadioButton into QTreeWidget? ----And, which is more difficult for me, how to make only one item selectable, although they are in different groups?

I rewrite the code from @Andy into PyQt5:

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

def main(): 
    app     = QApplication (sys.argv)
    tree    = QTreeWidget ()
    headerItem  = QTreeWidgetItem()
    item    = QTreeWidgetItem()

    for i in range(3):
        parent = QTreeWidgetItem(tree)
        parent.setText(0, "Parent {}".format(i))
        parent.setFlags(parent.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
        for x in range(5):
            child = QTreeWidgetItem(parent)
            child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
            child.setText(0, "Child {}".format(x))
            child.setCheckState(0, Qt.Unchecked)
    tree.show() 
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

The running result of the code above:

enter image description here

UPDATE: The desired result should be like as followings... enter image description here

Any help will be highly appreciated! Thanks!

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Rt Rtt
  • 595
  • 2
  • 13
  • 33
  • You could explain what it means: *how to make only one item selectable, although they are in different groups?* – eyllanesc Feb 02 '18 at 03:33
  • What is a group and what do you mean that is in another group? Do you mean each group is associated with parent0, parent1, etc, and that the same items are for example those with the same name? – eyllanesc Feb 02 '18 at 03:34
  • Do you want the parents to also have the QRadioButton? – eyllanesc Feb 02 '18 at 03:37
  • All parents will have the same children? – eyllanesc Feb 02 '18 at 03:37
  • @eyllanesc Thanks for the answer. I added a picture above to explain my question. Please have a look. The name of the groups is not important. In summery my questions: 1 how to add Radiobutton, and 2 how to make Radiobutton 'unique'. – Rt Rtt Feb 02 '18 at 03:50
  • @eyllanesc Some of the Children have the same Name, but they are different because they are in different groups. – Rt Rtt Feb 02 '18 at 03:51
  • From what I understand, only one radiobutton of each group should be selectable. I am right? – eyllanesc Feb 02 '18 at 03:51
  • @eyllanesc If one Radiobutton is selected, regardless of the group, all the other Radiobuttons should be UNchecked. Only one Radiobutton at one time. That is what I am planning to do. – Rt Rtt Feb 02 '18 at 03:55
  • @eyllanesc Hi, I understand now to make the unique checkable of Radiobutton is not good for the task. Thus I changed my question again. It would be fine if the Radiobuttons are shown. Would you please have a look on it? Thanks. – Rt Rtt Feb 02 '18 at 05:24
  • Restore your question, I just implemented the complete solution. – eyllanesc Feb 02 '18 at 05:26
  • @eyllanesc Oh, that would be great then! I will restore the question then. – Rt Rtt Feb 02 '18 at 05:28

1 Answers1

5

If you want to establish a QRadioButton and it is exclusive in a group, a possible solution is to implement a delegate, in this delegate we will overwrite the paint method to draw the QRadioButton and the editorEvent method to catch the click event and change the status of the other items according to be the case.

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


class Delegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        if not index.parent().isValid():
            QStyledItemDelegate.paint(self, painter, option, index)
        else:
            widget = option.widget
            style = widget.style() if widget else QApplication.style()
            opt = QStyleOptionButton()
            opt.rect = option.rect
            opt.text = index.data()
            opt.state |= QStyle.State_On if index.data(Qt.CheckStateRole) else QStyle.State_Off
            style.drawControl(QStyle.CE_RadioButton, opt, painter, widget)

    def editorEvent(self, event, model, option, index):
        value = QStyledItemDelegate.editorEvent(self, event, model, option, index)
        if value:
            if event.type() == QEvent.MouseButtonRelease:
                if index.data(Qt.CheckStateRole) == Qt.Checked:
                    parent = index.parent()
                    for i in range(model.rowCount(parent)):
                        if i != index.row():
                            ix = parent.child(i, 0)
                            model.setData(ix, Qt.Unchecked, Qt.CheckStateRole)

        return value


def main():
    app = QApplication(sys.argv)
    tree = QTreeWidget()
    tree.setItemDelegate(Delegate())

    for i in range(3):
        parent = QTreeWidgetItem(tree)
        parent.setText(0, "Parent {}".format(i))
        for x in range(5):
            child = QTreeWidgetItem(parent)
            child.setFlags(child.flags() | Qt.ItemIsUserCheckable)
            child.setText(0, "Child {}".format(x))
            child.setCheckState(0, Qt.Unchecked)

    tree.expandAll()
    tree.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you so much! – Rt Rtt Feb 02 '18 at 05:53
  • It also helps to add a check on uncheck status, so when the same item is selected, the radio button doesn't disappear. – QuirkyBit Jul 12 '20 at 21:02
  • ` if index.data(QtCore.Qt.CheckStateRole) == QtCore.Qt.Unchecked: parent = index.parent() for i in range(model.rowCount(parent)): if i == index.row(): ix = parent.child(i, 0) model.setData(ix, QtCore.Qt.Checked, QtCore.Qt.CheckStateRole)` – QuirkyBit Jul 12 '20 at 21:03