duplicate rows in QStandardItemModel in Qt - c++

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 );

Related

QT ComboBox ItemData from Database

I have the following code which links a QT QComboBox to my sqlite database and it works great.
However in my database I have the Category and Item table linked with a foreign key.
So when I pull info from the QComboBox I need to get the Category_ID not the name which is listed in the box.
How would I go about setting the QComboBox ItemData to the Category_ID field with a model or better yet use the model to set the QComboBox ItemData as my Category Object?
Thanks,
void MainWindow::populatCat()
{
QSqlQueryModel *model = new QSqlQueryModel();
QString sql;
sql = "select Category_Name From Category ORDER BY Category_Name ASC;";
QSqlQuery* query = new QSqlQuery(db);
query->prepare(sql);
if(!query->exec()){
qDebug () << "Query Erorr: " << query->lastError();
}else{
qDebug () << "Query Successful: " << query->lastQuery();
}
model->setQuery(*query);
ui->cboCat->setModel(model);
}
Okay, I'll present an answer now. :)
QComboBox* myBox = new QComboBox();
connect( myBox, SIGNAL( indexChanged( int ) ), this, SLOT( handleIndexChange( int ) ) );
void myObject::handleIndexChange( int /*index*/ ) {
// We actually don't need the index
QComboBox* box = qobject_cast<QComboBox*>( sender() );
if ( box ) {
QVariant data = box->currentData(); // do whatever w/ data... sounds like call toInt() in your case.
}
}
The essence of all three of my approaches is that you have to do something extra to get data() which corresponds to the current item after a change. It would be nice if it emitted a signal taking the underlying data as the argument, but that could get expensive.

How to make a subchild to a child in QTreeWidget?

I want to make it so that I can expand a third level (subchild) to a child under the top level item (root). All I've been able to do is make multiple children to a single root.
this is in my .cpp
QStringList string1, string2;
string1 << "xxxxxxxx" << "xxxxxxxxxxx";
string2 << "yyyyyy" << "yy";
m_treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(string1));
m_treeWidget->insertTopLevelItem(1, new QTreeWidgetItem(string2));
//here I add a child
AddChild(m_treeWidget->topLevelItem(0),"hello","world", m_treeWidget);
//here I make two attempts to make a sub child
AddChild(m_treeWidget->itemBelow(m_treeWidget->topLevelItem(0)),"hello_sub1","world_sub1", m_treeWidget);
AddChild(m_treeWidget->itemAt(0,0),"hello_sub2","world_sub2", m_treeWidget);
The following is my Add Child Method also in the same .cpp file:
void Dialog::AddChild (QTreeWidgetItem *parent, QString name, QString Description, QTreeWidget* treeWidget)
{
QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}
In order to make a tree hierarchy you can use the QTreeWidgetItem's API, especially its constructors. Constructors can accept either QTreeWidget or QTreeWidgetItem as a parent object. In the first case, the top level item will be added to the tree widget and in the second case - child item of another item. This API is easier to use because you don't need to explicitly append items to the tree widget. Here is the sample code that implements the idea:
QStringList string1, string2;
string1 << "xxxxxxxx" << "xxxxxxxxxxx";
string2 << "yyyyyy" << "yy";
QTreeWidget tv;
// The top level items
QTreeWidgetItem *top1 = new QTreeWidgetItem(&tv, string1);
QTreeWidgetItem *top2 = new QTreeWidgetItem(&tv, string2);
// A child item.
QTreeWidgetItem *child1 =
new QTreeWidgetItem(top1, QStringList() << "Hello" << "World");
// The grandchildren.
new QTreeWidgetItem(child1, QStringList() << "Hello_sub1" << "World_sub1");
new QTreeWidgetItem(child1, QStringList() << "Hello_sub2" << "World_sub2");
Actually I was able to solve it another way...
in the .cpp:
//Initialize the QTreeWidget with 2 columns
QTreeWidget m_treeWidget = new QTreeWidget();
m_treeWidget->setColumnCount(2);
//these are the method calls:
AddRoot("Root1_Column1", "Root2_Column2", m_treeWidget);
AddRoot("Root2_Column1", "Root2_Column2", m_treeWidget);
//topLevelItem(0) makes it a child of the first root... topLevelItem(1) makes it a child of the second root
AddChild(m_treeWidget->topLevelItem(0),"Child1_Column1","Child1_Column2");
AddChild(m_treeWidget->topLevelItem(1),"Child2_Column1","Child2_Column2");
AddSubChild(m_treeWidget->itemBelow(m_treeWidget->topLevelItem(0)),"SubChild_Column1", "SubChild_Column2");
With these being the methods I used within the same .cpp file:
void Dialog::AddRoot (QString name, QString Description, QTreeWidget* treeWidget)
{
QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
item->setText(0,name);
item->setText(1,Description);
item->setExpanded(true); //expand automatically
treeWidget->addTopLevelItem(item);
}
void Dialog::AddChild (QTreeWidgetItem *parent, QString name, QString Description)
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}
void Dialog::AddSubChild (QTreeWidgetItem *parent, QString name, QString Description)
{
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText(0,name);
item->setText(1, Description);
parent->addChild(item);
}

check if the name already exists in QTableWidget

I have a problem.
I have 2 QTextEdit fields : value & name.
When I push the button i create QTableWidgetItems with the value from "value" and "name".
But now I will check if the name alredy exists.
But I don't know, with " findItems " ? with contain's ?
Tabelle extends from QWidget in the header.
I'am an c++/ QT Beginner and have no idea as I do that such.
PS: I'am speaking Germany, so you can answer in Germany, my English isn't very good ;D
Thank you :)
void Tabelle::pushButtonClicked() :
strname = ( txtname ->text ());
strvalue = ( txtvalue ->text ());
The textfields to Strings.
Put the vlaue in Items:
QTableWidgetItem * valueitem = new QTableWidgetItem(0);
valueitem->setText(strvalue);
QTableWidgetItem * nameitem = new QTableWidgetItem(0);
nameitem->setText(strname);
New row :
if ( cou >coucount )
{table->insertRow(table->rowCount());}
table->setItem( cou,1, valueitem );
table->setItem( cou, 0, nameitem); cou++
You can use QList QTableWidget::findItems(const QString & text, Qt::MatchFlags flags) const.
As the doc says:
Finds items that matches the text using the given flags.
Try the following code:
QList<QTableWidgetItem *> ItemList = Table->findItems("TestName", Qt::MatchExactly);
cout<< "Count:" << ItemList.count() << endl;

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

Make QCompleter search in QStandardItemModel "data" instead "text"

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?