Make QCompleter search in QStandardItemModel "data" instead "text" - c++

I am using a QCompleter with a QStandardItemModel as a model.
The code goes something like this:
QStandardItemModel *modelProtocolName = new QStandardItemModel();
QStringList list;
list << "one" << "two" << "three";
for (int i = 0; i < list.length(); i++)
{
QStandardItem *item = new QStandardItem();
item->setText( list.at( i ) );
item->setData( "real one, two or three is inserted here", ZAdvancedCompleter::CompleteRole );
modelProtocolName->appendRow( item );
}
ZAdvancedCompleter completerProtocolName = new ZAdvancedCompleter( this );
completerProtocolName->setModel( modelProtocolName );
Now when I use the QCompleter it searches in the list, i.e. in "one", "two" and "three". Is it possible to direct the search to the data of the model?

Related

Get installed apps data issue

struct AppsData {
QList<QIcon> icons;
QStringList name;
QStringList version;
QStringList publisher;
QStringList installLocation;
QStringList uninstallLocation;
};
void Test::setAppData(QList<QIcon> icons, QStringList names, QStringList versions, QStringList publishers, QStringList installLocations, QStringList uninstallLocations)
{
AppsData appsData;
appsData.icons = icons;
appsData.name = names;
appsData.version = versions;
appsData.publisher = publishers;
appsData.installLocation = installLocations;
appsData.uninstallLocation = uninstallLocations;
QVector<AppsData> dataVector;
dataVector.push_back(appsData);
}
I want to display all apps data in appropriate columns.
Image:
Also I have tried to accomplish it without vectors:
for (int i = 0; i < uninstallLocations.count(); i++) {
allApplicationsItem = new QTreeWidgetItem(allApplications);
allApplicationsItem->setText(0, names.at(i));
allApplicationsItem->setText(1, versions.at(i));
allApplicationsItem->setText(2, publishers.at(i));
allApplicationsItem->setText(3, installLocations.at(i));
allApplicationsItem->setText(4, uninstallLocations.at(i));
}
but it doesn't work, the application crashes.
Assuming you are using Qt5:
Once you have a QTreeWidget and the vector created, you should iterate over its elements, and create a new QTreeWidgetItem for each one, so you'd have something like:
QTreeWidget *treeWidget = new QTreeWidget(this);
treeWidget->setCoulmnCount(1);
for(int i = 0; i < vector.count(); i++) {
QTreeWidgetItem *newItem = new QTreeWidgetItem(treeWidget);
newItem->setText(0, vector.value(i)); // 0 to display it at column 0
}
As you can see, first you need to create the QTreeWidget and then add each child as a QTreeWidgetItem to it.
By the way, you should consider changing the name of the variable vector to something more specific.

duplicate rows in QStandardItemModel in Qt

I'm trying to achieve something I though would be easy but cannot figure how to make it work.
In this basic example, I'm creating an address book, a single person can be in 2 groups, John Doe is a friend, but also a work colleague.
If I change his phoneNumber inside the friend group, it should also change in the work group.
This is how I first tried this with static content (in the end it is linked to a db)
addressBookListModel = new QStandardItemModel(0, 4);
addressBookListModel->setHeaderData(0,Qt::Horizontal,"First Name", Qt::DisplayRole);
addressBookListModel->setHeaderData(0,Qt::Horizontal,"fn", Qt::UserRole);
addressBookListModel->setHeaderData(1,Qt::Horizontal,"Last Name", Qt::DisplayRole);
addressBookListModel->setHeaderData(1,Qt::Horizontal,"ln", Qt::UserRole);
addressBookListModel->setHeaderData(2,Qt::Horizontal,"E-Mail", Qt::DisplayRole);
addressBookListModel->setHeaderData(2,Qt::Horizontal,"mail", Qt::UserRole);
addressBookListModel->setHeaderData(3,Qt::Horizontal,"Phone Number", Qt::DisplayRole);
addressBookListModel->setHeaderData(3,Qt::Horizontal,"phone", Qt::UserRole);
Then inserting the data :
//Group 1
QStandardItem * work = new QStandardItem("Work");
QList<QStandardItem*> workgroup;
workgroup << work ;
addressBookListModel->appendRow(workgroup);
//group 2
QStandardItem * friends = new QStandardItem("Friends");
QList<QStandardItem*> friendgroup;
friendgroup << friends ;
addressBookListModel->appendRow(friendgroup);
//One contact in both groups
QStandardItem * fn = new QStandardItem("John");
QStandardItem * ln = new QStandardItem("Doe");
QStandardItem * mail = new QStandardItem("john.doe#gmail.com");
QStandardItem * phone = new QStandardItem("+123456789");
QList<QStandardItem*> rowitems;
rowitems << fn << ln << mail << phone;
work->appendRow(rowitems);
friends->appendRow(row items);
but this only inserts john doe inside work like this :
I Thought this would be because row items is not a pointer, so I tried it this way :
//One contact in both groups 2
QStandardItem * fn = new QStandardItem("John");
QStandardItem * ln = new QStandardItem("Doe");
QStandardItem * mail = new QStandardItem("john.doe#gmail.com");
QStandardItem * phone = new QStandardItem("+123456789");
QList<QStandardItem*> rowitems;
rowitems << fn << ln << mail << phone;
QList<QStandardItem*> rowitemsB;
rowitemsB << fn << ln << mail << phone;
work->appendRow(rowitems);
friends->appendRow(rowitemsB);
But this gave me the exact same result, John Doe is not present inside Friends, although in both cases, there is an arrow indicating the presence of a child.
Any Idea how to make the same data appear twice?
A QStandardItem can be added once and only once to a QStandardItemModel. Check your debugger log, I'm sure QT writes debug messages saying it's not allowed when you insert the same item twice. By the way, what would return QStandrardItem::index() of an item inserted twice (this method returns row/column position of the item in the QStandardItemModel)?
So you have to create different QStandardItem. You should do like that:
void addEntry( const QString& first, const QString& last, const QString& mail, const QString& tel, QStandardItem* parent )
{
QStandardItem * fn = new QStandardItem(first);
QStandardItem * ln = new QStandardItem(last);
QStandardItem * mail = new QStandardItem(mail);
QStandardItem * phone = new QStandardItem(tel);
QList<QStandardItem*> rowitems;
rowitems << fn << ln << mail << phone;
parent->appendRow(rowitems);
}
...
addEntry( "John", "Doe", "john.doe#gmail.com", "+123456789", work );
addEntry( "John", "Doe", "john.doe#gmail.com", "+123456789", friends );

Qt: set columns in treeView

How can I implement this code I have for a qTreeWidget for a qTreeView?
for (const auto & i : names) {
QTreeWidgetItem * item = new QTreeWidgetItem(ui->treeWidget);
item->setText(0, QString::fromStdString(i));
ui->treeWidget->addTopLevelItem(item);
const std::unordered_map<std::string, double> map = m_reader.getMapFromEntry(i);
for (const auto & j : map) {
QTreeWidgetItem * item2 = new QTreeWidgetItem();
item2->setText(0,QString::fromStdString(j.first));
item2->setText(1,QString::number(j.second));
item->addChild(item2);
}
}
I have a model and a treeView, like this:
m_model = new QStandardItemModel(m_reader.getAllNames().size(),2,this);
ui->treeView->setModel(m_model);
I tried this, but that only shows one column:
QStandardItem * parentItem = m_model->invisibleRootItem();
for (const auto & i : names) {
QStandardItem * item = new QStandardItem(QString::fromStdString(i));
parentItem->appendRow(item);
const std::unordered_map<std::string, double> map = m_reader.getMapFromEntry(i);
for (const auto & j : map) {
QList<QStandardItem *> rowItems;
rowItems << new QStandardItem(QString::fromStdString(j.first));
rowItems << new QStandardItem(QString::number(j.second));
item->appendRow(rowItems);
}
}
With the treeWidget, I had so set the columnCount, like this:
ui->treeWidget->setColumnCount(2);
But treeView does not have a method like this.
So, to summarize: How can I implement a TreeView with more than one column?
EDIT:
To clarify, I want something like this:
|-A
| |-B-C
| |-D-E
where A is the parent and B,C,D,E the children, with B,D being in column 0 and C,E in column 1.
Hope this helps!
To support multiple columns, the model must contain data for multiple columns.
So in some sense, columns are a property of the model, not the view. Views then can decide to hide or rearrange certain columns (For example, a QListView always only shows the first column, while one can hide or reorder columns in a QTableView).
As you use QStandardItemModel, its documentation should give a few hints how to create multiple columns.
E.g., look at this example from the documentation:
QStandardItemModel model(4, 4);
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 4; ++column) {
QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
model.setItem(row, column, item);
}
}
It creates a model with 4 initial rows and columns each, and then fills it with items via setItem().
Alternatively, you can pass a list of items to QStandardItemModel::appendRow(), with an item for each column:
QList<QStandardItem*> items;
items.append(new QStandardItem(tr("One"));
items.append(new QStandardItem(tr("Two"));
model->appendRow(items);
This adds a new row with "One' in the first column and "Two" in the second. For even more ways to deal with multiple columns, see the QStandardItemModel docs.
Note: QTreeView expects the same number of columns on all levels of the hierarchy, so one should fill rows with empty items for the unused columns if need be.
Just an addition to answer by Frank Osterfeld:
QTreeView displays all columns of subtables inserted into top level QStandardItems. You just have to "force" it to show additional columns by inserting dummy QStandardItems into top-level table. Example:
QStandardItemModel *objectTreeModel = new QStandardItemModel(NULL);
QStandardItem *mainItem = new QStandardItem(tr("Main Item"));
QStandardItem *subItem1 = new QStandardItem(tr("Sub-Item 1"));
QStandardItem *subItem2 = new QStandardItem(tr("Sub-Item 2"));
mainItem->appendRow(QList<QStandardItem *>() << subItem1 << subItem2);
QStandardItem *dummyItem = new QStandardItem();
objectTreeModel->appendRow(QList<QStandardItem *>() << mainItem << dummyItem );
Now you will be able to see 2 columns and if you expand mainItem, both subitems will be visible.

Qt hide column in QTableView

I want to hide the ID column in the QtableView and i can't do that on my implementation. Can anyone help me?
void MainWindow::on_actionClear_Search_triggered()
{
model = new QStandardItemModel(cars.size(),6,this);
//create header
createHeader(model);
//set data to the table view
populate(cars);
ui->tableView->setColumnHidden(6,true);
ui->tableView->setModel(model);
}
void MainWindow::createHeader(QStandardItemModel *model){
model->setHorizontalHeaderItem(0,new QStandardItem("Car"));
model->setHorizontalHeaderItem(1, new QStandardItem("Type"));
model->setHorizontalHeaderItem(2, new QStandardItem("Mileage"));
model->setHorizontalHeaderItem(3, new QStandardItem("Year"));
model->setHorizontalHeaderItem(4, new QStandardItem("Is registered"));
model->setHorizontalHeaderItem(5, new QStandardItem("ID"));
}
void MainWindow::populate(const QList<Vehicle> &vehicles)
{
int j = 0;
QList<Vehicle>::ConstIterator iter;
for( iter= vehicles.begin(); iter != vehicles.end(); iter++){
const Vehicle& car = *iter;
//set car
QString makeAndModel = car.getGeneralData().getMake() + car.getGeneralData().getModel();
QStandardItem *mAndM = new QStandardItem(QString(makeAndModel));
mAndM->setEditable(false);
model->setItem(j,0,mAndM);
//set type
QStandardItem *type = new QStandardItem(QString(car.getGeneralData().getType()));
type->setEditable(false);
model->setItem(j,1,type);
//set mileage
QString mileageString = QString::number(car.getGeneralData().getMileage());
QStandardItem *mileage = new QStandardItem(QString(mileageString));
mileage->setEditable(false);
model->setItem(j,2,mileage);
//set year
QString yearString = QString::number(car.getGeneralData().getYear());
QStandardItem *year = new QStandardItem(QString(yearString));
year->setEditable(false);
model->setItem(j,3,year);
//set registration
QString regString = VehicleHelper::convertBoolToString(car.getRegistration().isRegistered());
QStandardItem *regDate = new QStandardItem(QString(regString));
regDate->setEditable(false);
model->setItem(j,4,regDate);
//set ID column
QStandardItem *idNumber = new QStandardItem(QString(car.getVehicleID().getID()));
idNumber->setEditable(false);
model->setItem(j,5,idNumber);
j++;
}
}
You use ui->tableView->setColumnHidden(6, true);, but there is no column with index 6. You should write ui->tableView->setColumnHidden(5, true); instead, because ID column number is rather 5 than 6.
UPDATE:
You also need to hide column(s) after you set the model to the view, i.e:
ui->tableView->setModel(model);
ui->tableView->setColumnHidden(5, true);
Another approach is set specified column's width to zero : ui->tableView->setColumnWidth(col,0); ui->tableWidget->setColumnWidth(col,0);.
Ui->tableView->horizontalHeader()->hideSection(col);
where col - number of table column

Memory Management in Qt

I have small doubt about Qt memory management.
Let's take an example of Listview, in listview we add each item by allocating memory dynamically. So in this case do we need to delete all the "new"ed items manually.
E.g:
Qlistview *list = new Qlistview;
QStandardItemModel *mModel = new QStandardItemModel();
list ->setModel(mModel);
for(int I =0;i<10;i++)
{
QsandardItem *item = new QsandardItem(“Hi”);
mModel->appendRow(item);
}
In this example, should item be deleted manually?
QStandardItemModel takes ownership of items, so they will be automatically deleted when model is destroyed. You still need to delete the model itself (setModel() doesn't transfer ownership of model to the view, because one model can be used by multiple views).
Agree with chalup's answer , the answer for your question is:
if you called mModel->clear();, it will help you delele all of those items, you don't need to mannually delete items one by one, what's more if you want to totally delete model, you should called delete mModel;.
Run the example code provided by ChrisW67 here, you will have a better understanding:
#include <QCoreApplication>
#include <QDebug>
#include <QStandardItemModel>
class MyItem: public QStandardItem
{
public:
MyItem(const QString & text): QStandardItem(text) {
qDebug() << "Item created" << this;
}
~MyItem() {
qDebug() << "Item destroyed" << this;
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QStandardItemModel* model = new QStandardItemModel;
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 4; ++column) {
QStandardItem *item =
new MyItem(QString("row %0, column %1").arg(row).arg(column));
model->setItem(row, column, item);
}
}
qDebug() << "Finished making model";
model->clear();
qDebug() << "Model cleared";
qDebug() << "===================";
QStandardItem *newitem1 = new MyItem(QString("new item"));
qDebug()<<"create new item at"<<newitem1;
QStandardItem *newitem2 = new MyItem(QString("new item"));
QStandardItem *newitem3 = new MyItem(QString("new item"));
QStandardItem *newitem4 = new MyItem(QString("new item"));
//because we didn't delete model so far, we can still append items to model.
model->appendRow({newitem1,newitem2,newitem3,newitem4});
model->clear();
qDebug() << "Model cleared again";
//although the memoty of newitem1 has already been deallocated, but the pointer still point to that address, now newitem1 is a dangling pointer
if(newitem1){
qDebug()<<"newitem1 address is"<<newitem1;
}
else{
qDebug()<<"newitem1 address in null";
}
// delete newitem1;//this will cause program crash because newitem1 acutally has been delete, double delete should not be allowed
newitem1 = nullptr;//Instead of delete, wo could set newitem1 pointet to null, this can avoid wild pinter/dangling pointer
delete model;
qDebug()<<"deleted model";
return a.exec();
I am learing c++ too, if there is something wrong above, please tell me, i will correct it.