How to apply Filter for Tree which is developed using QStandardItemModel - qt

Implemented Tree using QStandardItemModel.. like below
QStandardItem *americaItem = new QStandardItem("America");
QStandardItem *mexicoItem = new QStandardItem("Canada");
QStandardItem *usaItem = new QStandardItem("USA");
QStandardItem *bostonItem = new QStandardItem("Boston");
QStandardItem *europeItem = new QStandardItem("Europe");
QStandardItem *italyItem = new QStandardItem("Italy");
QStandardItem *romeItem = new QStandardItem("Rome");
QStandardItem *veronaItem = new QStandardItem("Verona");
//building up the hierarchy
rootNode-> appendRow(americaItem);
rootNode-> appendRow(europeItem);
americaItem-> appendRow(mexicoItem);
americaItem-> appendRow(usaItem);
usaItem-> appendRow(bostonItem);
europeItem-> appendRow(italyItem);
italyItem-> appendRow(romeItem);
italyItem-> appendRow(veronaItem);
//register the model
treeView->setModel(standardModel);
So now Im unable to do search operation, using that QFilterProxyModel im able to search only parent data.. Any suggestion to search parent and child rows too..(using filterAcceptsRow or any other)

Implemented search filter like this:
Derived a class from QSortFilterProxyModel
Overrided the filterAcceptsRow method
bool FilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
// check the current item
bool result = QSortFilterProxyModel::filterAcceptsRow(source_row,source_parent);
QModelIndex currntIndex = sourceModel()->index(source_row, 0, source_parent);
if (sourceModel()->hasChildren(currntIndex))
{
// if it has sub items
for (int i = 0; i < sourceModel()->rowCount(currntIndex) && !result; ++i)
{
// keep the parent if a children is shown
result = result || filterAcceptsRow(i, currntIndex);
}
}
return result;
}
mFilterProxyModel->setFilterRegExp(ui->mLeSearchFilter->text());

Related

How to remove all child items of the root item in tree view

I want to remove all the tree items in the tree view of the invisible Root Item.
Currently this is what my workflow is
QModelIndex index = treeView->rootIndex();
QAbstractItemModel *model = treeView->model();
TreeModel *myModel = qobject_cast<TreeModel*>(model);
TreeItem* itm = myModel->getItem(index);
itm->removeChildren(0, itm->childCount());
bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
for (int row = 0; row < count; ++row)
{
delete childItems.takeAt(position);
}
return true;
}
Though i am able to delete all the items in the tree view it seems as if the Tree model indexes are not getting updated.
After deleting all the Tree items if i try to add a new item the application crashes.
You need delete your elements in between these calls.
beginResetModel();
and
endResetModel()

QTreeWidget takeChild() - Qt

I have a treeWidget in which I need to remove the QTreeWidgetItem's childelement.
QTreeWidgetItem *listing = new (ui->treeWidget);
AddChild(listing,id);
AddChild(listing,id);`// this is what i need to delete
AddChild(listing,id);
listing->takeChild(1);
I tried func takeChild(int index) but nothing happend
void AddChild(QTreeWidget *s,int id)
{
QTreeWidgetItem *_s = new QTreeWidgetItem(ui->treeWidget);
_s->setText(0,QString::number(id));
s->addChild(_s);
}
There are errors in your code,
QTreeWidgetItem *listing = new (ui->treeWidget);
should be:
QTreeWidgetItem *listing = new QTreeWidgetItem(ui->treeWidget);
and the signature of AddChild() functions is wrong:
void AddChild(QTreeWidget *s,int id)
should be:
AddChild(QTreeWidgetItem *s,int id)
Now the main issue why takeChild() is not working for you, is that you are not adding the items as children to listing , but you are adding them to the treeWidget, thus in your AddChild(), you should set the parent to S which is listing, So your code should be:
QTreeWidgetItem *listing = new QTreeWidgetItem(ui->treeWidget);
listing->setText(0, tr("Listing"));
AddChild(listing,0);
AddChild(listing,1); // this is what i need to delete
AddChild(listing,2);
listing->takeChild(1);
and the function AddChild()
void AddChild(QTreeWidgetItem *s,int id)
{
QTreeWidgetItem *_s = new QTreeWidgetItem(s);
_s->setText(0,QString::number(id));
s->addChild(_s);
}

qtablewidget selectedItems gives empty list

I have a qtablewidget with one column with a widget and others with data. The only column with widget is shown and all other columns are hidden.
foreach (BillHeader *billHeader, billHeaderList)
{
m_pBillTable->insertRow(i);
itemWidget = new LookupItem;
itemWidget->setImage(1);
...
m_pBillTable->setCellWidget(i, 0, itemWidget);
tableItem = new QTableWidgetItem(billHeader->billNumber);
tableItem->setTextAlignment(Qt::AlignCenter);
m_pBillTable->setItem(i, 1, tableItem);
...
m_pBillTable->hideColumn(1);
...
I have a signal slot connected as below:
connect(m_pOkButton, SIGNAL(clicked()), this, SLOT(handleOkClick()));
when ok button click i try to get the selected item and get data from the widget set to it
void OrderLookup::handleOkClick()
{
qDebug()<<Q_FUNC_INFO<<"Invoked";
QList<QTableWidgetItem*> itemList = m_pBillTable->selectedItems();
qDebug()<<Q_FUNC_INFO<<itemList.count();
if (!itemList.isEmpty())
{
int row = itemList.at(0)->row();
qDebug()<<Q_FUNC_INFO<<row;
LookupItem *item = (LookupItem*)m_pBillTable->cellWidget(row, 0);
if (NULL != item)
{
QString billNumber = item->getBillNumber();
emit orderLookupComplete(billNumber);
accept();
}
}
qDebug()<<Q_FUNC_INFO<<"Exits";
}
But i am getting the list count as zero.
The row is getting selected and gets highlighted.
I’ve set some properties to table widget as below:
m_pBillTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_pBillTable->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pBillTable->setSelectionMode(QAbstractItemView::SingleSelection);
m_pBillTable->setFocusPolicy(Qt::NoFocus);
Please can someone help me to know why list count is empty..
The issue got solved ..
QItemSelectionModel *itemModel = m_pBillTable->selectionModel();
QModelIndexList indexList = itemModel->selectedRows();
qDebug()<<Q_FUNC_INFO<<"IndexList Count"<<indexList.count();
if (!indexList.isEmpty())
{
int row = indexList.at(0).row();

QSortFilterProxyModel with QStandardItemModel after appendRow are not working

Here what I have got:
a QTreeView widget (*);
Source model MainModel inherits from QStandardItemModel. No virtual data() const method reimplemented;
Proxy MainFilterProxyModel inherits from QSortFilterProxyModel;
The tree:
[PERIOD 1]
[CHILD 1]
[CHILD 2]
[SUBCHILD 2.1]
...
[CHILD N]
[PERIOD 2]
...
[PERIOD N]
So the main problem comes when I'm trying to add a CHILD-row like (**) code do. Filter proxy model, after document was added to source model, does not know about new row and didn't show it on the tree.
I'm sure that proxy didn't get signal from QStandardItemModel when appendRow method do his job, so proxy can't filter new row, and didn't make it visible.
Any help?
Thanks.
PS: If I turn off proxy, everything appended just fine. But the problem is not in proxy. Proxy just doesn't get the signal about new row appended to the main source model...
(*) Here is QTreeView:
MainView::MainView( QWidget* parent /* = 0 */ ) : QTreeView( parent )
{
if( !model_ )
{
model_ = new MainModel( this );
}
if( !proxy_ )
{
proxy_ = new MainFilterProxyModel( this );
proxy_->setDynamicSortFilter( true );
proxy_->setSourceModel( model_ );
setModel( proxy_ );
}
}
(**) Here is my append function:
void MainModel::addRow( const DocumentPtr& document, QStandardItem* parentItem )
{
assert( document );
QList< QStandardItem* > items;
items << ( new QStandardItem );
items << ( new QStandardItem );
items << ( new QStandardItem );
items << ( new QStandardItem );
items << ( new QStandardItem );
items << ( new QStandardItem );
items << ( new QStandardItem );
updateRow( document, items );
if( !parentItem )
{
BOOST_FOREACH( const TimePeriod& period, TimePeriod::all() )
{
if( period.contains( QDateTime::fromTime_t( document->creationDate() ) ) )
{
QStandardItem* periodItem = itemByPeriod( period );
Q_ASSERT( periodItem );
periodItem->appendRow( items );
break;
}
}
}
else
{
parentItem->appendRow( items );
}
}
The base class for modeling is QAbstractItemModel. It is better to use the methods of the abstract class to do what you want. QStandardItemModel is a simple implementation of the abstract methods of QAbstractItemModel and most of the QStandardItemModel new methods are used by the reimplemented abstract functions. Here is a code to add item and subitem using the abstract class methods:
QAbstractItemModel * pModel = new QStandardItemModel(parent);
int nRows = pModel->rowCount();
pModel->insertRow(nRows); // this will emit rowsAboutToBeInserted() and rowsInserted() signals
pModel->insertColumn(0); // this will emit columnsAboutToBeInserted() and columnsInserted() signals
const QModelIndex indexFirstItem = pModel->index(nRows, 0);
pModel->setData(indexFirstItem, "Item text"); // this will emit dataChanged() signal
int nChildRows = pModel->rowCount(indexFirstItem);
pModel->insertRow(nChildRows, indexFirstItem); // this will emit rowsInserted()
pModel->insertColumn(0, indexFirstItem); // we also need to do this for the item's children
const QModelIndex indexChild = pModel->index(nChildRows, 0, indexFirstItem);
pModel->setData(indexChild, "Child item text");
If we try to do the same using QStandardItemModel methods it will look like:
QStandardItemModel *pModel = new QStandardItemModel(parent);
QStandardItem *pItem = new QStandardItem("Item text");
pItem->appendRow(new QStandardItem); // pItem is not yet added to pModel and rowsInserted won't be emitted
pModel->appendRow(pItem); // this will probably emit rowsInserted() signal but since we set tha text of the item when creating the pItem the dataChanged() signal won't be emitted.
So if you do pItem->appendRow() to add sub items and if the pItem is not yet added to the model, you will probably not get the rowsInserted() signal and therefore the proxy model won't be notified. From my experience the first method works better and is more robust though you need to write a couple of extra lines. Working directly with QStandardItemModel methods will often end with missing signals or other headaches. All you need to look is the QAbstractItemModel and QModelIndex documentations.

searching for a particular entry in a table by qlineedit?

What i want is that if i enter an ID in the textbox and then press enter,then if the ID is present ,then it gets displayed on the table the valuesof the table are inserted with the help of map in another window from which this window Box1 is opened as map.So as far as i have an idea,we have to run find command of map and then using if loop if that entered value in textbox is presentthen will display it in the same way as dummy data is displayed.
code used
Box1::Box1(QWidget *parent)
:QDialog(parent)
{
searchgroup = new QGroupBox(tr("Data Search"));
QHBoxLayout *layout2 = new QHBoxLayout;
text = new QLineEdit(this);
searchh = new QLabel(tr("&Enter ID:"));
searchh->setBuddy(text);
layout2->addWidget(searchh);
layout2->addWidget(text);
searchgroup->setLayout(layout2);
tableegroup = new QGroupBox(tr("Searched Data"));
QVBoxLayout *layout1 = new QVBoxLayout;
tablee = new QTableView(this);
mode1 = new QStandardItemModel(1,2,this);
mode1->setHorizontalHeaderItem(0, new QStandardItem(QString("ID")));
mode1->setHorizontalHeaderItem(1, new QStandardItem(QString("DATA")));
map<int,QString>::iterator itt;
itt=dataa.begin();
for (int colu = 0; colu < 2; colu++)
{
item1 = new QStandardItem();
if (colu == 0)
{
item1->setData(((*itt).first), Qt::DisplayRole);
mode1->setItem(0,0,item1);
} else
{
item1->setData(((*itt).second), Qt::DisplayRole);
mode1->setItem(0,1,item1);
}
}
tablee->setModel(mode1);
layout1->addWidget(tablee);
tableegroup->setLayout(layout1);
QVBoxLayout *mainlayout1 = new QVBoxLayout;
//mainlayout1->addWidget(menubarr);
mainlayout1->addWidget(searchgroup);
mainlayout1->addWidget(tableegroup);
setLayout(mainlayout1);
}
Thanks for any help in advance
EDIT
what i want
void Box1::textReturn()
{
bool ok;
int id = text->text().toInt(&ok);
// map<int,QString>::iterator itt;
if (ok && dataa.contains(id))
{
// add row (id, data[id] to table
}
else
{
QMessageBox msgbox = new QMessagebox();
msgbox->setWindowTitle("Alert");
msgbox->setText("No such ID present!");
msgbox->show();
}
}
EDIT2
void Box1::textReturn()
{
int id = (text->text()).toInt();
map<int,QString>::iterator itt;
itt = dataa.find(id);
if(itt != dataa.end()) //returns 1 if we found something
{
QList<QStandardItem *> items;
items << new QStandardItem(QString("%1").arg(id));
items << new QStandardItem((*itt).second);
mode1->appendRow(items);
tablee->update();
}
else
{
QMessageBox *msgbox = new QMessageBox();
msgbox->setWindowTitle("Alert");
msgbox->setText("INVALID ID ENTERED");
msgbox->show();
}
}
As #KCiebiera said, you have to do this connection
connect(text, SIGNAL(returnPressed()), this, SLOT(textReturnPressed());
Then you need to find your key in the table using
QList<QStandardItem *> QStandardItemModel::findItems ( const QString & text,
Qt::MatchFlags flags = Qt::MatchExactly, int column = 0 )
As you have map, so elements shouldn't repeat, your QList should be NULL or contains just one element. When u'll get your element (as QStandardItem) you just need to invoke
tablee->showColumn ( int column )
tablee->showRow ( int row )
Where your column will be QStandarItem->column() and row QStandardItem->row();
EDIT
void Box1::textReturnPressed()
{
int id = (test->text()).toInt();
map<int, string>::iterator it;
it = dataa.find(id);
if(it != dataa.end()) //we found something
{
QList<QStandardItem *> items;
items << new QStandardItem(QString("%1").arg(id));
items << new QStandardItem((*it).second);
mode1->appendRow(items);
}
else
QMessageBox::information(this, "Info", "ID not found!", QMessageBox::ok);
}
Something like this;
As far as I understand your question. You need to create a new slot in the Box1 class. Let's call it textReturnPressed(). Then you have to connect it to returnPressed() signal from text
connect(text, SIGNAL(returnPressed()), this, SLOT(textReturnPressed());
and here is textReturnPressed (I hope it compiles)
void textReturnPressed()
{
bool ok;
int id = text->text().toInt(&ok);
if (ok && dataa.count(id) > 0) {
QList<QStandardItem *> items;
items << new QStandardItem(QString("%1").arg(id));
items << new QStandardItem(dataa[id]);
mode1.appendRow(items);
}
}
You don't need an iterator to check if an item is in the map. Just call map.count() function.

Resources