QT ComboBox ItemData from Database - c++

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.

Related

Qt5 : Get value of item clicked in a listview

I'm making a Qt5.7 application where I am populating a QListView after reading stuff from a file. Here's the exact code of it.
QStringListModel *model;
model = new QStringListModel(this);
model->setStringList(stringList); //stringList has a list of strings
ui->listView->setModel(model);
ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers); //To disable editing
Now this displays the list just fine in a QListView that I have set up. What I need to do now is to get the string that has been double clicked and use that value elsewhere. How do I achieve that?
What I tried doing was to attach a listener to the QListView this way
... // the rest of the code
connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(fetch()));
...
And then I have the function fetch
void Window::fetch () {
qDebug() << "Something was clicked!";
QObject *s = sender();
qDebug() << s->objectName();
}
However the objectName() function returns "listView" and not the listView item or the index.
The signal already provides you with a QModelIndex which was clicked.
So you should change your slot to this:
void Window::fetch (QModelIndex index)
{
....
QModelIndex has now a column and a row property. Because a list has no columns you are interessted in the row. This is the index of the item clicked.
//get model and cast to QStringListModel
QStringListModel* listModel= qobject_cast<QStringListModel*>(ui->listView->model());
//get value at row()
QString value = listModel->stringList().at(index.row());
You should add the index as parameter of your slot. You can use that index to access the list
Your code should be some thing like this.
void Window::fetch (QModelIndex index) {
/* Do some thing you want to do*/
}

How to fill database sqlite tablewidget

I am writing "SQLite" database and I create the database table like this:
void MainWindow::createdata()
{
QSqlQuery query;
query.exec("DROP TABLE messages");
query.exec("CREATE TABLE messages("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"IPAddress VARCHAR(20),"
"date VARCHAR(10),"
"message VARCHAR(30))");
query.prepare("INSERT INTO messages(IPAddress, date, message) values(?,?,?)");
query.addBindValue("192.168.1.1");
query.addBindValue("jun 3 2016");
query.addBindValue("hello");
if (query.exec()) {
qDebug() << "ok!";
}
else
{
qDebug() << query.executedQuery();
qDebug() << query.lastError();
}
}
And i create "qtablewidget" like this:
QTableWidget* table = new QTableWidget();
table->setRowCount(10);
table->setColumnCount(4);
table->setWindowTitle("Received Message");
table->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
table->setHorizontalHeaderLabels(QString("ID;HostAddress;Date;Message").split(";"));
table->setStyleSheet("QTableView {selection-background-color: blue;}");
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->setSelectionBehavior(QAbstractItemView::SelectRows);
table->setSelectionMode(QAbstractItemView::SingleSelection);
QSqlQuery query("SELECT * FROM messages");
but i don't know how should i fill the "tablewidget" to show with query.
Can anyone please help me?Thanks
You should use QTableView (Model based version of table view) and then using QSqlQueryModel, you can populate your table.
QSqlQueryModel *model = new QSqlQueryModel();
model->setQuery(query);
tableView->setModel(model);
To use QSqlQueryModel with a QTableWidget, you should iterate through QSqlQueryModel row by row and add them to your QTableWidget.
QSqlQueryModel *model = new QSqlQueryModel();
model->setQuery(query);
int i;
QSqlRecord row
for(i = 0, row = model->record(i); !row.isEmpty(); i++, row = model->record(i)){
// Get each field using `value` method of variabale 'row'
// and insert this fields to its corresponding cell in QTableWidget
}
Relevant Question:
Setting the model to a QTableWidget

Filter with QComboBox C++

I want to create an editable QComboBox which filters results according to the search query and updates the dropdown entries accordingly.
After reading How do I Filter the PyQt QCombobox Items based on the text input? I tried to implement something similar in C++.
But I can't store anything inside the QComboBox now. Even after adding new entries through addItem() the total count remains 0.
What is the reason for this and how do I insert entries inside the QComboBox with QSortFilterProxyModel?
Here is the relevant snippet of the code:
SearchBox = new QComboBox(this);
SearchBox->setEditable(true);
// Try adding a few entries and check if they persist after changing the model
SearchBox->addItem(QString("hi"));
SearchBox->addItem(QString("bye"));
int count = SearchBox->count(); // count = 2
ProxyModel = new QSortFilterProxyModel;
ProxyModel->setSourceModel(SearchBox->model());
ProxyModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
SearchBox->setModel(ProxyModel);
// Check count again
count = SearchBox->count(); // count = 0 <- Why?
// Try adding new entries
SearchBox->addItem(QString("Hi again"));
count = SearchBox->count(); // count = 0 .. So new entries don't get stored
Completer = new QCompleter(ProxyModel,this);
Completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
SearchBox->setCompleter(Completer);
QObject::connect(SearchBox->lineEdit(), SIGNAL(textChanged(const QString)), ProxyModel, SLOT(setFilterFixedString(const QString)));
QObject::connect(Completer, SIGNAL(activated(const QString &)), this, SLOT(onCompleterActivated(const QString &)));
Use QStringListModel to store items. Application crashes if proxy model have no items (if filter string filters out all items)(this needs further investigation - is this completer issue or combobox). This can be fixed by not applying such filter (onTextChanged(QString text) slot). Completer completes input if theres only one item (not sure if it's ok). And sometimes checkbox doubles all items (don't know why). If this issues is critical, I think you need to write custom ComboBox from scratch and this is serious work.
{
SearchBox = new QComboBox(this);
SearchBox->setEditable(true);
QStringList Items;
Items << "hi" << "bye";
StringListModel = new QStringListModel();
StringListModel->setStringList(Items);
ProxyModel = new QSortFilterProxyModel;
ProxyModel->setSourceModel(StringListModel);
ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
SearchBox->setModel(ProxyModel);
// Check count again
int count = SearchBox->count(); // count = 2
// Try adding new entries
QStringList Items_ = StringListModel->stringList();
Items_ << "hi again";
StringListModel->setStringList(Items_);
count = SearchBox->count(); // count = 3
Completer = new QCompleter(ProxyModel,this);
Completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
SearchBox->setCompleter(Completer);
QObject::connect(SearchBox->lineEdit(), SIGNAL(textChanged(const QString)), this, SLOT(onTextChanged(QString)));
QObject::connect(Completer, SIGNAL(activated(const QString &)), this, SLOT(onCompleterActivated(const QString &)));
}
void MainWindow::onTextChanged(QString Text) {
QStringList Items = StringListModel->stringList();
QString Item;
foreach(Item,Items) {
if (Item.indexOf(Text) > -1) {
ProxyModel->setFilterFixedString(Text);
return;
}
}
}

C++ QListView with icons And Signals on items clicked

I have a QListview where I have set a model. The model contains the QList. Now I want to get the contents of QListview on clicking the item. But I don't know how to do this? Through some tutorials I followed I am able to get two items appear in the QListview as follows. But I dont know how to make it work?? Please anyone help. The code which I am working as follows.
listviewmodel =new QListView;
listviewmodel->setModel( createModel() );
listviewmodel->setViewMode(QListView::IconMode);
listviewmodel->setIconSize(QSize(size().width()/8, size().height()/8));
connect(listviewmodel,SIGNAL(clicked(const QModelIndex)),this,SLOT(ItemClicked(QModelIndex)));
QAbstractItemModel *MainWindow::createModel()
{
QStandardItemModel *model = new QStandardItemModel();
QList<QStandardItem *> listItem;
QStandardItem *item2 = new QStandardItem();
item2->setIcon(QIcon(QPixmap::fromImage(qimages2)));
listItem << item2;
QStandardItem *item1 = new QStandardItem();
item1->setIcon(QIcon(QPixmap::fromImage(qimages1)));
listItem << item1;
model->appendColumn(listItem);
return model;
}
void MainWindow::ItemClicked (QModelIndex index )
{
textEdit->setText(index.data().toString());
}
I checked your code in QtCreator and it works as you described. So what is the problem? Are you getting some errors? Maybe did you not put declaration of ItemClicked(QModelIndex) below the public slots:? Are you sure that connect returns true? Try to check it:
bool success = connect(listviewmodel,SIGNAL(clicked(const QModelIndex)),this,SLOT(ItemClicked(QModelIndex)));
Q_ASSERT(success);
EDIT: If you want to display only icons at QListView and get some text informations after clicking on specified item, you can do it in the following way:
item2->setIcon(QIcon(QPixmap::fromImage(qimages2)));
item2->setData("informations about item2", Qt::UserRole);
(...)
void MainWindow::ItemClicked (QModelIndex index )
{
QString data = index.data(Qt::UserRole).value<QString>();
ui->textEdit->setText(data);
}

Showing output of sql query inside a QLabel

I am writing a qt gui application where I am planning to show the output of an sql query inside a QLabel.
Now population the output inside a QTableView model is simple enough and that I can do using;
QSqlDatabase dbSqlite = QSqlDatabase::addDatabase("QSQLITE"); //these 2 lines for SQLite DB connection
dbSqlite.setDatabaseName("/home/aj/test.db");
dbSqlite.setUserName("aj");
QString MyQuerySqlite = ui->sqlite_queryEdit->text(); //take the query from a QLineEdit
dbSqlite.open(); //open db connection
QSqlQuery query(MyQuerySqlite,dbSqlite);
if(query.exec()) //populate in table
{
this->model1=new QSqlQueryModel();
model1->setQuery(MyQuerySqlite);
ui->sqlite_tableView->setModel(model1);
qDebug()<<QDateTime::currentDateTime()<<"SQLITE QUERY SUCCESS "<<dbSqlite.lastError().text();
}
Any idea on how to achieve this inside a QLabel ???
The output of the query will be one single record. For example the name of the world's tallest mountain, or the name of the capital of Engalnd. Just single records.
If you want to use QSqlQueryModel for this, you can use QSqlQueryModel::record ( int row ) to retrieve a specific record and then QSqlRecord::value ( int index ) to get a field's value :
QString str = model1->record(0).value(0).toString();
label->setText(str);
You can get result with value method. For example:
QString country;
QSqlQuery query("SELECT country FROM artist");
while (query.next()) {
country.append( query.value(0).toString() + " ");
}
label->setText(country);
Also you can read data from model1. Something like:
label->setText(model1->data(model1->index(0,0),Qt::DisplayRole).toString());