I can't seem to add the certain dialog box in the TAB CONTROL that i've created.
Can someone help me?
I've created tab items (TCITEM) and the tab control using CreateWindow.
tab_handle is an HWND global variable.
//create items for tab
TCITEM tab1Item;
tab1Item.mask = TCIF_TEXT;
tab1Item.pszText = "Tab 1";
TCITEM tab2Item;
tab2Item.mask = TCIF_TEXT;
tab2Item.pszText = "Tab 2";
//create tab
CreateWindow(WC_TABCONTROL, "Test", TCS_FLATBUTTONS | WS_CHILD | WS_VISIBLE, 10, 20, 450, 230, this->m_hWnd, (HMENU) IDD_DLGTAB1, (HINSTANCE)GetWindowLong(this->m_hWnd, GWL_HINSTANCE), NULL);
//getting of tab
tab_handle = GetDlgItem(this->m_hWnd, IDD_DLGTAB1);
//inserting of tab items in tab
RECT tab_rectangle;
GetClientRect(tab_handle, &tab_rectangle);
int width = (tab_rectangle.right - tab_rectangle.left);
int height = (tab_rectangle.bottom - tab_rectangle.top);
//create dialog
HWND dialog_handle = CreateDialogParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), tab_handle, (DLGPROC) Tab1Dlg::DlgProc, (LPARAM) lParam);
TabCtrl_InsertItem(tab_handle, 0, &tab1Item);
TabCtrl_InsertItem(tab_handle, 1, &tab2Item);
MoveWindow(dialog_handle, tab_rectangle.left+20, tab_rectangle.top+20,(width - 300),(height - 300), TRUE);
ShowWindow(dialog_handle, SW_SHOW);
You have to create the dialog first. Then create the tab control as a child control of the dialog.
It's easier to use the dialog editor to drag and drop a tab control in to dialog. Then you can skip CreateWindow(WC_TABCONTROL...) and use GetDlgItem(dialog_handle, IDC_TAB1) to find the tab control.
You also need to create 2 border-less child dialogs in resource editor (not popup dialog). Then use CreateDialog(0, MAKEINTRESOURCE(IDD_PAGE1), dialog_handle, TabChildProc) to put child dialogs inside the tab.
If making a modal dialog, you may want to use DialogBox instead of CreateDialogParam and do the initialization in WM_INITDIALOG
HINSTANCE hinst = GetModuleHandle(NULL);
HWND dialog_handle = CreateDialogParam(hinst,
MAKEINTRESOURCE(IDD_DIALOG2), 0, (DLGPROC)Tab1Dlg::DlgProc, (LPARAM)0);
ShowWindow(dialog_handle, SW_SHOW);
RECT rc;
GetClientRect(dialog_handle, &rc);
CreateWindow(WC_TABCONTROL, "Test", TCS_FLATBUTTONS | WS_CHILD | WS_VISIBLE,
rc.left + 10, rc.top + 10,
rc.right - 20, rc.bottom - 20 - 30,
dialog_handle, (HMENU)IDC_TAB1, hinst, NULL);
tab_handle = GetDlgItem(dialog_handle, IDC_TAB1);
TCITEM tci = { 0 };
tci.mask = TCIF_TEXT;
char buf[50];
tci.pszText = buf;
strcpy_s(buf, "Page1");
tci.cchTextMax = strlen(buf);
TabCtrl_InsertItem(tab_handle, 0, &tci);
strcpy_s(buf, "Page2");
tci.cchTextMax = strlen(buf);
TabCtrl_InsertItem(tab_handle, 1, &tci);
Related
I am creating a pop up menu item in win32 . I was able to create a popup menu item and then I added few icons to it. This is how its looking
sameple code
HMENU Controls = CreatePopupMenu();
InsertMenu(Controls, 0 , MF_STRING, 1, L"FirstMenu00");;
static HBITMAP bmpSource = NULL;
bmpSource = (HBITMAP)LoadImage(NULL, L"C:\\Users\\mac\\bit.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
MENUITEMINFO mii{};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_DATA;
mii.wID = 1;
mii.hbmpItem = bmpSource;// &paHbm[i];
bool st = InsertMenuItem(Controls, 10, TRUE, &mii);
std::string errSTr = GetLastErrorAsString();
TrackPopupMenuEx(Controls, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_HORPOSANIMATION, xPos, yPos, hwnd, NULL);
I am trying to arrange the menu icons in the following fashion
Ie I am trying to create a pattern where first row has 2 icons and the next row has 3 icons .
How can I achieve the same ?
You can use MF_MENUBREAK or MF_MENUBARBREAK flag in AppendMenu function to create a multi-column menu item. It seems that each raw has the same columns.
Here is a sample you can refer to:\
HMENU hmenuPopup = CreatePopupMenu();
// Add the bitmap menu items to the menu.
bool st = AppendMenu(hmenuPopup, MF_BITMAP, uID, (LPCWSTR)paHbm);
if (!st)
{
ErrorExit(L"AddBitmapMenu");
}
st = AppendMenu(hmenuPopup, MF_BITMAP | MF_MENUBARBREAK, uID + 1, (LPCWSTR)LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP2)));
if (!st)
{
ErrorExit(L"AddBitmapMenu");
}
More reference: Menu Item Separators and Line Breaks, Displaying menu items in multiple columns
I want to insert buttons of diffrent sizes in a toolbar.
Lets say for example 2 buttons. One have a size of 32x16, the Other 16x16.
I used Two Image Lists. Each image list has it's own image size (1st 32x16 - 2nd 16x16).
But the problem is, when I compile the code i get the images loaded correctly but the buttons have the same width(32).
code:
//(1) Create the Toolbar ImageList
HIMAGELIST hImageListLarge = ImageList_Create(32, 16, ILC_COLOR8 | ILC_MASK, 1, 0);
if (!hImageListLarge)
return false;
HIMAGELIST hImageListSmall = ImageList_Create(16, 16, ILC_COLOR8 | ILC_MASK, 1, 0);
if (!hImageListSmall)
return false;
//(2) Fill the Image List
if (ImageList_Add(hImageListLarge,
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_CONNECT_TO)),
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_CONNECT_TO_MASK))) == -1)
return false;
if (ImageList_Add(hImageListSmall,
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_HELP)),
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_HELP_MASK))) == -1)
return false;
//(3) Create the Toolbar window
m_hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, nullptr,
WS_CHILD | TBSTYLE_WRAPABLE | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | TBSTYLE_TOOLTIPS ,
0, 0, 0, 0, m_hWnd, nullptr, m_hInstance, nullptr);
if (m_hToolbar == nullptr)
return false;
//(4) Sets the Image list for the Toolbar
SendMessage(m_hToolbar, CCM_SETVERSION, 5, 0);
SendMessage(m_hToolbar, TB_SETIMAGELIST, 0, (LPARAM)hImageListLarge);
SendMessage(m_hToolbar, TB_SETIMAGELIST, 1, (LPARAM)hImageListSmall);
//(5) Initialize the TBBUTTON structures for each button
m_tbButtons[0].fsStyle = BTNS_SEP;
m_tbButtons[1].iBitmap = MAKELONG(0, 0);
m_tbButtons[1].idCommand = ID_CONNECTIONS_CONNECT_TO;
m_tbButtons[1].fsState = TBSTATE_ENABLED;
m_tbButtons[1].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
m_tbButtons[1].iString = (INT_PTR)TEXT("Connect to");
m_tbButtons[2].iBitmap = MAKELONG(0, 1);
m_tbButtons[2].idCommand = ID_HELP_ABOUT;
m_tbButtons[2].fsState = TBSTATE_ENABLED;
m_tbButtons[2].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE ;
m_tbButtons[2].iString = (INT_PTR)TEXT("Help");
//(6) Add buttons to the toolbar
SendMessage(m_hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(m_hToolbar, TB_ADDBUTTONS, 3, (LPARAM)m_tbButtons);
//(7) auto Resize the toolbar
SendMessage(m_hToolbar, TB_AUTOSIZE, 0, 0);
SendMessage(m_hToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);
ShowWindow(m_hToolbar, SW_SHOW);
//(8) Modify the size of the separator that will hold the combobox
TBBUTTONINFO tbbi;
tbbi.cbSize = sizeof(tbbi);
tbbi.dwMask = TBIF_SIZE | TBIF_BYINDEX;
tbbi.cx = 500;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)0, (LPARAM)& tbbi);
tbbi.cx = 32;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)1, (LPARAM)& tbbi);
tbbi.cx = 16;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)2, (LPARAM)& tbbi);
//(9) Get the Rectangle occupied by the separator
RECT rcSep;
SendMessage(m_hToolbar, TB_GETITEMRECT, (WPARAM)0, (LPARAM)& rcSep);
//(10) Create the hosts comboBox
m_hComboHosts = CreateWindow(WC_COMBOBOXW, nullptr, WS_CHILD | CBS_DROPDOWN | WS_VISIBLE,
rcSep.left, rcSep.top, rcSep.right - rcSep.left, rcSep.bottom - rcSep.top, m_hToolbar,
(HMENU)IDC_COMBO_HOSTS, m_hInstance, nullptr);
if (!m_hComboHosts)
return false;
return true;
After a quick check, please modify the following code:
Comment this line of code:
SendMessage(m_hToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);
TBSTYLE_EX_MIXEDBUTTONS
Version 5.81. This style allows you to set text for all buttons, but
only display it for those buttons with the BTNS_SHOWTEXT button style.
The TBSTYLE_LIST style must also be set. Normally, when a button does
not display text, your application must handle TBN_GETINFOTIP or
TTN_GETDISPINFO to display a tooltip. With the TBSTYLE_EX_MIXEDBUTTONS
extended style, text that is set but not displayed on a button will
automatically be used as the button's tooltip text. Your application
only needs to handle TBN_GETINFOTIP or or TTN_GETDISPINFO if it needs
more flexibility in specifying the tooltip text.
When you set TBSTYLE_EX_MIXEDBUTTONS style, it will allow you to set text for all buttons.
After testing, this style will prevent you from changing the width of the button.
If you want to display the button text, just add the BTNS_SHOWTEXT style.
Modified code:
//(1) Create the Toolbar ImageList
HIMAGELIST hImageListLarge = ImageList_Create(32, 16, ILC_COLOR8 | ILC_MASK, 1, 0);
if (!hImageListLarge)
return false;
HIMAGELIST hImageListSmall = ImageList_Create(16, 16, ILC_COLOR8 | ILC_MASK, 1, 0);
if (!hImageListSmall)
return false;
//(2) Fill the Image List
if (ImageList_Add(hImageListLarge,
LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TB_CONNECT_TO)),
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_CONNECT_TO_MASK))) == -1)
return false;
if (ImageList_Add(hImageListSmall,
LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TB_HELP)),
LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TB_HELP_MASK))) == -1)
return false;
//(3) Create the Toolbar window
m_hToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, nullptr,
WS_CHILD | TBSTYLE_WRAPABLE | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | TBSTYLE_TOOLTIPS,
0, 0, 0, 0, m_hWnd, nullptr, hInst, nullptr);
if (m_hToolbar == nullptr)
return false;
//(4) Sets the Image list for the Toolbar
SendMessage(m_hToolbar, CCM_SETVERSION, 5, 0);
SendMessage(m_hToolbar, TB_SETIMAGELIST, 0, (LPARAM)hImageListLarge);
SendMessage(m_hToolbar, TB_SETIMAGELIST, 1, (LPARAM)hImageListSmall);
//(5) Initialize the TBBUTTON structures for each button
m_tbButtons[0].fsStyle = BTNS_SEP;
m_tbButtons[1].iBitmap = MAKELONG(0, 0);
m_tbButtons[1].idCommand = ID_CONNECTIONS_CONNECT_TO;
m_tbButtons[1].fsState = TBSTATE_ENABLED;
m_tbButtons[1].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE; // If you want display text, you can add BTNS_SHOWTEXT
m_tbButtons[1].iString = (INT_PTR)TEXT("Connect to");
m_tbButtons[2].iBitmap = MAKELONG(0, 1);
m_tbButtons[2].idCommand = ID_HELP_ABOUT;
m_tbButtons[2].fsState = TBSTATE_ENABLED;
m_tbButtons[2].fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
m_tbButtons[2].iString = (INT_PTR)TEXT("Help");
//(6) Add buttons to the toolbar
SendMessage(m_hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(m_hToolbar, TB_ADDBUTTONS, 3, (LPARAM)m_tbButtons);
//(7) auto Resize the toolbar
SendMessage(m_hToolbar, TB_AUTOSIZE, 0, 0);
//SendMessage(m_hToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);
ShowWindow(m_hToolbar, SW_SHOW);
//(8) Modify the size of the separator that will hold the combobox
TBBUTTONINFO tbbi;
tbbi.cbSize = sizeof(tbbi);
tbbi.dwMask = TBIF_SIZE | TBIF_BYINDEX;
tbbi.cx = 44;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)1, (LPARAM)& tbbi);
tbbi.cx = 27;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)2, (LPARAM)& tbbi);
//(9) Get the Rectangle occupied by the separator
RECT rcSep;
SendMessage(m_hToolbar, TB_GETITEMRECT, (WPARAM)0, (LPARAM)& rcSep);
//(10) Create the hosts comboBox
m_hComboHosts = CreateWindow(WC_COMBOBOXW, nullptr, WS_CHILD | CBS_DROPDOWN | WS_VISIBLE,
rcSep.left, rcSep.top, rcSep.right - rcSep.left, rcSep.bottom - rcSep.top, m_hToolbar,
(HMENU)IDC_COMBO_HOSTS, hInst, nullptr);
if (!m_hComboHosts)
return false;
return true;
I used the first TB_SETBUTTONINFO message to modify the size of a button (Separator).
To make it large enough for holding a comboBox control:
//(8) Modify the size of the separator that will hold the combobox
TBBUTTONINFO tbbi;
tbbi.cbSize = sizeof(tbbi);
tbbi.dwMask = TBIF_SIZE | TBIF_BYINDEX;
tbbi.cx = 500;
SendMessage(m_hToolbar, TB_SETBUTTONINFO, (WPARAM)0, (LPARAM)& tbbi);
This is the code for creating the ComboBox:
//(9) Get the Rectangle occupied by the separator
RECT rcSep;
SendMessage(m_hToolbar, TB_GETITEMRECT, (WPARAM)0, (LPARAM)& rcSep);
//(10) Create the hosts comboBox
m_hComboHosts = CreateWindow(WC_COMBOBOXW, nullptr, WS_CHILD | CBS_DROPDOWN | WS_VISIBLE,
rcSep.left, rcSep.top, rcSep.right - rcSep.left, rcSep.bottom - rcSep.top, m_hToolbar,
(HMENU)IDC_COMBO_HOSTS, m_hInstance, nullptr);
This is working as expected.
But when I try to add two other buttons (32x16 - 16x16), I get always the same width of the first Imagelist (32).
But when I swap the image list indexes, I get (16 for both).
I am using the new Visual styles ComCtl32.lib
I apologize for my poor English. I write a C ++ application in the Win32 API in Visual Studio 2017 Community on Windows 10. The application has a toolbar with buttons. I want to assign my custom functionality to each button. Therefore, each button must have its custom specific icon. (I added the icons to the application’s ResourceFiles folder.) The problem is that I can’t install my custom ICO icons on the buttons in the toolbar. When I run my application, the buttons are empty without icons. I re-read a lot of information on this topic on SO and on other sites. Still, I can’t install my icons on the buttons. I would be very grateful if anyone would help. Thank you in advance. Below is my code, with which I try to put my icons on the toolbar buttons:
#define IDM_INPUT 0
#define IDM_OUTPUT 1
#define IDM_TRIANGULATE 2
#define IDM_STOP 3
HWND CreateSimpleToolbar(HWND hWndParent)
{
// Declare and initialize the constants used in the function:
// - picture list id for buttons,
const int ImageListID = 0;
// - number of buttons,
const int numButtons = 4;
// - the size of each image for the button.
const int bitmapSize = 16;
const DWORD buttonStyles = BTNS_AUTOSIZE;
// Create the toolbar.
HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0,
hWndParent, NULL, hInst, NULL);
if (hWndToolbar == NULL)
return NULL;
// Create a list of pictures for buttons.
g_hImageList = ImageList_Create(bitmapSize, bitmapSize,
ILC_COLOR16 | ILC_MASK, // Provide a transparent background.
numButtons, 0);
ImageList_AddIcon(g_hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)));
ImageList_AddIcon(g_hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON2)));
ImageList_AddIcon(g_hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON3)));
ImageList_AddIcon(g_hImageList, LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON4)));
// Set a list of pictures for buttons.
SendMessage(hWndToolbar, TB_SETIMAGELIST,
(WPARAM)ImageListID,
(LPARAM)g_hImageList);
// Upload pictures for buttons.
SendMessage(hWndToolbar, TB_LOADIMAGES,
(WPARAM)IDB_STD_SMALL_COLOR,
(LPARAM)HINST_COMMCTRL);
// Initialize information about buttons.
TBBUTTON tbButtons[numButtons] =
{
{ MAKELONG(IDI_ICON1, ImageListID), IDM_INPUT, TBSTATE_ENABLED, buttonStyles, {0}, 0, 0 },
{ MAKELONG(IDI_ICON2, ImageListID), IDM_OUTPUT, TBSTATE_ENABLED, buttonStyles, {0}, 0, 0},
{ MAKELONG(IDI_ICON3, ImageListID), IDM_TRIANGULATE, TBSTATE_ENABLED, buttonStyles, {0}, 0, 0},
{ MAKELONG(IDI_ICON4, ImageListID), IDM_STOP, TBSTATE_ENABLED, buttonStyles, {0}, 0, 0}
};
// Add buttons.
SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons);
// Resize the toolbar and then show it.
SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
ShowWindow(hWndToolbar, TRUE);
return hWndToolbar;
}
IDI_ICON1, IDI_ICON2, IDI_ICON3 and IDI_ICON4 are the identifiers of the four ICO icon files resulting from the addition of these icons to the application resources.
If I check the result of the LoadIcon function in the debugger, I will see the message "Unable to read memories", although the returned HICON value itself is not zero.
Please tell me what needs to be fixed in the above code?
INTRODUCTION AND RELEVANT INFORMATION:
I am trying to implement listview control with editable items and subitems. Instead of regular listview look, items and subitems should have edit control, checkbox or combo box.
I am using raw WinAPI and C++. I am targeting Windows XP onwards.
MY EFFORTS TO SOLVE THE PROBLEM:
After researching here and on the Internet, I was able to only find examples in MFC. They all use LVN_BEGINLABELEDIT technique to implement this behavior.
Unfortunately I do not understand entirely this concept so I have decided to start from scratch ( I consider this also to be the best approach for improving ones programming skills ).
MY CONCEPT:
I have decided to catch NM_DBLCLK for listview and to get coordinates from there using ListView_GetItemRect or ListView_GetSubItemRect macro.
Then I would simply move the combobox/checkbox/edit control over corresponding item/subitem ( combobox/edit control/checkbox would be created as separate, hidden windows ).
After user finishes with input ( by pressing enter or changing focus ) I would simply hide the combobox/checkbox/edit control.
MY CURRENT RESULTS:
At the moment, I am stuck with the dimensions of combobox/edit control/checkbox not being the same as item/subitem dimensions, when moved above the item/subitem.
QUESTION:
Can my code example submitted below be improved to properly adjust combobox/edit control/checkbox window size to the size of the item/subitem? For now, I will only focus on this part of the problem, to keep this question as short as possible.
Here is the instruction for creating small application that illustrates the problem. Notice that I have tried to keep things as minimal as I could:
1.) Create default Win32 project in Visual Studio ( I use VS 2008 ).
2.) Add the following WM_CREATE handler to main window's procedure:
case WM_CREATE:
{
HWND hEdit = CreateWindowEx( 0,WC_EDIT, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_CENTER | ES_AUTOHSCROLL,
250, 10, 100, 20, hWnd, (HMENU)1500, hInst, 0 );
HWND hComboBox = CreateWindowEx( 0,WC_COMBOBOX, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER | CBS_DROPDOWNLIST,
100, 10, 100, 20, hWnd, (HMENU)1600, hInst, 0 );
HWND hwndLV = CreateWindowEx( 0, WC_LISTVIEW,
L"Editable Subitems",
WS_CHILD | WS_VISIBLE | WS_BORDER |
LVS_REPORT | LVS_SINGLESEL,
150, 100, 250, 150, hWnd, (HMENU)2000, hInst, 0 );
// set extended listview styles
ListView_SetExtendedListViewStyle( GetDlgItem( hWnd, 2000 ),
LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER );
// add some columns
LVCOLUMN lvc = {0};
lvc.iSubItem = 0;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
for (long nIndex = 0; nIndex < 5; nIndex++ )
{
wchar_t txt[50];
swprintf_s( txt, 50, L"Column %d", nIndex + 1 );
lvc.iSubItem = nIndex;
lvc.cx = 60;
lvc.pszText = txt;
ListView_InsertColumn( GetDlgItem( hWnd,2000 ), nIndex, &lvc );
}
// add some items
LVITEM lvi;
lvi.mask = LVIF_TEXT;
lvi.iItem = 0;
for( lvi.iItem = 0; lvi.iItem < 10; lvi.iItem++ )
for (long nIndex = 0; nIndex < 5; nIndex++ )
{
wchar_t txt[50];
swprintf_s( txt, 50, L"Item %d%d", lvi.iItem + 1, nIndex + 1 );
lvi.iSubItem = nIndex;
lvi.pszText = txt;
if( ! nIndex ) // item
SendDlgItemMessage( hWnd, 2000,
LVM_INSERTITEM, 0,
reinterpret_cast<LPARAM>(&lvi) );
else // sub-item
SendDlgItemMessage( hWnd, 2000,
LVM_SETITEM, 0,
reinterpret_cast<LPARAM>(&lvi) );
}
}
return 0L;
3.) Add the following handler for WM_NOTIFY in main window's procedure:
case WM_NOTIFY:
{
if( ((LPNMHDR)lParam)->code == NM_DBLCLK )
{
switch( ((LPNMHDR)lParam)->idFrom )
{
case 2000: // remember, this was our listview's ID
{
LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lParam;
// SHIFT/ALT/CTRL/their combination, must not be pressed
if( ( lpnmia->uKeyFlags || 0 ) == 0 )
{
// this is where we store item/subitem rectangle
RECT rc = { 0, 0, 0, 0 };
if( (lpnmia->iSubItem) <= 0 ) // this is item so we must call ListView_GetItemRect
{
// this rectangle holds proper left coordinate
// since ListView_GetItemRect with LVIR_LABEL flag
// messes up rectangle's left cordinate
RECT rcHelp = { 0, 0, 0, 0 };
// this call gets the length of entire row
// but holds proper left coordinate
ListView_GetItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, &rcHelp, LVIR_BOUNDS );
// this call gets proper rectangle except for the left side
ListView_GetItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, &rc, LVIR_LABEL );
// now we can correct the left coordinate
rc.left = rcHelp.left;
}
else // it is subitem, so we must call ListView_GetSubItemRect
{
ListView_GetSubItemRect( lpnmia->hdr.hwndFrom,
lpnmia->iItem, lpnmia->iSubItem,
LVIR_BOUNDS, &rc );
}
// convert listview client coordinates to parent coordinates
// so edit control can be properly moved
POINT p;
p.x = rc.left;
p.y = rc.top;
ClientToScreen( lpnmia->hdr.hwndFrom, &p );
ScreenToClient( hWnd, &p );
MoveWindow( GetDlgItem( hWnd, 1500 ),
p.x, p.y,
rc.right - rc.left,
rc.bottom - rc.top, TRUE );
// set focus to our edit control
HWND previousWnd = SetFocus( GetDlgItem( hWnd, 1500 ) );
}
}
break;
default:
break;
}
}
}
break;
And this is the result I get:
You can clearly see that top and bottom border of the edit control are not drawn properly. As for combobox, the width is properly adjusted, but height remains the same.
I have tried substituting MoveWindow call with SetWindowPos but the result was the same.
After further tampering, I have found out that NMITEMACTIVATE bugs when returning the rectangle of a subitem, if listview doesn't have LVS_EX_FULLROWSELECT style set. You can see this by simply commenting out the part in my WM_CREATE handler where I set this style. Maybe I am doing something wrong and this "bug" may be caused by my code, but I don't see the problem.
EDITED on September, 17th 2014:
After testing the values for iItem and iSubItem members of NMITEMACTIVATE structure when listview doesn't have LVS_EX_FULLROWSELECT I can verify that the bug is not in my code. It always returns iItem to be 0, no matter which subitem I click. This explains the faulty behavior I got when removing this style.
If any further info is required please leave a comment and I will act as soon as possible.
Thank you for your time and efforts to help.
The issue you're facing is multi-faceted.
Firstly, the default font of the edit control is larger (higher) than that of the list-view. You can fix this one quite trivially, by first getting the font from the list-view and then setting it to the edit control. Doing this will then make the bottom border of the control visible.
The next issue is that the caret of the edit control needs a pixel above and below it, to ensure that the control doesn't have its borders interfered with. In addition to this 1 pixel of 'space' you then need another pixel for the border.
Added to this second point, the dimensions calculated by rc.right - rc.left and rc.bottom - rc.top are 1 pixel too small. Think of a rect that starts at 1,1 and extends to 2,2 - this is a rect of 4 pixels - 2 wide and 2 high. Simply subtracting the top/left from the bottom/right would give you a width/height of only 1 pixel each. To fix this, you need to add 1 to each of these subtractions.
Finally, since the caret is exactly the height of the 'client-area' of each item/sub-item, you need to make the edit control 2 pixels taller than the item/sub-item, and start 1 2 pixels higher than it does currently.
Here's the output I get when making the suggested changes:
And here's the changes/additions I made.
1. Get/Set the font. (inserted after creating the list-view and before setting its extended style)
HFONT lvFont = (HFONT)SendDlgItemMessage(hWnd, 2000, WM_GETFONT, 0, 0);
SendDlgItemMessage(hWnd, 1500, WM_SETFONT, (WPARAM)lvFont, TRUE);
2. Set the window position/size
MoveWindow( GetDlgItem( hWnd, 1500 ),
p.x, p.y-2,
1+ rc.right - rc.left,
1+ 2 + rc.bottom - rc.top, TRUE );
Finally, contrast this against the original output from your code:
UPDATE:
Here's a snapshot of the appearance when the built-in label editing functionality is used (LVS_EDITLABELS style)
I have the following code which passes a window handler form OpenCV window to win32 handler, therefore I can show the grabbed images from camera to the screen and the images will show as a child window of my main API.
but the problem is that when I want to add a tooldbar to my program, the image window handler comes at the top of the toolbar. how can I sort this out?
//create a window and set the handler from openCV to win32
cv::namedWindow("test",cv::WINDOW_AUTOSIZE);
hWnd2 = (HWND) cvGetWindowHandle("test");
hParent = ::GetParent(hWnd2);
::SetParent(hWnd2, hWnd);
::ShowWindow(hParent, SW_HIDE);
_liveCapturing=true;
lastPicNr = 0;
SetWindowTextW(hStatus, L"Live Capturing ... ");
if(FullScreen()){
::ShowWindow(hWnd, SW_MAXIMIZE);
}
code for the toolbar :
HWND CreateToolbar(HWND hwnd){
HWND hTbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_TOP , 0, 0, 0, 0, hwnd, (HMENU)12, GetModuleHandle(NULL), NULL);
SendMessage(hTbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[3];
TBADDBITMAP tbab;
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_STD_SMALL_COLOR;
SendMessage(hTbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
return hTbar;
}
Probably you have found the solution a long time ago, but i want to post my anwers in case other users need it.
You can simply add the OpenCV window with the same code you have to a child window in your window (which you set it position in advance). For example you can add it to a static text window (label) ...
If you want to move the OpenCV window, call SetWindowPos() with the desired coordinates.
SetWindowPos(hWnd2, 0, 0, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER);