QTableView how to find out if Row is selected? - c++

I have a QTableview that has a QTableModel set to it.
This view can be modified eg. rows/columns shifted and removed etc.
I have a function to export a table model to excel/csv which takes a QTableModel, however the model doesnt reflect the view if its been modified, so i have a function that creates a new table model based on the QTableViews current layout.
However i now want to be able to select a few rows and export only the selected, so in essence i need to just create a model based on selected rows in the view not all of them.
below shows my current loop,
// Loop over the view's data and add it to the map for the model
for(int i = 0; i < rowIndexs.size(); ++i)
{
// Loop over visible headers only as we are matching the view not the model
for(int j = 0; j < headersIndexs.size(); ++j)
{
// Column is the logical index of the visual index of the current column, this values is used as which column to look at in the model to get the cell data
int column = this->horizontalHeader()->logicalIndex(headersIndexs.at(j));
int row = this->verticalHeader()->logicalIndex(rowIndexs.at(i));
/// add to some data container thats not important for this question....
}
so now to make only rows that are selected get added into my container i want to just check is this row selected eg.
if(this->VerticalHeader()->at(row).isSelected)
{
// Add it to the container
}
else
{
// Ignore it and just go to the next one
}
Does such an isSelected function exist on QTableView Rows? if so what is it ??
Cheers

QItemSelectionModel *select = tableview->selectionModel();
QItemSelctionModel has following calls to retrieve the list of QModelIndex.
QModelIndexList selectedColumns ( int row = 0 ) const
QModelIndexList selectedIndexes () const
QModelIndexList selectedRows ( int column = 0 ) const
From QModelIndex to col and row
int row = modelindex.row()
int col = modelindex.col()
From (row, col) to QModelIndex
QModelIndex idx = QTableModel->index(row, col)

Related

While reloading or repainting QTableWidget it adds blank rows and write data after these blank rows

The function is to read the hard drive partitions from a text file. The function is working fine, but when I want to reload the table after the change in partition layout, it add the blank row of the same quantity as displayed previously and starts writing data rows after words.
void PartitionPage::processPartitions(QString line, int numberOfRows){
static int row = 0;
QStringList partitions = line.split(":");
qDebug() << numberOfRows;
//qDebug() << partitions.count();
if(partitionTable->rowCount() < (row + 1))
partitionTable->setRowCount(row + 1);
// we want to dispay first 7 columns only
//if(partitionTable->columnCount() < partitions.size())
// partitionTable->setColumnCount( partitions[0].size() );
// Set Header Label Texts Here
// set the columncount to 7 as we only want to display first 7 column
partitionTable->setColumnCount(7);
partitionTable->setColumnWidth(0, 120);
partitionTable->setColumnWidth(1, 120);
partitionTable->setColumnWidth(2, 120);
partitionTable->setColumnWidth(3, 120);
partitionTable->setColumnWidth(4, 120);
partitionTable->setColumnWidth(5, 120);
partitionTable->setColumnWidth(6, 120);
partitionTable->setHorizontalHeaderLabels(QString("Partition; Start Sector; End Sector; Total Sectors; Partition Size; Partition ID; File System").split(";"));
for( int column = 0; column < partitionTable->columnCount(); column++){
QTableWidgetItem *newItem = new QTableWidgetItem();
newItem->setText(partitions.at(column));
partitionTable->setItem(row, column, newItem);
newItem->setTextAlignment(Qt::AlignCenter);
}
row++;
partitionTable->setAlternatingRowColors(true);
partitionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
}
Blank rows
Qt have many bugs in view-model system. Your most funny.
Possible solutions:
1) Try use another Qt version.
2) Try make table with QTableView and own "model" (children of QAbstractTableModel) That will not simple for first time. But can help

How to Add Icon in cells of a column CListCtrl

I have a CListCtrl that shows my data in rows. It has two column. Now i need to add another column that will be actually showing a icon.
// set look and feel
listCtrl.SetExtendedStyle(listCtrl.GetExtendedStyle() | columnStyles);
Adding row items as below :
for (const auto dataValue : dataTable)
{
int rowIndex = listCtrl.GetItemCount();
listCtrl.InsertItem(rowIndex, dataValue.at(0).c_str());
for (int colIndex = 1; colIndex < listCtrl.GetHeaderCtrl()->GetItemCount(); ++colIndex)
{
listCtrl.SetItemText(rowIndex, colIndex, dataValue.at(colIndex).c_str());
}
}
I added a new column that will contain the icons for the rows.
I can not getting proper idea how to add icon in the cells of the added column. Consider it's added in first column.
Please suggest.
You don't need a new column, as the image is displayed in the left of the first column (Given your text I assume you are using the LVS_REPORT style).
You need to have a member image list with same count of images as items of your list. So on your list's derived class, add a member:
CImageList m_ImageList;
Then on your list's OnCreate function:
m_ImageList.Create(32, 32, ILC_COLOR24, numberOfEnableParts, 1);
m_ImageList.SetImageCount(n);
for (int i = 0; i< n; i++)
{
if(InsertItem(n, sText) != -1)
{
//set text of columns with SetItemText
//...
// don't know if you use a icon or a bitmap; next line I did it for the second case
m_ImageList->Replace(n, CBitmap::FromHandle(hBmp), (CBitmap*)NULL);
//then, associate the item with its own image of the image list
LVITEM lvi;
lvi.iItem= i;
lvi.iSubItem= 0;
lvi.mask = LVIF_IMAGE;
lvi.iImage= i;
SetItem(&lvi);
}
}
SetImageList(m_ImageList, LVSIL_SMALL);

Hide future columns of QStandardItemModel in QTreeView

I have a QStandardItemModel. This model might get additional columns via an input widget.
In addition, the QStandardItemModel is the model of a QTreeView.
I would like to guarantee that just the first n columns of the QStandardItemModel are visualised in the QTreeView.
How could I achieve this?
But:
The model is not aware of the view (expect Qt does something in the background)
The view is not informed about the updated columns by my code. Nevertheless, the new columns are visualised.
What is my motivation?
I would like to visualise the first n columns in a QTreeView. On selection of an item the remaining columns (of the row of the selected item) shall be presented in a QTableWidget as rows.
But:
The model is not aware of the view (expect Qt does something in the background)
The view is not informed about the updated columns by my code. Nevertheless, the new columns are visualised.
You are correct that the model is unaware of the view. This is exactly how it should be and is good practice. The Qt Model-View Framework is a good practical implementation of the Model-View-Controller (MVC) Pattern
Models are not supposed to know what's going to be viewed or not, thier responsibility is to store and organise data and properties of those data.
Views connect to models and have a read-only relationship with them. They must be notified when changes are made to the models so that they know that they must update themselves. In Qt this is done by connecting signals in the model to slots in the view. These connections are made in the function QAbstractItemView::setModel
Your question deals specifically with the display of columns and in Qt, the main Item View classes delegate the responsibility of column and row visibility to the QHeaderView class, which is created automatically by all views by default.
If you want to create special functionality, you need to either manipulate these default views, or else setting a custom header view to the main view.
I've done the second option.
I've also connected the model to two views, one that is limited to show only the first 5 columns and the second one without a custom header view. This is to show that the underlying model is completely unaware of the viewing restrictions and still contains the complete data set.
#include <QtWidgets/QApplication>
#include <QtWidgets/qtreeview.h>
#include <QtGui/qstandarditemmodel.h>
#include <QtWidgets/QHeaderView>
class RestrictedHeaderView : public QHeaderView {
Q_OBJECT
public:
RestrictedHeaderView(int cols, QWidget *parent = 0) : QHeaderView(Qt::Horizontal, parent), visibleColumns(cols) {}
protected slots:
virtual void sectionsInserted(QModelIndex const &parent, int logicalFirst, int logicalLast){
if (!parent.isValid() && logicalLast >= visibleColumns){
for (int col = visibleColumns; col <= logicalLast; ++col){
hideSection(col);
}
}
}
private:
int visibleColumns;
};
#include "main.moc"
int main(int argc, char** argv){
QApplication app(argc, argv);
QTreeView view;
view.setWindowTitle("Limited View");
QTreeView view2;
view2.setWindowTitle("Complete View");
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);
}
}
// Apply the model to both views and show them
view.setModel(&model);
view.show();
view2.setModel(&model);
view2.show();
// set a custom header to the limited view only so that it automatically hides all columns that are inserted after the fifth column
view.setHeader(new RestrictedHeaderView(5));
// Add new columns to the underlying model
model.insertColumns(4, 3);
for (int row = 0; row < 4; ++row){
for(int column = 4; column < 7; ++column){
QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
model.setItem(row, column, item);
}
}
return app.exec();
}

Removing widgets from QGridLayout

I try to remove widgets from a specified row in a QGridLayout like this:
void delete_grid_row(QGridLayout *layout, int row)
{
if (!layout || row < 0) return;
for (int i = 0; i < layout->columnCount(); ++i) {
QLayoutItem* item = layout->itemAtPosition(row, i);
if (!item) continue;
if (item->widget()) {
layout->removeWidget(item->widget());
} else {
layout->removeItem(item);
}
delete item;
}
}
But when I call it, the app crashes with SIGSEGV on delete item in the first iteration. Any ideas?
Short answer: Use the code provided below
Removing a row or column (or even a single cell) from a QGridLayout is tricky. Use the code provided below.
Long answer: Digging into QGridLayout details
First, note that QGridLayout::rowCount() and QGridLayout::columnCount() always return the number of internally allocated rows and columns in the grid layout. As an example, if you call QGridLayout::addWidget(widget,5,7) on a freshly constructed grid layout, the row count will be 6 and the column count will be 8, and all cells of the grid layout except the cell on index (5,7) will be empty and thus invisible within the GUI.
Note that it's unfortunately impossible to remove such an internal row or column from the grid layout. In other words, the row and column count of a grid layout can always only grow, but never shrink.
What you can do is to remove the contents of a row or column, which will effectively have the same visual effect as removing the row or column itself. But this of course means that all row and column counts and indices will remain unchanged.
So how can the contents of a row or column (or cell) be cleared? This unfortunately also isn't as easy as it might seem.
First, you need to think about if you only want to remove the widgets from the layout, or if you also want them to become deleted. If you only remove the widgets from the layout, you must put them back into a different layout afterwards or manually give them a reasonable geometry. If the widgets also become deleted, they will disappear from the GUI. The provided code uses a boolean parameter to control widget deletion.
Next, you have to consider that a layout cell can not just only contain a widget, but also a nested layout, which itself can contain nested layouts, and so on. You further need to handle layout items which span over multiple rows and columns. And, finally, there are some row and column attributes like minimum widths and heights which don't depend on the actual contents but still have to be taken care of.
The code
#include <QGridLayout>
#include <QWidget>
/**
* Utility class to remove the contents of a QGridLayout row, column or
* cell. If the deleteWidgets parameter is true, then the widgets become
* not only removed from the layout, but also deleted. Note that we won't
* actually remove any row or column itself from the layout, as this isn't
* possible. So the rowCount() and columnCount() will always stay the same,
* but the contents of the row, column or cell will be removed.
*/
class GridLayoutUtil {
public:
// Removes the contents of the given layout row.
static void removeRow(QGridLayout *layout, int row, bool deleteWidgets = true) {
remove(layout, row, -1, deleteWidgets);
layout->setRowMinimumHeight(row, 0);
layout->setRowStretch(row, 0);
}
// Removes the contents of the given layout column.
static void removeColumn(QGridLayout *layout, int column, bool deleteWidgets = true) {
remove(layout, -1, column, deleteWidgets);
layout->setColumnMinimumWidth(column, 0);
layout->setColumnStretch(column, 0);
}
// Removes the contents of the given layout cell.
static void removeCell(QGridLayout *layout, int row, int column, bool deleteWidgets = true) {
remove(layout, row, column, deleteWidgets);
}
private:
// Removes all layout items which span the given row and column.
static void remove(QGridLayout *layout, int row, int column, bool deleteWidgets) {
// We avoid usage of QGridLayout::itemAtPosition() here to improve performance.
for (int i = layout->count() - 1; i >= 0; i--) {
int r, c, rs, cs;
layout->getItemPosition(i, &r, &c, &rs, &cs);
if (
(row == -1 || (r <= row && r + rs > row)) &&
(column == -1 || (c <= column && c + cs > column))) {
// This layout item is subject to deletion.
QLayoutItem *item = layout->takeAt(i);
if (deleteWidgets) {
deleteChildWidgets(item);
}
delete item;
}
}
}
// Deletes all child widgets of the given layout item.
static void deleteChildWidgets(QLayoutItem *item) {
QLayout *layout = item->layout();
if (layout) {
// Process all child items recursively.
int itemCount = layout->count();
for (int i = 0; i < itemCount; i++) {
deleteChildWidgets(layout->itemAt(i));
}
}
delete item->widget();
}
};
The QGridLayout itself is managing the QLayoutItem's. I believe the moment you call removeWidget the item will be deleted. Thus you have an invalid pointer at that point. Attempting to do anything with it, not just delete, will fail.
Thus, just don't delete it, you'll be fine.

how can i paint row with different color in QTreeWidget (Qt)

i have in my application that when i click on row i have the default blue row marked
but beside this blue color i what to paint the row in different color via function not depending on user clicked signal , in sort i need a function that i will pass the row index and it will paint the row in x color.
create a delegate function with an item role. set the item role in each tree item. Access the item in the paint event of tree delegate and paint the row accordingly.
For QStandardItem you can set the back ground role to your desired color.
void customSelect(const QModelIndex &index)
{
if( !index.isValid() )
return;
QStandardItemModel* myModel = dynamic_cast<QStandardItemModel*> ( index.model() );
if( !myModel )
return;
int row = index.row();
for( int col = 0 , colCount = myModel.columnCount(); col < colCount ; ++i)
{
QStandardItem *item = myModel.item( row, col );
item->setData(Qt::blue, Qt::BackgroundColorRole);
}
}