I have a QTableView that enables MultiSelection selectionMode following a SelectRows behavior as follow:
QSqlQueryModel model = db_manager->get_all();
ui->tableView->setModel(model);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableView->setSelectionMode(QAbstractItemView::MultiSelection);
ui->tableView->show();
The selection is working properly before which the indexes of theses selected rows are put into QModelIndexList as follow:
selectedRowsIndexesList = ui->tableView->selectionModel()->selectedRows();
Now I need to extract the information where these indexes are pointing to. I do this at the moment manually as follow:
qDebug() << model->index(0,0).data().toString();
I change the first "0" manually. But I need to automate the process through a for-loop statement like this:
for (int i = 0; i < selectedRowsIndexesList.size(); i++){
qDebug() << model->index(??,0).data().toString();
}
How can I do that ?
You already have the indexes in a list, so why go back to the model?
You can simply access the data using the indexes you've stored:
for (int i = 0; i < selectedRowsIndexesList.size(); i++){
qDebug() << selectedRowsIndexesList[i].data().toString();
}
The QModelIndexList is just a typedef as per the documentation. It is just a synonym for QList<QModelIndex> and you can iterate through the indexes as you would do through any QList variables.
for(int i = 0; i < mindex_list.size(); i++)
qDebug() << mindex_list.at(i).toString();
Or something similar.
Related
I have a wxScrolledWindow object filled with elements (pictures) (every element add with the class ThumbNail which uses dc.paint). I would like to dynamically change the elements with new once (not the same number) (change of folder by the user).
How can I empty all the items in wxScrolledWindow object and put new once back in? And then reset the scrollbars.
_ScrolThumbs = new wxScrolledWindow(_pMainPanel);
wxGridSizer *m_swSizer = new wxGridSizer(1,1,0);
_ScrolThumbs->SetSizer(m_swSizer); // Sets the window to have the given layout sizer.
std::vector<ThumbNail*> _Thumbs;
for(int i=0;i < FilePr::Instance()->GetNumThumbs() ;i++)
{
_Thumbs.push_back(new ThumbNail(_ScrolThumbs, PicName[i]));
_ScrolThumbs ->GetSizer()->Add (_Thumbs[i], 1, wxALL|wxALIGN_CENTER_VERTICAL, 5);
}
Then I tried to do this (when a button is hit):
wxWindowList& lst = _ScrolThumbs->GetChildren();
//if (!lst.empty())
std::cout << lst.size() << '\n';
while(!lst.empty()) //for(int i = 0; i < lst.size(); i++) //lst.size()
{
wxWindow *wnd = lst.back();
wnd->Destroy();
}
But putting new elements back in, like I did above does not work...
Any idea how to do this or were to find help on the web? Thanks!
_ScrolThumbs->GetSizer()->Clear(true);
// or
_ScrolThumbs->DestroyChildren();
I need to copy two columns from an QSqlTableModel and put into a QVector.
I'm trying this:
ParameterData pd;
QSqlTableModel *m = mapTbModels.value(table);
QList<QSqlField> parameterList = getFields(table);
for (int j = 0; j <parameterList.size(); j++) {
QSqlField f = parameterList[j];
QVector<QPointF> v;
if (f.type() != QVariant::Int)
continue;
else {
pd.name = f.name();
timer.start();
for (int i = 0; i < m->rowCount(); i++)
v << value(m, i, f.name());
qDebug() << "Database" << timer.elapsed();
}
pd.data = v;
pd.table = table;
emit data(pd);
emit status(QString::number(j*100/parameterList.size()));
QCoreApplication::processEvents();
}
What's the fastest way?
I once made some performance tests with Qt 5.2 and postgres to check the qsql features. It turned out, that using QSqlTableModel is around 1000 times slower than using own SQL queries like
QSqlQuery query("",db);
query.prepare("SELECT a.fueltype_longname, coalesce(a.bunkerlog_amount,0) FROM (\
SELECT f.fueltype_longname, b.bunkerlog_amount, rank() OVER (PARTITION BY b.bunkerlog_fueltype ORDER BY b.bunkerlog_id DESC) FROM data.t_bunkerlog2 b\
RIGHT JOIN data.t_fueltype f ON b.bunkerlog_fueltype = f.fueltype_longname \
) a WHERE a.rank=1");
query.exec();
So for a data intensive app use query/prepare/exec. If you just want so show simple tables to the user, use QSqlTableModel etc. for convenience.
So I have reached my ceiling of knowledge when it comes to Qt and C++ in general I guess. I am creating check boxes in a QScrollArea based off the input from a QComboBox. Depending on the value selected in the QComboBox, a specific number of check boxes are created. Once I created those check boxes, I am having a problem understanding how to interact (in my case, simply check to see if they are checked or not) with them outside of the function they are being created and called in. I know how to work with them if the buttons were static, but since the check boxes are dynamic (is that the right word?) and can change, I don't know what to do. Below is a little snippet of code on how the check boxes are created. If I now want to simply check if any of the boxes are checked, how do I do that. Can I "return" or "call" the created check boxes in another function somehow? I know I'll simply need to loop through the array and check, I just simply don't know how to get the array of check boxes into another function or how to return them in the function below.
Thanks for the help!
void MyProgram::create_checkboxes(QString opnum)
{
QWidget* MDAcheckboxes = new QWidget(ui->MDA);
QVBoxLayout* MDAlayout = new QVBoxLayout(MDAcheckboxes);
QCheckBox *MDAmycheckBox[9];
QList<QString> boxes;
if (opnum == "640")
{
boxes << "16-1" << "16-2";
for (int i = 0; i < 2; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "645")
{
boxes << "13-01"<<"13-2"<<"13-3"<<"13-4"<<"13-5";
for (int i = 0; i < 5; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
else if (opnum == "650")
{
boxes << "13-6"<<"13-7"<<"13-8"<<"13-9"<<"13-10"<<"13-11"<<"13-12"<<"13-13"<<"13-14";
for (int i = 0; i < 9; i++)
{
MDAmycheckBox[i] = new QCheckBox(MDAcheckboxes);
MDAmycheckBox[i]->setText(boxes[i]);
MDAlayout->addWidget(MDAmycheckBox[i]);
}
ui->MDA->setWidget(MDAcheckboxes);
}
}
All your checkBoxes should have a parent. In this case you will be able to find it with findChildren. It also can be done without groupBox if you sure that app has no any other checkboxes and findChildren will not return you checkboxes which you don't need.
Try this:
QList<QCheckBox *> allButtons = ui->groupBox->findChildren<QCheckBox *>();
qDebug() <<allButtons.size();
for(int i = 0; i < allButtons.size(); ++i)
{
if(allButtons.at(i)->isChecked())
qDebug() << "Use" << allButtons.at(i)->text()<< i;//or what you need
}
In general case:
QList<QCheckBox*> allButtons = parentOfCheckBoxes->findChildren<QCheckBox *>();
Moreover findChildren allows you to find children with special objectName which can be useful in some cases. Note that you can set the same objectName to the different objects.
http://qt-project.org/doc/qt-5/qobject.html#findChildren
I am using a QTableWidget and want to copy some cells to clipboard. It seems the QTableWidget only supports the selectedItems method.
For some reason I get the output as first column and then second column. Not: first row and then second row. This makes it somehow difficult to seperate the cols/rows. Do you know what went wrong? Thanks!
QList<QTableWidgetItem *> selectedCells(TableView->selectedItems());
QTableWidgetItem * item;
mCopyByteArray.clear();
foreach(item, selectedCells)
{
mCopyByteArray.append(item->text());
mCopyByteArray.append("\r\n");
}
When building it up:
TableView = new QTableWidget(); /* I know that name somehow is wrong ;) */
TableView->setColumnCount(2);
QStringList HHeaderList;
HHeaderList << "Computer name" << "ServiceTag";
TableView->setHorizontalHeaderLabels(HHeaderList);
TableView->verticalHeader()->setVisible(false);
TableView->setEditTriggers(QTableWidget::NoEditTriggers);
Any ideas? Thank you!
This algorithm I wrote should do the trick:
QList<QTableWidgetItem *> selectedCells(TableView->selectedItems());
mCopyByteArray.clear();
QString text;
int row_count = TableView->rowCount();
int column_count = TableView->columnCount();
for( int i = 0; i < row_count; i++ )
{
for( int j = 0; j < column_count; j++ )
{
text = selectedCells.at( i + j * row_count )->text();
mCopyByteArray.append( text );
mCopyByteArray.append( "\r\n" );
}
}
You can use QTableWidget::selectedRanges() instead. Small Example:
#include <QList>
#include <QTableWidget>
#include <QTableWidgetSelectionRange>
/...
// you can have more than one selected areas in the table. So you can have more then one
// selected ranges
QList <QTableWidgetSelectionRange*> selectRanges(TableView->selectedRanges());
for (int i =0; i != selectRanges.size(); ++i) {
QTableWidgetSelectionRange range = selectRanges.at(i);
int top = range.topRow();
int bottom = range.bottomRow();
for (int i = top; i <= bottom; ++i) {
QTableWidgetItem *item1 = TableView->itemAt(i, 0); //first column item
QTableWidgetItem *item2 = TableView->itemAt(i, 1); //second column item
// do desired stuff
}
}
Note: I amn't aware of performance issues for this approach. You can check it.
Not really an answer, but some more information that I found out:
It seems that the order in which the selected items are returned by the selectedItems() function is the order in which they were selected.
Moreover, if the selectionBehavior property of the QTableWidget is set to SelectRows, then the selected items are returned in the order in which the rows were selected. For example, for a 2x3 table, where the rows are numbered 'A', 'B' and the columns are numbered '1', '2', '3': if you select B2 and then A1, then the selected items are returned as: B1,B2,B3,A1,A2,A3.
I have an app where I want to show SQL query results in a hierarchical structure. I have something work that is based on this example.
The main part of my code where the tree nodes are created currently looks like this:
void TreeModel::setupModelData(TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
parents << parent;
QList<QVariant> columnData;
QVector<QString> vecFileNames = getFileNames();
QVector<QString> vecTableNames = getTableNames();
for(int i = 0; i < vecFileNames.size(); i++)
{
columnData.clear();
columnData << vecFileNames[i];
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
int childCount = parents.last()->childCount() - 1;
parents << parents.last()->child(childCount); //add the current parent's last child as a parent
for(int j = 0; j < vecTableNames.size(); j++)
{
columnData.clear();
columnData << vecTableNames[j];
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
QVector<QString> vecTableValues = getTableValues(&vecTableNames[j]);
int childCount = parents.last()->childCount() - 1;
parents << parents.last()->child(childCount); //add the current parent's last child as a parent
for(int k = 0; k < vecTableValues.size(); k++)
{
columnData.clear();
columnData << vecTableValues[j];
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
}
}
parents.pop_back();
}
}
QVector<QString> TreeModel::getFileNames()
{
db.open();
QVector<QString> vecFileNames;
QSqlQuery query(db);
QString strQuery = "SELECT PK_fileName FROM fileproperties";
query.prepare(strQuery);
if(query.exec() == true)
{
while(query.next())
{
vecFileNames.push_back(query.value(0).toString());
}
}
db.close();
return vecFileNames;
}
However, it is incredibly slow retrieving 2000 queries worth of data.
Can anyone suggest another approach to the one I'm using now?
You should implement function hasChildren() and use lazy population of model data. You should basically read this article and documentation of QAbstractItemModel class (especially canFetchMore() function).
I would guess that the perfomance suffers by inserting 2000 entries individually, triggering 2000 view updates, maybe 2000 sorts etc... you should provide a way of adding data to your model that takes "batches" of items and only signals changes once...
For MS SQL Servers I always use QSqlQuery::setForward(true) to speed up the queries by up to 10 times.
This "forward" mode just disables the row caches and forces the sql driver to request all results as one fat reply, instead of getting the query results as multiple parts (one ore more rows).
I discovered the problem with a MS SQL Server 2005+2008 with more than 10 million entries, where I searched for only 200-400 entries for a special day to display them inside a QTableView using an QSqlTableModel.
With the forward mode enabled my query times went from over 10s to only 200-300 milliseconds - on a database with over 10 million entries!
Example:
QSqlQuery query(database);
query.setForwardOnly(m_bForwardOnly);
query.exec(statement);
if ( query.lastError().isValid() || database.lastError().isValid() ) {
...evaluate the results...
}