How to Add Icon in cells of a column CListCtrl - mfc

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

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

Setting image in list control item

I want to set image only in particular rows of listctrl.
If I use CListCtrl's SetImageList, it is setting image in first column of each row.
Is it possible to set image only in whichever row I want.
I think it's a little bit messy but it works for me.
If your CListCtrl has LVS_OWNERDRAWFIXED style, than you can decide which column which image will have.
For this purpose you need to set extended style LVS_EX_SUBITEMIMAGES for your list after it will be created. Than you add CImageList
field to your CListCtrl-derived class, for example it will have m_imgList name. This field has to be initialized with default values
and with image resource that will be using. After that you have to call SetImageList and pass it m_imgList. As long as your list will
have LVS_OWNERDRAWFIXED style you need to implement DrawItem function in which you will call something like this for image drawing:
LVITEM lvItem = {0};
lvItem.mask = LVIF_IMAGE;
lvItem.iSubItem = nCol; // column index
lvItem.iItem = nItem; // item index
GetItem(&lvItem);
POINT p; // init it like you want
pDC // pointer on device context
m_imgList.Draw(pDC, lvItem.iImage, p, ILD_MASK);
And before that, when you will fill the list with values, you have to fill in LVITEM structure for needed column:
LVITEM lvItem = {0};
lvItem.iItem = nItem; // item index
lvItem.iSubItem = i; // column index
lvItem.iImage = nImg; // image index from imageList
lvItem.mask = LVIF_IMAGE;
And after that you have to call InsertItem or SetItem with this lvItem parameter.
A simple way to achieve it is adding a transparent image in your CImageList and set it on the list item you don't want the image to appear.

QTableView how to find out if Row is selected?

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)

How to change UITabBarItem position?

I need to change UITabBarItem's image and text position when it's highlighted. Is it possible?
It's look like there is no way to change UITabBarItem's image's position. I just corrected my selected image to have about 15 pixels in button and corrected UITabBarItem's title's position on 15 in tabBar:didSelectItem: method of my custom UITabBarController:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
// If there is another selected item set default properties to it.
for (int counter = 0; counter < [self.tabBar.items count]; counter++) {
UITabBarItem *currentSelectedItem = [self.tabBar.items objectAtIndex:counter];
[currentSelectedItem setTitlePositionAdjustment:UIOffsetMake(0, 0)];
}
// Set selected item.
UITabBarItem *selectedItem = item;
[selectedItem setTitlePositionAdjustment:UIOffsetMake(0, -15)];
}

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.