Trying to create my own Toolbar inside Mainframe class VS 6.0 - c++

I am having issues with creating my own Toolbar inside the Mainframe. I have bitmaps of buttons which I want to use for my own Toolbar but the problem is that the Toolbar displays inside the View of my SDI application. Here is a pic of the incorrectly displayed Toolbar.
http://www.flickr.com/photos/14402427#N02/3409050475/
Here is the code inside the OnCreate function of the Mainframe class : I also have a
// CToolBarCtrl m_wndToolBar; declared inside the MainFrame.h class.
if(m_wndToolBar.Create(WS_CHILD | TBSTYLE_FLAT | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC
,CRect(0,0,250,50),this,0))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
TBBUTTON tbbutton[3] = {0};
CSize button_size(90,90);
CSize bitmap_size(80,80);
//m_wndToolBar.AddStrings("String 1\0String 2\0String 3\0");
tbbutton[0].iBitmap = 0;
tbbutton[0].idCommand = ID_CONNECT;
tbbutton[0].fsState = TBSTATE_ENABLED;
tbbutton[0].fsStyle = TBSTYLE_BUTTON;
tbbutton[0].dwData = 0;
tbbutton[0].iString = 0;
tbbutton[1].iBitmap = 1;
tbbutton[1].idCommand = ID_DISCONNECT;
tbbutton[1].fsState = TBSTATE_ENABLED;
tbbutton[1].fsStyle = TBSTYLE_BUTTON;
tbbutton[1].dwData = 0;
tbbutton[1].iString = 1;
tbbutton[2].iBitmap = 2;
tbbutton[2].idCommand = ID_STOP;
tbbutton[2].fsState = TBSTATE_ENABLED;
tbbutton[2].fsStyle = TBSTYLE_BUTTON ;
tbbutton[2].dwData = 0;
tbbutton[2].iString = 2;
m_wndToolBar.SetButtonSize(button_size);
m_wndToolBar.SetBitmapSize( bitmap_size);
m_wndToolBar.AddButtons(3,tbbutton);
m_wndToolBar.AddBitmap(1,IDB_BITMAP1);
m_wndToolBar.AddBitmap(1,IDB_BITMAP2);
m_wndToolBar.AddBitmap(1,IDB_BITMAP3);
return TRUE;

Add a call to DockControlBar(&m_wndToolBar) just before the return.

From your image it seems that it is not painted or not painted correctly, did you try adding bitmaps first and then adding buttons? or can you call AutoSize on the m_wndToolbarBar.?

Related

C++ win32 ListView columns

I have a problem with my code.
First,the essence of this code is to create a ListView with some columns, using win32.
The problem is when I try to add columns to my ListView and try to display it doesn't show me the columns. Here is my code, thanks for any help.
HWND function::CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient;
// The parent window's client area.
GetClientRect (hwndParent, &rcClient);
HWND hWndListView = CreateWindow(WC_LISTVIEW, "ViewList",WS_BORDER| WS_CHILD | LVS_REPORT | LVS_EDITLABELS,500,300,300,300,hwndParent,NULL,hInst,NULL);
return (hWndListView);
}
VOID function::SetView(HWND hWndListView, DWORD dwView)
{
// Retrieve the current window style.
DWORD dwStyle = GetWindowLong(hWndListView, GWL_STYLE);
// Set the window style only if the view bits changed.
if ((dwStyle & LVS_TYPEMASK) != dwView)
{
SetWindowLong(hWndListView,
GWL_STYLE,
(dwStyle & ~LVS_TYPEMASK) | dwView);
} // Logical OR'ing of dwView with the result of
}
BOOL InitListViewColumns(HWND hWndListView)
{
char szText[256] ="test"; // Temporary buffer.
LVCOLUMN lvc;
int iCol;
// Initialize the LVCOLUMN structure.
// The mask specifies that the format, width, text,
// and subitem members of the structure are valid.
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM|LVS_REPORT;
// Add the columns.
for (iCol = 0; iCol < C_COLUMNS; iCol++)
{
lvc.iSubItem = iCol;
lvc.pszText = "LOL";
lvc.cx = 100; // Width of column in pixels.
if ( iCol < 2 )
lvc.fmt = LVCFMT_LEFT; // Left-aligned column.
else
lvc.fmt = LVCFMT_RIGHT; // Right-aligned column.
// Load the names of the column headings from the string resources.
LoadString(hInst,iCol,szText, sizeof(szText)/sizeof(szText[0]));
// Insert the columns into the list view.
if (ListView_InsertColumn(hWndListView, iCol, &lvc) == -1)
return FALSE;
}
return TRUE;
}
You forgot to specify the WS_VISIBLE style when calling CreateWindow to create the listview. The listview and the columns are there, just not visible.
The buffer you pass to LoadString is never used because you never set lvc.pszText = szText so all the columns are named "LOL".
Edit: My answer applies to the code after it had been edited with fixes from the comments. LVS_REPORT is still not a valid LVCF_* flag but because it has the same value as LVCF_FMT it does no harm in this particular code but should still be removed because the code is technically incorrect.

When using DialogBoxIndirect, how do I get text the user entered when the dialog closes?

I'm using DialogBoxIndirect() to create a modal dialog in memory. One of the controls that I'm adding to the dialog has the EDIT class, so users can type in information in the dialog. When the dialog is closed, how do I figure out what the user typed into the EDIT field? I don't have an HWND for the EDIT field or the dialog itself, all I have is the id. The only way I know of is GetWindowText(), but that requires an HWND.
Code snippet:
//-----------------------
// Define Edit Input
//-----------------------
lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->x = 10; lpdit->y = 10;
lpdit->cx = 150; lpdit->cy = 25;
lpdit->id = ID_TEXT2; // Text input
lpdit->dwExtendedStyle = WS_EX_CLIENTEDGE;
lpdit->style = WS_CHILD | WS_VISIBLE;
lpw = (LPWORD)(lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0081; // Edit class
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_ACP, 0, lpszMessage, -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0; // No creation data
//-----------------------
// Define an OK button.
//-----------------------
lpw = lpwAlign(lpw); // Align DLGITEMTEMPLATE on DWORD boundary
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->x = 10; lpdit->y = 40;
lpdit->cx = 35; lpdit->cy = 13;
lpdit->id = IDOK; // OK button identifier
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
lpw = (LPWORD)(lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // Button class
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_ACP, 0, "OK", -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0; // No creation data
GlobalUnlock(hgbl);
ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE)hgbl, GetFocus(), (DLGPROC)GenericDlgProc);
// How do I get the text here, that the user entered into control id ID_TEXT2?
You can use GetDlgItemText() to get text from an edit control using its ID; basically what this does is a GetDlgItem() followed by a GetWindowText() all in one useful function call.
However by the time your DialogBoxIndirect() call has returned it's too late to do this - the dialog is gone, and the controls along with it. You can't read a control's value once it's been destroyed.
The usual way to deal with this is to handle WM_DESTROY in your DialogProc, and save the control values there (alternatively, if you have an OK and a Cancel button, you might do this in the WM_COMMAND handler for IDOK instead).

How can I have a multi-line item in a ListControl MFC?

I have an MFC List Control in Visual Studio 2013 (C++) with a List of items (Report view)
LVCOLUMN lvColumn;
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 120;
lvColumn.pszText = "Full Name";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(0, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 75;
lvColumn.pszText = "Profession";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(1, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 80;
lvColumn.pszText = "Fav Sport";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(2, &lvColumn);
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 75;
lvColumn.pszText = "Hobby";
((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertColumn(3, &lvColumn);
LVITEM lvItem;
int nItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.pszText = "Sandra C. Anschwitz";
nItem = ((CListCtrl*)GetDlgItem(IDC_LIST1))->InsertItem(&lvItem);
((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 1, "Singer");
((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 2, "HandBall");
((CListCtrl*)GetDlgItem(IDC_LIST1))->SetItemText(nItem, 3, "Beach");
How can I have multiline items for Full Name, Profession, Sport and Hobby?
Surprisingly, this is not possible with the default CListCtrl. But, with a little custom coding (and some trickery), you can get the effect you want.
First, you’ll need to derive your own class from CListCtrl and set the owner draw bit (Owner Draw Fixed = true) for the control style. In your parent dialog class, create an image list (here’s the trickery). The image list will be used to specify the height of each row of the list control. In my example below, I used:
m_imagelist.Create(48, 48, ILC_COLOR4, 10, 10);
m_listctrl.SetImageList(&m_imagelist, LVSIL_SMALL);
You’ll need to play around with the cx and cy values for the image list to fit your needs. Your control will use the image list to size each row because it’s anticipating displaying icons. Next, add a handler for DrawItem like this:
void MyClistCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CString text = _T("Now is the time \nfor all good men\nto come to the aid");
pDC->DrawText(text , &lpDrawItemStruct->rcItem, DT_TOP);
// TODO: Add your code to draw the specified item
}
In my example, this results in…
It may not be an elegant solution, but, it works. Note: With this approach, every row will have the same height.
EDIT: There are a few ways to obtain the row text. The easiest would be to use GetItemText like so:
CString txt = GetItemText(lpDrawItemStruct->itemID, 0);
pDC->DrawText(txt, &lpDrawItemStruct->rcItem, DT_TOP);
The above assumes you set the text for each row using one of the CListCtrl methods to set text.

TreeView add Shell Icons

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

c++ Virtual ListView in Tile view, can't get subitems to appear

I have a straight win32 c++ app and I'm filling the window with a ListView whose view type is set to LV_VIEW_TILE and I'm also setting the style to LVS_OWNERDATA.
I'm having trouble trying to work out how to get the subitems to show. This code creates the view.
DWORD exstyle =WS_EX_CLIENTEDGE|LVS_EX_DOUBLEBUFFER|LVS_EX_JUSTIFYCOLUMNS|LVS_EX_INFOTIP;
g_hwndList = CreateWindowEx(exstyle, WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | LVS_ICON | LVS_OWNERDATA, 0, 0, 0, 0, hWnd, (HMENU) 2702, hInst, NULL);
ListView_SetView(g_hwndList, LV_VIEW_TILE);
LVTILEVIEWINFO tileViewInfo = { };
tileViewInfo.cbSize = sizeof(LVTILEVIEWINFO);
tileViewInfo.dwFlags = LVTVIF_AUTOSIZE;
tileViewInfo.dwMask = LVTVIM_COLUMNS;
tileViewInfo.cLines = 1;
BOOL tst = ListView_SetTileViewInfo(g_hwndList, &tileViewInfo);
I only want one more subitem/column to appear. In my LVN_GETDISPINFO I currently have this:
static int colfmt[1];
colfmt[0] = LVCFMT_LEFT;
static int order[1];
order[0] = 1;
if ((nimfo->item.mask & LVIF_COLUMNS) == LVIF_COLUMNS) {
nimfo->item.cColumns = 1;
nimfo->item.piColFmt = PINT(colfmt);
nimfo->item.puColumns = PUINT(order);
}
if ((nimfo->item.mask & LVIF_TEXT) == LVIF_TEXT) {
nimfo->item.pszText = di->LABEL;
}
if ((nimfo->item.mask & LVIF_IMAGE) == LVIF_IMAGE) {
nimfo->item.iImage = di->IMAGE_INDEX;
}
I can't work out at what point and where I need to supply the subitem/column text, I'm never seeing the nimfo->item.subitem changing from 0 and for each call for LVIF_TEXT the structure values are always the same.
So at what point do I need to supply the extra textual data?
Many thanks.
I, rather stupidly, wasn't adding any columns and therefore wasn't being asked for the other items.
added this and everything works
LVCOLUMN col = {};
col.mask = LVCF_SUBITEM;
col.iSubItem = 0;
ListView_InsertColumn(g_hwndList, 0, &col);