PDA

View Full Version : Custom tree view with checkbox and icon - Plz help



ttvo
26th January 2009, 23:23
Hi all,

I'm new to Qt and really need help with subclassing the QAbstractItemModel to create a custom tree with:
1) checkbox or radio button or nothing
2) icon
3) label1 - item name
4) label2 - which is a count of label1's children

See attached image. THANKS IN ADVANCE.


Trish

jpn
27th January 2009, 13:55
Qt item views support checkable items with icons out of the box. All you need is to create a QItemDelegate subclass to render the default check box as a radio button instead. You can use QStyle for that.

ttvo
11th February 2009, 00:14
Thanks. I currently have the following code


QStandardItemModel *model = new QStandardItemModel();
QStandardItem *parentItem = new QStandardItem(QIcon("C:\\dataset_small.png"), "Authors");
model->appendRow(parentItem);
QStandardItem *author1 = new QStandardItem(QIcon("C:\\dataset_small.png"), "Smith, V");
author1->setCheckable(true);
parentItem->appendRow(author1);
parentItem->appendRow(new QStandardItem(QIcon("C:\\dataset_small.png"), "Campbell, C"));
for (int i = 0; i < 3; ++i) {
QStandardItem *item = new QStandardItem(QIcon("C:\\dataset_small.png"), QString("Book # %0").arg(i+1));
item->setCheckable(true);
author1->insertRow(i, item);
}
ui.treeView->setModel(model);

producing the attached image. Remaining things are:
1) I like the checkbox for the author node, but I'd like to have the radio button for the book items to force only one book can be selected at the time. Could you please elaborate on the QItemDelegate?
2) I also want to have a count of children next to the labels meaning I want to have a "2" next to the "Authors" string (since there are 2 authors) and a "3" next to "Smith, V" because he has 3 books

jpn
11th February 2009, 11:57
1) I like the checkbox for the author node, but I'd like to have the radio button for the book items to force only one book can be selected at the time. Could you please elaborate on the QItemDelegate?

The exclusively checked items should be handled at model side, for example by reimplementing QStandardItem::setData() and handling Qt::CheckStateRole. The visual appearance can be handled by overriding QItemDelegate::drawCheck(). Construct a style option and call QStyle::drawPrimitive(QStyle::PE_IndicatorRadioBut ton).


2) I also want to have a count of children next to the labels meaning I want to have a "2" next to the "Authors" string (since there are 2 authors) and a "3" next to "Smith, V" because he has 3 books
You could reimplement QStandardItem::data() and append rowCount() to Qt::DisplayRole.

ttvo
12th February 2009, 01:01
The exclusively checked items should be handled at model side, for example by reimplementing QStandardItem::setData() and handling Qt::CheckStateRole. The visual appearance can be handled by overriding QItemDelegate::drawCheck(). Construct a style option and call QStyle::drawPrimitive(QStyle::PE_IndicatorRadioBut ton).

ok, I add the following code for the radiobutton

void RadioButtonDelegate::drawCheck(QPainter *painter,
const QStyleOptionViewItem &option,
const QRect &rect, Qt::CheckState state) const
{
// Q_D(const QItemDelegate);
if (!rect.isValid())
return;

QStyleOptionViewItem opt(option);
opt.rect = rect;
opt.state = opt.state & ~QStyle::State_HasFocus;

switch (state) {
case Qt::Unchecked:
opt.state |= QStyle::State_Off;
break;
case Qt::PartiallyChecked:
opt.state |= QStyle::State_NoChange;
break;
case Qt::Checked:
opt.state |= QStyle::State_On;
break;
}

// const QWidget *widget = d->widget(option);
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_IndicatorRadioButton, &opt, painter);
}
Note that I had to comment out the Q_D(const QItemDelegate) here in order for my code to compile
1) what is the equivalent code for "Q_D(const QItemDelegate);"? I'd like to understand this since the Q_D appears in QStandardItem::setdata() and data().
2) My tree now only has radiobuttons. How can I customize it such that the author node has checkboxes and only the book node has radiobuttons?
Many thx in advance.


You could reimplement QStandardItem::data() and append rowCount() to Qt::DisplayRole.
I ran into the Q_D(...) issue as described above so I didn't get far.

jpn
12th February 2009, 10:11
Note that I had to comment out the Q_D(const QItemDelegate) here in order for my code to compile
1) what is the equivalent code for "Q_D(const QItemDelegate);"? I'd like to understand this since the Q_D appears in QStandardItem::setdata() and data().

Q_D is a macro that declares a d-pointer to the private implementation (ie. QItemDelegate -> QItemDelegatePrivate). You cannot use private parts of Qt, you have to get along without them...


2) My tree now only has radiobuttons. How can I customize it such that the author node has checkboxes and only the book node has radiobuttons?
You have to identify it somehow. You can for example store the information to a custom role, or you can check the parent(s) of the model index to see where it is located in the tree.

topoden
24th November 2009, 18:13
Hi guys,

I'm currently solving almost the same problem, especially the following one:


The exclusively checked items should be handled at model side, for example by reimplementing QStandardItem::setData()

I wonder how did you implement the QStandardItem::setData method ? It looks that the only way to do that is

Go through all items in the model and un-check them
Run the default implementation for the being checked item so that the new state is properly processed


So something like this:




void uncheckBranchItems(QStandardItem * parent_item)
{
for (int i = 0; i < parent_item->rowCount(); ++i)
{
QStandardItem * child_item = parent_item->child(i);
if (Qt::Checked == child_item->checkState())
{
child_item->setCheckState(Qt::Unchecked);
}

uncheckBranchItems(child_item);
}
}

void RadioButtonItem::setData(const QVariant & value, int role)
{
if (Qt::CheckStateRole == role)
{
if (value.isValid() && (Qt::Checked == static_cast<Qt::CheckState>(value.toInt())))
{
uncheckBranchItems(model()->invisibleRootItem());
}
}

QStandardItem::setData(value, role);
}


Now imagine that I have another object which subscribes to the QTreeView::clicked() signal, check the item check state and do some custom logic then. I need somehow emulate the signal for the items being un-checked during call to uncheckBranchItems(). The signal should be emitted from the model, not from the item. Because possible subscribers to the signal do not know anything about the items but about model only. How would you do that ?

I'm actually curious what was your implementation of QStandardItem::setData method and whether you implemented some signal notifications on current checked item changes. Probably my solution is bad and you could advise something better where the required signal notifications are easy to do?

sergio87
22nd September 2011, 10:10
Hi all,

I'm doing the same as you. How did you put the radioButton? Or simply you implement the above algorithm?

I see that you subclassed the RadioButtonItem, could be?

So, can you post the final code?

Sorry for my poor English.

Many thanks!!!

sergio87
26th September 2011, 11:05
Hi,

I solved almost this problem. :)
The code is:

In MainWindow I have:

void MainWindow::startTree(){ QStandardItemModel *model = new QStandardItemModel();
for( int r=0; r<5; r++ ){
SubQStandardItem *item = new SubQStandardItem( QString("Row:%1").arg(r) );
item->setEditable(false);
for( int i=0; i<3; i++ ){
SubQStandardItem *subItem = new SubQStandardItem( QString("Item %1").arg(i) );
subItem->setCheckable(true);
subItem->setEditable(false);
item->appendRow(subItem);
}
model->setItem(r, item);
}
view = new QTreeView(centralWidget);
view->setModel(model);
view->show();
}
SubQStandardItem.h:

/* * SubQStandardItem.h
*
* Created on: 23/09/2011
* Author: Sergio Madrazo Giménez
*/


#ifndef SUBQSTANDARDITEM_H_
#define SUBQSTANDARDITEM_H_
#include <QStandardItem>


class SubQStandardItem : public QStandardItem
{


public:
SubQStandardItem(QString);
virtual ~SubQStandardItem();


private:
void setData(const QVariant & value, int role);
void uncheckBranchItems(QStandardItem * parent_item);
};


#endif /* SUBQSTANDARDITEM_H_ */

SubQStandardItem.cpp:

/* * SubQStandardItem.cpp
*
* Created on: 23/09/2011
* Author: smadrazo
*/


#include "SubQStandardItem.h"


SubQStandardItem::SubQStandardItem(QString qs)
: QStandardItem(qs)


{
// TODO Auto-generated constructor stub
}


SubQStandardItem::~SubQStandardItem() {
// TODO Auto-generated destructor stub
}


void SubQStandardItem::setData(const QVariant & value, int role)
{
QStandardItem::setData(value, role);
if (Qt::CheckStateRole == role){
if (value.isValid() && (Qt::Checked == static_cast<Qt::CheckState>(value.toInt())))
uncheckBranchItems(model()->invisibleRootItem());
}
QStandardItem::setData(value, role);
}


void SubQStandardItem::uncheckBranchItems(QStandardItem * parent_item){
int count=0;
for (int i = 0; i < parent_item->rowCount(); ++i)
{
QStandardItem * child_item = parent_item->child(i);
if (Qt::Checked == child_item->checkState())
count++;
uncheckBranchItems(child_item);
}
if(count>1){
for (int i = 0; i < parent_item->rowCount(); ++i){
QStandardItem * child_item = parent_item->child(i);
child_item->setCheckState(Qt::Unchecked);
}
}
}

This code checks only one item of the row.

I hope it help you! ;)

sagarbade
4th July 2019, 13:51
Thanks. I currently have the following code


QStandardItemModel *model = new QStandardItemModel();
QStandardItem *parentItem = new QStandardItem(QIcon("C:\\dataset_small.png"), "Authors");
model->appendRow(parentItem);
QStandardItem *author1 = new QStandardItem(QIcon("C:\\dataset_small.png"), "Smith, V");
author1->setCheckable(true);
parentItem->appendRow(author1);
parentItem->appendRow(new QStandardItem(QIcon("C:\\dataset_small.png"), "Campbell, C"));
for (int i = 0; i < 3; ++i) {
QStandardItem *item = new QStandardItem(QIcon("C:\\dataset_small.png"), QString("Book # %0").arg(i+1));
item->setCheckable(true);
author1->insertRow(i, item);
}
ui.treeView->setModel(model);

producing the attached image. Remaining things are:
1) I like the checkbox for the author node, but I'd like to have the radio button for the book items to force only one book can be selected at the time. Could you please elaborate on the QItemDelegate?
2) I also want to have a count of children next to the labels meaning I want to have a "2" next to the "Authors" string (since there are 2 authors) and a "3" next to "Smith, V" because he has 3 books



hey ...What About TreeView Qml Type