Remove image from certain treeview item? - c++

I have a treeview with checkboxes and it has imagelist set with TreeView_SetImageList().
I am trying to remove image from nodes that do not have children. I was successful in removing checkboxes from parent nodes, so I thought to try the similar approach:
// add an item
TVINSERTSTRUCT tvis = {0};
tvis.item.mask = TVIF_TEXT // | TVIF_IMAGE;
// tvis.item.iImage = -1; // I thought this will work
// tvis.item.iSelectedImage = -1; // but it does not work at all
tvis.item.pszText = L"Some text";
tvis.hInsertAfter = TVI_LAST;
tvis.hParent = TVI_ROOT;
htItem = reinterpret_cast<HTREEITEM>( SendMessage( hwndTV,
TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );
// remove image
TVITEM tvi;
tvi.hItem = htItem;
tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.iImage = -1;
tvi.iSelectedImage = -1;
TreeView_SetItem( hwndTV, &tvi );
It does not work as expected. At first the image is not shown, but the item text is not next to the checkbox:
If I select another item the image suddenly reappears:
If I click on the problematic node again I get the same result, as shown in the first picture.
My question is simple:
How do I remove an image from a node?
Thank you.
Best regards.

You cannot remove images from individual nodes. Once you have an image list assigned, the TreeView reserves space for the list's images on all nodes equally, even if individual nodes do not display images from the list.
To do what you are asking, do not assign the image list at all, and then custom-drawn the nodes to make them appear however you want.

Related

Setting back and font colour for CComboBoxEx items

I have read up on a few articles about CComboBox and changing font properties by using owner draw.
But I am using a CComboBoxEx. At the moment I can set the images etc.:
COMBOBOXEXITEM cmbItem;
cmbItem.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT | CBEIF_LPARAM;
if (psReference != nullptr) // AJT v18.1.6
cmbItem.iImage = ImageType::kReferenced;
else
cmbItem.iImage = pEntry->IsCircuitVisit() || pEntry->IsSpecialEvent() ? ImageType::kSpecialEvent : ImageType::kNoEvent;
cmbItem.iSelectedImage = cmbItem.iImage;
cmbItem.iItem = i;
cmbItem.pszText = strDateText.GetBuffer(_MAX_PATH);
cmbItem.lParam = (LPARAM)pEntry;
strDateText.ReleaseBuffer();
m_cbDates.InsertItem(&cmbItem);
It all works fine. But I would like to set certain items with a different colour background, and or possibly change the text colour.
Is owner draw still the only way?

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.

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

How to get the minimum size of a treeview control that avoids scroll bars?

I have a dialog with a tree view inside it, and would like to have the dialog re-size itself automatically when the tree is expanded or collapsed to avoid scroll bars or excessive space.
In order to do so I need some way of finding the "desired" size of the tree view, i.e., the smallest size large enough to avoid displaying scroll bars.
Any suggestions?
Edit: So, I'm halfway there. I can determine the height by counting the number of visible items and multiplying by TreeView_GetItemHeight. I still have no idea how to find the width, however...
It's not quite perfect (it doesn't seem possible to have TreeView_GetItemRect horizontally include the whole line up to the end of text), but the following works great for my use case with disabled horizontal scrolling.
void Dialog::getDimensionTreeView(unsigned int id,
unsigned int &width, unsigned int &height) {
HWND item = GetDlgItem((HWND)_hwnd, id);
if(!item) {
width = 0;
height = 0;
return;
}
RECT area = { };
HTREEITEM node = TreeView_GetRoot(item);
do {
RECT rc;
LPRECT prc = &rc;
// Ideally this would use `fItemRect`=FALSE, but that seems
// to just return the current width of the treeview control.
TreeView_GetItemRect(item, node, prc, TRUE);
if(rc.left < area.left) area.left = rc.left;
if(rc.right > area.right) area.right = rc.right;
if(rc.top < area.top) area.top = rc.top;
if(rc.bottom > area.bottom) area.bottom = rc.bottom;
} while((node = TreeView_GetNextVisible(item, node)));
width = area.right - area.left;
height = area.bottom - area.top;
}
Thanks to Hans Passant for putting me on the right track.

Row Background Color GtkTreeView Widget

I'm attempting to color disabled rows in a gtk tree view widget a light gray color. From what I've read, I'm supposed to set the background-gdk property of the corresponding cellrenderer and bind it to a model column. This sort of works.
Gtk::CellRendererText* textRenderer = manage(new Gtk::CellRendererText());
textRenderer->property_editable() = false;
Gtk::TreeViewColumn *col = manage(new Gtk::TreeViewColumn("Column1", *textRenderer));
col->add_attribute(*textRenderer, "background-gdk", m_treeview_columns.m_back_color);
my_treeview.append_column(*col);
Gtk::TreeModel::Row row;
for (int i = 0; i < NUMBER_OF_ROWS; iLane++){
row = *(treeview_liststore->append());
row[m_workListColumns.m_back_color] = Gdk::Color("#CCCCCC");
}
In the end though, I get only the cells colored properly. BUT I also get an ugly white-space in between the cells. Does anyone know of a way to fix this or a better way to achieve the effect I'm after?
Could you set the background of the row to match the cell background or set the bakground of the tree view all together ? Or maybe the cell with cell-background-gdk ?