I'm trying to insert a item of list control when an add button is clicked.
But an add button is clicked, it does not insert a item.
also I changed View property of list control from icon to report.
Does following code have a problem?
BOOL CMFCApplication7Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
// Here is insert columns.
TCHAR *szText[2] = { _T("NAME"), _T("E-MAIL") };
int nWid[2] = { 65, 180 };
LV_COLUMN lCol;
lCol.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
lCol.fmt = LVCFMT_LEFT;
for (int i = 0; i < 2;i++)
{
lCol.pszText = szText[i];
lCol.iSubItem = i;
lCol.cx = nWid[i];
m_ListC.InsertColumn(i, &lCol);
}
return TRUE;
}
// Here is insert item code.
void CMFCApplication7Dlg::OnBnClickedButtAdd()
{
TCHAR szText[50] = _T("");
int nIndex = 0;
UpdateData(TRUE);
LVITEM litem;
litem.mask = LVIF_TEXT;
litem.iItem = nIndex;
litem.iSubItem = 0;
swprintf_s(szText, sizeof(szText), _T("%s"), m_strName);
litem.pszText = (LPWSTR)szText;
m_ListC.InsertItem(&litem);
litem.iSubItem = 1;
swprintf_s(szText, sizeof(szText), _T("%s"), m_strMail);
litem.pszText = (LPWSTR)szText;
m_ListC.SetItem(&litem);
m_strName = _T("");
m_strMail = _T("");
nIndex++;
UpdateData(FALSE);
}
You set information LVITEM that is not covered by the mask. Also the iSubItem member is not used in report mode when you insert a normal column.
User the member functions of the m_listC InsertColumn, InsertItem and SetItemText instead of the struct Version. It is less error prone.
Tipp: Use ASSERT/VERIFY to check if the things you are doing work... You have no error checking in your code.
Related
I tried to use this piece of code but it does not give any information.
WCHAR szString[256];
MENUITEMINFO mf;
int pos=0;
ZeroMemory(&mf, sizeof(mf));
mf.cbSize = sizeof(mf);
mf.fMask = MIIM_STRING;
mf.fType = MFT_STRING;
mf.cch = 256;
mf.dwTypeData = szString;
for (pos = GetMenuItemCount(hmenu); --pos >= 0; )
if (GetMenuItemInfo(hmenu, (UINT) pos, TRUE, &mf))
if (mf.dwTypeData == L"Print"){
bool x= false;
x= true;
return TRUE;
}
GetMenuItemInfo function does not produce any results. The HMENU i was using was from QueryContextMenu() function, which is supposedly wrong. Any direction anyone could give?
My App setup icons for panes in status bar (class CMFCStatusBar). There is only one method for this task - CMFCStatusBar::SetPaneIcon(). But if icon have alpha channel this method loads wrong image (on black background).
I looked into the source code and I saw that CMFCStatusBar uses internal HIMAGELISTs for every panes. All this HIMAGELIST creates with flag ILC_MASK | ILC_COLORDDB, not ILC_COLOR32 or ILC_COLOR24.
This is a bug!
So, is there a way to use the icons with alpha channel in CMFCStatusBar panes?
Example:
HICON hIcon = ::LoadImage(hModule, MAKEINTRESOURCE(nIconID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
m_StatusBar.SetPaneIcon(m_StatusBar.CommandToIndex(ID_INDICATOR_1), hIcon);
Microsoft developed the CMFC classes (Feature Pack) from the BCG toolkit. If you compare the CMFCStatusBar::SetPaneIcon() method with the BCG method from the same class, you’ll notice a few subtle differences.
BCG defines its method with a flag for alpha blend. The method looks like:
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
The CMFC equivalent removes the ‘bAlphaBlend’ flag.
Comparing the method code, you’ll see that BCG uses the following code that has been removed from the CMFC version:
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
I’m not sure why the CMFC version differs so much (Microsoft may have a valid reason), but, I’ve included the BCG version below. I would study the BCG version and possibly create your own ‘SetPaneIcon’ method from that code (at your own risk).
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
{
ASSERT_VALID(this);
CBCGStatusBarPaneInfo* pSBP = _GetPanePtr(nIndex);
if (pSBP == NULL)
{
ASSERT (FALSE);
return;
}
// Disable animation (if exist):
SetPaneAnimation (nIndex, NULL, 0, FALSE);
if (hBmp == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy (pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
return;
}
BITMAP bitmap;
::GetObject (hBmp, sizeof (BITMAP), &bitmap);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
RecalcLayout ();
}
else
{
ASSERT (pSBP->cxIcon == bitmap.bmWidth);
ASSERT (pSBP->cyIcon == bitmap.bmHeight);
::ImageList_Remove (pSBP->hImage, 0);
}
//---------------------------------------------------------
// Because ImageList_AddMasked changes the original bitmap,
// we need to create a copy:
//---------------------------------------------------------
HBITMAP hbmpCopy = (HBITMAP) ::CopyImage (hBmp, IMAGE_BITMAP, 0, 0, 0);
if (bAlphaBlend)
{
::ImageList_Add (pSBP->hImage, hbmpCopy, NULL);
}
else
{
::ImageList_AddMasked (pSBP->hImage, hbmpCopy, clrTransparent);
}
::DeleteObject (hbmpCopy);
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
}
My solution, based in rrirower code.
CMFCStatusBarPaneInfo* CMyStatusBar::GetPane(int nIndex) const {
if (nIndex == 255 && m_nCount < 255) {
// Special case for the simple pane
for (int i = 0; i < m_nCount; i++)
{
CMFCStatusBarPaneInfo* pSBP = GetPane(i);
ENSURE(pSBP != NULL);
if (pSBP->nStyle & SBPS_STRETCH) {
return pSBP;
}
}
}
if (nIndex < 0 || nIndex >= m_nCount) {
return NULL;
}
if (m_pData == NULL) {
ASSERT(FALSE);
return NULL;
}
return((CMFCStatusBarPaneInfo*)m_pData) + nIndex;
}
void CMyStatusBar::SetPaneIcon(int nIndex, HICON hIcon, BOOL bUpdate /*= TRUE*/)
{
ASSERT_VALID(this);
CMFCStatusBarPaneInfo* pSBP = GetPane(nIndex);
if (pSBP == NULL)
{
ASSERT(FALSE);
return;
}
// Disable animation(if exist):
SetPaneAnimation(nIndex, NULL, 0, FALSE);
if (hIcon == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy(pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
return;
}
ICONINFO iconInfo;
::GetIconInfo(hIcon, &iconInfo);
BITMAP bitmap;
::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap);
::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
pSBP->hImage = ::ImageList_Create(pSBP->cxIcon, pSBP->cyIcon, ILC_COLOR32 | ILC_MASK, 1, 0);
::ImageList_AddIcon(pSBP->hImage, hIcon);
RecalcLayout();
}
else
{
ASSERT(pSBP->cxIcon == bitmap.bmWidth);
ASSERT(pSBP->cyIcon == bitmap.bmHeight);
::ImageList_ReplaceIcon(pSBP->hImage, 0, hIcon);
}
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
}
I already created treeview where I can add some items. Basicly I want to tree-view all directories and files with icons associated to them.
So I have these functions:
Adding items to treeview
HTREEITEM AddItemToTree(HWND hwndTree, char *text, int nLevel)
{
TVINSERTSTRUCT tvins;
static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST;
static HTREEITEM hRootItem = NULL;
static HTREEITEM hPrevLev2Item = NULL;
AddIconToTree(hwndTree, text); //////////// THIS IS THE FUNCTION BELOW...
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = 0;
tvi.iSelectedImage = 0;
tvi.pszText = GetFileNameFromPath(text);
tvins.hInsertAfter = hPrev;
tvins.item = tvi;
if(nLevel == 1)
{
tvins.hParent = TVI_ROOT;
}
else if(nLevel == 2)
{
tvins.hParent = hRootItem;
}
else
{
TVITEM tviSetup;
tviSetup.hItem = hPrev;
tviSetup.mask = TVIF_PARAM;
TVITEM * tviLocal = &tviSetup;
TreeView_GetItem(hwndTree, tviLocal);
if(nLevel > tviLocal->lParam)
{
tvins.hParent = hPrev;
}
else
{
HTREEITEM hPrevLocal = TreeView_GetParent(hwndTree, hPrev);
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
for(int i = nLevel; i <= tviLocal->lParam;)
{
HTREEITEM hPrevLocalTemp = TreeView_GetParent(hwndTree, hPrevLocal);
hPrevLocal = hPrevLocalTemp;
tviLocal->hItem = hPrevLocal;
TreeView_GetItem(hwndTree, tviLocal);
}
tviLocal->mask = TVIF_TEXT;
TreeView_GetItem(hwndTree, tviLocal);
tvins.hParent = hPrevLocal;
}
}
hPrev = (HTREEITEM)SendMessage(hwndTree, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
if(hPrev == 0)
{
return false;
}
if(nLevel == 1)
{
hRootItem = hPrev;
}
return hPrev;
}
ADDING ICONS TO TREEVIEW:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SMALLICON);
int index = sfi.iIcon;
ICONINFO iconinfo;
GetIconInfo(sfi.hIcon, &iconinfo);
HBITMAP hBitmap = iconinfo.hbmColor;
DestroyIcon(sfi.hIcon);
himg = ImageList_Create(16, 16, ILC_COLOR32, 1, 1);
int iImageList = ImageList_Add(himg, hBitmap, NULL);
DeleteObject(hBitmap);
//TreeView_SetImageList(hwndTree, himg, TVSIL_NORMAL);
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)(HIMAGELIST)himg);
MessageBox(hwnd, strPath, "Path:", MB_OK); /* Because of this msgbox I found out what is
really happening, because without it everything I have seen when I run the program was
treeview with icon of the last file, which was folder...So blank icon.*/
return index;
}
My main problem is, that when I'm setting some icon, it is set not only for the one item as I'm expecting, but on all items in treeview. So basicly every item's icon is overwritten by new item's icon. By the way I know that if I want to get icon of folder, I need to use FILE_ATTRIBUTE_DIRECTORY...
So that's it.
Any help would be greatly appriciated!
Thank You in advance :-)
In your AddIconToTree function you're creating a brand new image list every time, which will only ever have one icon in it. You need to maintain the same image list and add additional icons to it rather than re-creating it for every item.
Alternatively, you can get a handle to the shell imagelist with the SHGetImageList function and then assign it to the tree directly. If you don't need to add any of your own images to the tree's image list this is a much easier way of displaying system icons for files and folders as the shell imagelist handles all that for you.
// To initialise the tree's image list - do this one time only
HIMAGELIST himg;
if (SUCCEEDED(SHGetImageList(SHIL_SMALL, IID_IImageList, reinterpret_cast<void**>(&himg))))
SendMessage(hwndTree, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)himg);
Then your AddIconToTree function simply becomes:
int AddIconToTree(HWND hwndTree, char *strPath)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
// SHGFI_SYSICONINDEX will return the icon's index within the shell image list
SHGetFileInfo(strPath, FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi),
SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
return sfi.iIcon;
}
And when you actually add items to the list, make sure you assign the index to the item:
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIS_STATEIMAGEMASK;
tvi.iImage = tvi.iSelectedImage = AddIconToTree(hwndTree, text);
The method called in OnInitDialog:
void ChookDlg::add_tab_items()
{
tab_item_ptrs.push_back( tab_item_ptr( new CTabSLSensor ) );
tab_item_ptrs.push_back( tab_item_ptr(new user_dlg) );
tab_item_ptrs.push_back( tab_item_ptr( new admin_dlg ) );
for ( auto tab_item_res_id = first_tab_item_res_id, idx = 0U; tab_item_res_id != last_tab_item_res_id + 1; ++tab_item_res_id, ++idx )
{
ASSERT(tab_item_ptrs.at(idx)->Create(tab_item_res_id, this)); // calls OnInitDialog
tab_item_ptrs.at(idx)->ShowWindow(SW_HIDE);
mapped_tab_items[static_cast< tab_item >(idx)] =
tab_item_image_container(
tab.InsertItem(tab.GetItemCount(), _T("SL Sensor"), tab_item_ptrs.back().get()),
tab_item_ptrs.at(idx)
);
}
}
tab is an objec of type CMyTabCtrl which inherits CTabCtrl.
Here is the Insert method:
LONG CMyTabCtrl::InsertItem(int nItem, LPCTSTR lpszItem, CMyTabCtrlTab *myTabCtrlTab)
{
UINT mask = TCIF_PARAM;
LPARAM lParam = reinterpret_cast<LPARAM>(myTabCtrlTab);
if (NULL != lpszItem) {
mask |= TCIF_TEXT;
}
ASSERT(myTabCtrlTab != NULL);
LONG retval = CTabCtrl::InsertItem(mask, nItem, lpszItem, 0, lParam);
if (retval < 0)
return retval;
CRect windowRect;
GetWindowRect(&windowRect);
AdjustRect(FALSE, &windowRect);
// The left border is 3 pixel, the bottom border 2 pixel and the right border 1 pixel
// Adjust to 1 pixel at each side.
// windowRect.left -= 2;
// windowRect.bottom += 1;
GetParent()->ScreenToClient(&windowRect);
myTabCtrlTab->SetWindowPos(&wndTop, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), SWP_HIDEWINDOW);
return retval;
}
Debug Assertion Failure is raised in winocc.cpp on the line 318:
BOOL CWnd::SetWindowPos(const CWnd* pWndInsertAfter, int x, int y, int cx,
int cy, UINT nFlags)
{
ASSERT(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));
Templates are set correctly.
Here's the OnInitDialog:
BOOL ChookDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
ASSERT((IDM_RECONNECT & 0xFFF0) == IDM_RECONNECT);
ASSERT(IDM_RECONNECT < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
CString strReconnectMenu;
bNameValid = strReconnectMenu.LoadString(IDS_RECONNECT);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_RECONNECT, strReconnectMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// initialize tab item pointers container
add_tab_items();
tab.ChangeTab( static_cast< int >( tab_item::sensor ) );
return TRUE; // return TRUE unless you set the focus to a control
}
tab declaration:
private:
CMyTabCtrl tab;
Not sure about this because MFC was a life-time ago but instinct tells me the line below is suspect
GetParent()->ScreenToClient(&windowRect);
Should be calling GetClientRect instead of ScreenToClient.
In the code
tab.InsertItem(tab.GetItemCount(), _T("SL Sensor"), tab_item_ptrs.back().get())
the not initialized dialog pointer is taken. It should be of the form
tab.InsertItem(tab.GetItemCount(), _T("SL Sensor"), tab_item_ptrs.at(idx).get())
I want to make the first item in a tray icon's context menu bold. It should be easy but I don't find my answer anywhere. Can someone please point me in the right direction? This is the code that I'm using to render the items:
void MenuItemWin::CreateNative(
LPMENUITEMINFO itemInfo, HMENU nativeParentMenu, bool registerNative)
{
ZeroMemory(itemInfo, sizeof(MENUITEMINFO));
itemInfo->cbSize = sizeof(MENUITEMINFO);
itemInfo->wID = ++UIWin::nextItemId;
itemInfo->dwItemData = (ULONG_PTR) this;
itemInfo->fMask = MIIM_ID | MIIM_FTYPE | MIIM_DATA;
HMENU nativeSubmenu = 0;
if (this->IsSeparator())
{
itemInfo->fType = MFT_SEPARATOR;
}
else
{
itemInfo->fMask = itemInfo->fMask | MIIM_STRING | MIIM_SUBMENU | MIIM_STATE;
itemInfo->fType = MFT_STRING;
itemInfo->fState = this->IsEnabled() ? MFS_ENABLED : MFS_DISABLED;
itemInfo->dwTypeData = (LPWSTR) this->wideOldLabel.c_str();
AutoPtr<MenuWin> wsubmenu = this->submenu.cast<MenuWin>();
if (!wsubmenu.isNull())
nativeSubmenu = wsubmenu->CreateNative(registerNative);
itemInfo->hSubMenu = nativeSubmenu;
if (this->IsCheck())
{
itemInfo->fState |= this->GetState() ? MFS_CHECKED : MFS_UNCHECKED;
}
else if (!this->iconPath.empty())
{
HBITMAP bitmap = UIWin::LoadImageAsBitmap(iconPath,
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
if (bitmap)
{
itemInfo->fMask = itemInfo->fMask | MIIM_BITMAP;
itemInfo->hbmpItem = bitmap;
}
else
{
std::string error = Win32Utils::QuickFormatMessage(GetLastError());
Logger::Get("UI.MenuItem")->Error("Could not load icon (%s): %s",
iconPath.c_str(), error.c_str());
}
}
}
if (registerNative)
{
NativeItemBits* bits = new NativeItemBits;
bits->id = itemInfo->wID;
bits->parentMenu = nativeParentMenu;
bits->submenu = nativeSubmenu;
this->nativeItems.push_back(bits);
}
}