I have a CPropertySheet with three tabs. I have a different CPropertyPage class for each tab. When my CPropertySheet is loaded with the debugger, the first page is always shown correctly. However, when I click on any of the other tabs, the CPropertyPage area becomes blank. Even if I click back on the first tab, the area is still empty. I am using Visual Studio, MFC, C++.
I am trying to find the proper way to handle the different tab clicks and have my tabs show correctly. This is the code to initialize my property sheet and it's pages:
BOOL CSLIMOptCplusplusApp::InitInstance()
{
CWinApp::InitInstance();
SQLHENV m_1;
EnvGetHandle(m_1);
Login lgn; //Creates a Login dialog for the user to enter credentials.
lgn.DoModal();
CImageSheet* imagedlg = new CImageSheet( "Admin Options" );
CImageDisplay* pageImageDisplay = new CImageDisplay;
CImageDimensions* pageImageDimensions = new CImageDimensions;
ListOption* pageListOption = new ListOption;
ASSERT( imagedlg );
ASSERT( pageImageDisplay );
ASSERT( pageImageDimensions );
ASSERT( pageListOption );
imagedlg->AddPage( pageListOption);
imagedlg->AddPage( pageImageDisplay );
imagedlg->AddPage( pageImageDimensions );
imagedlg->m_psh.dwFlags |= PSH_NOAPPLYNOW; //Removes the default Apply button
imagedlg->Create();
imagedlg->ShowWindow( SW_SHOW );
m_pMainWnd = imagedlg;
This is the code for my CPropertySheet class:
BOOL CImageSheet::OnInitDialog()
{
CWnd* pOKButton = GetDlgItem( IDOK );
ASSERT( pOKButton );
pOKButton->ShowWindow( SW_HIDE );
CWnd* pCANCELButton = GetDlgItem( IDCANCEL );
ASSERT( pCANCELButton );
pCANCELButton->ShowWindow( SW_HIDE );
// Set Flags for property sheet
m_bModeless = TRUE;
m_nFlags |= WF_CONTINUEMODAL;
BOOL bResult = CPropertySheet::OnInitDialog();
m_bModeless = FALSE;
m_nFlags &= ~WF_CONTINUEMODAL;
//Get button sizes and positions
CRect rect, tabrect;
GetDlgItem( IDOK )->GetWindowRect( rect );
GetTabControl()->GetWindowRect( tabrect );
ScreenToClient( rect );
ScreenToClient( tabrect );
UpdateData( FALSE );
My problem was that I was setting m_bModeless to false,
BOOL bResult = CPropertySheet::OnInitDialog();
m_bModeless = FALSE; //Change to TRUE to fix the problem.
m_nFlags &= ~WF_CONTINUEMODAL;
Related
I have a CPropertySheet that I am using to show three CPropertyPages. I removed the default "Apply" and "Help" buttons. My problem comes that now that they are removed, I have a large gap where they were once located. Is there a way to remove this gap? Thanks!
Here is a picture of the gap I speak of:
Before the buttons were removed, they were located to the right side of the gap. Please note that the "Change Options" page was created in Visual Studio's designer and the page ends right under the Print button. The main Admin Options CPropertySheet was created entirely from code.
Here is the code to initialize the CPropertySheet and pages (and the removal of the "Help" and "Apply" buttons:
BEGIN_MESSAGE_MAP(CSLIMOptCplusplusApp, CWinApp)
//ON_COMMAND(ID_HELP, &CWinApp::OnHelp) Commented out to remove the "Help" button
END_MESSAGE_MAP()
BOOL OptCplusplusApp::InitInstance()
{
CWinApp::InitInstance();
SQLHENV m_1;
EnvGetHandle(m_1);
Login lgn; //Creates a Login dialog for the user to enter credentials.
lgn.DoModal();
CImageSheet* imagedlg = new CImageSheet( "SLIM Admin Options" );
CImageDisplay* pageImageDisplay = new CImageDisplay;
CImageDimensions* pageImageDimensions = new CImageDimensions;
ListOption* pageListOption = new ListOption;
ASSERT( imagedlg );
ASSERT( pageImageDisplay );
ASSERT( pageImageDimensions );
ASSERT( pageListOption );
imagedlg->AddPage( pageListOption);
imagedlg->AddPage( pageImageDisplay );
imagedlg->AddPage( pageImageDimensions );
imagedlg->m_psh.dwFlags |= PSH_NOAPPLYNOW; //Removes the default Apply button
imagedlg->Create();
imagedlg->ShowWindow( SW_SHOW );
m_pMainWnd = imagedlg;
I will edit if any further details are needed. Thanks.
To achieve this kind of a look with a property sheet....
You need to handle OnitDialog within the sheet and re-size it. For example, using a combination of CPropertySheet::GetPage and CWnd::MoveWindow will accomplish what you want.
BOOL MyPropSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
// TODO: Add your specialized code here
CPropertyPage* pg1 = GetPage(0);
CRect rect(0, 0, 0, 0);
pg1->GetWindowRect(&rect);
CRect thisRect(0, 0, 0, 0);
GetWindowRect(&thisRect);
thisRect.bottom = rect.bottom + 16;
MoveWindow(&thisRect);
return bResult;
}
I have created TreeView like this:
TreeView=CreateWindowEx(0, WC_TREEVIEW, TEXT("Tree View"), WS_VISIBLE | WS_CHILD, 0, 0, 200, 500, hwnd, (HMENU)ID_TREE_VIEW, GetModuleHandle(NULL), NULL);
Now I added one item to it like shown on this website.
It all okay, but after hours and hours of googling I still didn't found answer to these questions:
How to add subitems (nodes)?
How to add checkbox on each item (how to determine if specified checkbox is checked)?
EDIT #4:
In response to OPs request, I have added an example that removes checkbox from a parent node.
THE PROBLEM IS THAT CHECKBOX STILL APPEARS WHEN USER SELECTS A NODE AND PRESSES SPACEBAR.
This question solves that problem.
EDIT #3:
I have added the code that creates a node that is already checked.
It is the second child bode in the WM_CREATE handler.
END OF EDIT
case WM_CREATE:
{
// this is your treeview
TreeView = CreateWindowEx(0, WC_TREEVIEW,
TEXT("Tree View"), WS_VISIBLE | WS_CHILD,
0, 0, 200, 500,
hwnd, (HMENU)ID_TREE_VIEW, GetModuleHandle(NULL), NULL);
/************ enable checkboxes **************/
DWORD dwStyle = GetWindowLong( TreeView , GWL_STYLE);
dwStyle |= TVS_CHECKBOXES;
SetWindowLongPtr( TreeView , GWL_STYLE, dwStyle );
/************ add items and subitems **********/
// add root item
TVINSERTSTRUCT tvis = {0};
tvis.item.mask = TVIF_TEXT;
tvis.item.pszText = L"This is root item";
tvis.hInsertAfter = TVI_LAST;
tvis.hParent = TVI_ROOT;
HTREEITEM hRootItem = reinterpret_cast<HTREEITEM>( SendMessage( TreeView ,
TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );
// and here is an example of removing a checkbox
// from a specific item/subitem in case you ever need it
TVITEM tvi;
tvi.hItem = hRootItem ;
tvi.mask = TVIF_STATE;
tvi.stateMask = TVIS_STATEIMAGEMASK;
tvi.state = 0;
TreeView_SetItem( TreeView, &tvi );
// add firts subitem for the hTreeItem
memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );
tvis.item.mask = TVIF_TEXT;
tvis.item.pszText = L"This is first subitem";
tvis.hInsertAfter = TVI_LAST;
tvis.hParent = hRootItem;
HTREEITEM hTreeSubItem1 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView ,
TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );
// now we insert second subitem for hRootItem
memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );
tvis.item.mask = TVIF_TEXT | TVIF_STATE; // added extra flag
tvis.item.pszText = L"This is second subitem";
tvis.hInsertAfter = TVI_LAST;
tvis.hParent = hRootItem;
// for demonstration purposes let us check this node;
// to do that add the following code, and add the extra flag for
// mask member like above
tvis.item.stateMask = TVIS_STATEIMAGEMASK;
tvis.item.state = 2 << 12;
HTREEITEM hTreeSubItem2 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView ,
TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );
// let us expand the root node so we can see if checked state is really set
TreeView_Expand( TreeView, hRootItem, TVE_EXPAND );
}
return 0L;
EDIT #2:
Here Is the part that explains how to check if item is checked ( it now properly checks when you click on a checkbox and when you press spacebar! ) :
case WM_NOTIFY:
{
LPNMHDR lpnmh = (LPNMHDR) lParam;
if( lpnmh->idFrom == ID_TREE_VIEW ) // if this is our treeview control
{
switch( lpnmh->code ) // let us filter notifications
{
case TVN_KEYDOWN: // tree has keyboard focus and user pressed a key
{
LPNMTVKEYDOWN ptvkd = (LPNMTVKEYDOWN)lParam;
if( ptvkd->wVKey == VK_SPACE ) // if user pressed spacebar
{
// get the currently selected item
HTREEITEM ht = TreeView_GetSelection( ptvkd->hdr.hwndFrom );
// Prepare to test items state
TVITEM tvItem;
tvItem.mask = TVIF_HANDLE | TVIF_STATE;
tvItem.hItem = (HTREEITEM)ht;
tvItem.stateMask = TVIS_STATEIMAGEMASK;
// Request the information.
TreeView_GetItem( ptvkd->hdr.hwndFrom, &tvItem );
// Return zero if it's not checked, or nonzero otherwise.
if( (BOOL)(tvItem.state >> 12) - 1 )
MessageBox( hwnd, L"Not checked!", L"", MB_OK );
else
MessageBox( hwnd, L"Checked!", L"", MB_OK );
}
}
return 0L; // see the documentation for TVN_KEYDOWN
case NM_CLICK: // user clicked on a tree
{
TVHITTESTINFO ht = {0};
DWORD dwpos = GetMessagePos();
// include <windowsx.h> and <windows.h> header files
ht.pt.x = GET_X_LPARAM(dwpos);
ht.pt.y = GET_Y_LPARAM(dwpos);
MapWindowPoints( HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1 );
TreeView_HitTest(lpnmh->hwndFrom, &ht);
if(TVHT_ONITEMSTATEICON & ht.flags)
{
// Prepare to receive the desired information.
TVITEM tvItem;
tvItem.mask = TVIF_HANDLE | TVIF_STATE;
tvItem.hItem = (HTREEITEM)ht.hItem;
tvItem.stateMask = TVIS_STATEIMAGEMASK;
// Request the information.
TreeView_GetItem( lpnmh->hwndFrom, &tvItem );
// Return zero if it's not checked, or nonzero otherwise.
if( (BOOL)(tvItem.state >> 12) - 1 )
MessageBox( hwnd, L"Not checked!", L"", MB_OK );
else
MessageBox( hwnd, L"Checked!", L"", MB_OK );
}
}
default:
break;
}
}
}
break;
The relevant idea for proper testing when spacebar is pressed is handling of TVN_KEYDOWN message.
We use this message to get NMTVKEYDOWN structure filled, which will give us virtual key code of the pressed button and the HWND of the treeview that sent the notification.
Now we use TreeView_GetItem() macro to get the currently selected node and we check its state the same way we did when we did hit testing.
My only problem is concerning this part from the documentation for TVN_KEYDOWN:
Return value
If the wVKey member of lParam is a character key code, the character
will be used as part of an incremental search. Return nonzero to
exclude the character from the incremental search, or zero to include
the character in the search. For all other keys, the return value is
ignored.
I just do not know what to do with the return result so I have put 0L.
Important note: If you need to return value from dialog box procedure use something like this:
SetWindowLongPtr( hwnd, DWLP_MSGRESULT, (LONG_PTR)1 );
return TRUE;
see the remarks for Return value in this documentation and use SetWindowLongPtr instead of SetWindowLong so you can support both x32 and x64 versions of Windows.
That would be all. Hopefully you have your problem solved. If you need further help leave a comment.
END OF EDIT
I have never done checking if tree item is checked but I believe that accepted answer to this question is the way to go.
NOTE:
I would highly appreciate if there someone who can provide code snippet for showing how to determine if treeview node is checked or not.
I have a toolbar to a window in my application. I have read MSDN docs and can handle command and notification messages. My problem is with a dropdown menu attached to a button on the toolbar. The menu items open modal dialog boxes and wait for user to finalize settings changes. After the user clicks 'ok' or 'cancel' focus returns to the main window, however, the toolbar is still under the impression that the left mouse button is down so everytime i drag the mouse over the toolbar button that was clicked the button takes the 'button is checked' state and 'appears' to be pressed.
Is the problem related to the tracking of mouse events?
Here is notification message handling within window proc:
case WM_NOTIFY:
{
LPNMHDR lpnm = ( ( LPNMHDR )lParam );
LPNMTOOLBAR lpnmTB = ( ( LPNMTOOLBAR )lParam );
switch( lpnm->code )
{
case TBN_DROPDOWN:
{
// Get the coordinates of the button.
RECT rc;
SendMessage( lpnmTB->hdr.hwndFrom, TB_GETRECT, ( WPARAM )lpnmTB->iItem, ( LPARAM )&rc );
// Convert to screen coordinates.
MapWindowPoints( lpnmTB->hdr.hwndFrom, HWND_DESKTOP, ( LPPOINT )&rc, 2 );
// handle dropdown menus
return HandleTexEditDropdown( hWnd, lpnmTB, rc );
}
default:
break;
}
break;
}
Here is handle TexEditDropdown():
LRESULT CALLBACK CWindowManager::HandleTexEditDropdown( HWND hWnd, LPNMTOOLBAR lpnm, RECT &rc )
{
HRESULT hr = S_OK;
switch( lpnm->iItem )
{
case IDM_EDITTEXTURE_FILL:
{
// Get the menu.
HMENU hMenuLoaded = LoadMenu( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDR_BUCKETFILL ) );
// Get the submenu for the first menu item.
HMENU hPopupMenu = GetSubMenu( hMenuLoaded, 0 );
// Set up the pop-up menu.
// In case the toolbar is too close to the bottom of the screen,
// set rcExclude equal to the button rectangle and the menu will appear above
// the button, and not below it.
TPMPARAMS tpm;
tpm.cbSize = sizeof( TPMPARAMS );
tpm.rcExclude = rc;
// Show the menu and wait for input.
// If the user selects an item, its WM_COMMAND is sent.
INT nCmd = TrackPopupMenuEx( hPopupMenu,
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_RETURNCMD,
rc.left, rc.bottom, hWnd, &tpm );
DestroyMenu( hMenuLoaded );
switch( nCmd )
{
case IDM_BUCKETFILLSETTINGS:
DialogBox( GetModuleHandle( NULL ),
MAKEINTRESOURCE( IDD_TEXEDITBUCKETFILL ),
hWnd,
( DLGPROC )TexEditSettingsProc );
break;
default:
return 0;
}
SendMessage( ( HWND )lpnm->hdr.hwndFrom, TB_MARKBUTTON, lpnm->iItem, MAKELPARAM( FALSE, 0 ) );
UpdateWindow( hWnd );
SetStateChange();
return 1;
}
case IDM_EDITTEXTURE_RECOVER:
{
// Get the menu.
HMENU hMenuLoaded = LoadMenu( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDR_RECOVER ) );
// Get the submenu for the first menu item.
HMENU hPopupMenu = GetSubMenu( hMenuLoaded, 0 );
// Set up the pop-up menu.
// In case the toolbar is too close to the bottom of the screen,
// set rcExclude equal to the button rectangle and the menu will appear above
// the button, and not below it.
TPMPARAMS tpm;
tpm.cbSize = sizeof( TPMPARAMS );
tpm.rcExclude = rc;
// Show the menu and wait for input.
// If the user selects an item, its WM_COMMAND is sent.
INT nCmd = TrackPopupMenuEx( hPopupMenu,
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL | TPM_RETURNCMD,
rc.left, rc.bottom, hWnd, &tpm );
DestroyMenu( hMenuLoaded );
switch( nCmd )
{
case IDM_RECOVERFILE:
{
WCHAR wcs[ MAX_PATH ] = L"",
wcsFiletype[ MAX_PATH ] = L"",
wcsFilename[ MAX_PATH ] = L"";
D3DXIMAGE_INFO info;
// get currently loaded image info
if( FAILED( hr = CTextureEditor::GetImageInfo( &info ) ) )
{
DebugStringDX( ClassName, "Failed to CTextureEditor::GetImageInfo() at AuxiliaryViewportProcess()", __LINE__, hr );
break;
}
if( !CTextureEditor::CatImageFileType( info.ImageFileFormat, wcsFiletype ) )
{
DebugStringDX( ClassName, "Invalid image filetype at AuxiliaryViewportProcess()", __LINE__, hr );
break;
}
wsprintf( wcs, L"GDEImage Filetype (*%s)", wcsFiletype );
memcpy( &wcs[ 26 ], L"*", sizeof( WCHAR ) );
memcpy( &wcs[ 27 ], wcsFiletype, 4 * sizeof( WCHAR ) );
// Declare and initialize an OPENFILENAME struct to use for OpenFile Dialog
OPENFILENAME ofn;
ZeroMemory( ( void* )&ofn, sizeof( OPENFILENAME ) );
ofn.lStructSize = sizeof( ofn ); // SEE NOTE BELOW
ofn.hwndOwner = hWnd;
ofn.lpstrTitle = L"Recover Image From File";
ofn.lpstrFilter = wcs;
ofn.lpstrFile = wcsFilename;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"image file";
ofn.lpstrInitialDir = app.GetBinDirectory();
// OpenFile Dialog
if( GetOpenFileName( &ofn ) )
{
if( FAILED( hr = CTextureEditor::Recover( 0, wcsFilename ) ) )
{
DebugStringDX( ClassName, "Failed to CTextureEditor::Recover() at AuxiliaryViewportProc()", __LINE__, hr );
break;
}
}
break;
}
default:
return 0;
}
SendMessage( ( HWND )lpnm->hdr.hwndFrom, TB_MARKBUTTON, lpnm->iItem, MAKELPARAM( FALSE, 0 ) );
UpdateWindow( hWnd );
SetStateChange();
return 1;
}
default:
return 0;
}
return 0;
}
I think the returned value for TBN_DROPDOWN is not correct -- you are returning 1 which maps to TBDDRET_NODEFAULT meaning "The drop-down was not handled", you'll need to return TBDDRET_DEFAULT or TBDDRET_TREATPRESSED.
I have a tab control in my Win32 application. The control is multi-row capable. When I resize the window such that the tab control is reduced in width, multiple rows show up. The problem is that when I click on one of the lower rows the tabs in the upper rows are blocked by the current tab's window( the tab control doesn't properly resize the content window of the current tab so that the upper rows are visible ). How do I account for this problem?
Here is code for my resize function:
RECT cr;
GetClientRect( pHdr->hWndTab, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &cr );
OffsetRect( &cr, cxMargin - cr.left, cyMargin - cr.top );
SetWindowPos( pHdr->hWndDisplay, 0, cr.left, cr.top, cr.right, cr.bottom, SWP_SHOWWINDOW );
This code comes from Microsoft website...
pHdr->hWndTab is the window handle for the tab control
pHdr->hWndDisplay is the window handle for the content window of the current tab
EDIT: Actually, after clicking the lower tabs, the upper tabs move to the top of control...however, they are still blocked by the content window...
I fixed the problem by adjusting the display rectangle after offsetting:
typedef struct tag_dlghdr
{
HWND hWndTab;
HWND hWndDisplay;
RECT rcDisplay;
DLGTEMPLATE *apRes[ MAX_PAGES ];
DLGPROC MsgProc[ MAX_PAGES ];
}DLGHDR
Resize( HWND hWndDlg )
{
DLGHDR *pHdr = ( DLGHDR * )GetWindowLong( hWndDlg, GWL_USERDATA );
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD( dwDlgBase ) / 4;
int cyMargin = HIWORD( dwDlgBase ) / 8;
m_niCurTabSel = TabCtrl_GetCurSel( pHdr->hWndTab );
RECT cr;
GetClientRect( pHdr->hWndTab, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &cr );
OffsetRect( &cr, cxMargin - cr.left, cyMargin - cr.top );
CopyRect( &pHdr->rcDisplay, &cr );
TabCtrl_AdjustRect( pHdr->hWndTab, FALSE, &pHdr->rcDisplay );
SetWindowPos( pHdr->hWndDisplay, 0, pHdr->rcDisplay.left, pHdr->rcDisplay.top, pHdr->rcDisplay.right, pHdr->rcDisplay.bottom, SWP_SHOWWINDOW );
}
due to layout customization needs, I extended CTreeCtrl class.
I absolutely need to use CDC::DrawText() function to dinamically (re)write the text of the single nodes, WITHOUT calling SetItemText() function more than once(mandatory requisite).
Then, I wrote my own implementation of OnPaint() method.
I implemented also a DrawItems() method which draws nodes in CTreeCtrl.
Since I don't want to modify anything else than single labels beside the single nodes, then I need to re-implement most of original CTreeCtrl::OnPaint() code.
I only have two doubts:
How can I show the DEFAULT CTreeCtrl icons? I dont'need/don't want
custom icons.
How can I restore the default layout of selection mode for individual nodes?
Simply, currently selected nodes should be appear highlighted.
Some pieces of simplified, auto-explanatory code below:
void MyDlg::OnPaint()
{
CPaintDC dc(this);
CDC dc_ff;
CBitmap bm_ff;
CBitmap *bm_old;
CFont *font;
CFont *old_font;
CFont fontDC;
int old_mode;
GetClientRect(&m_Rect);
dc_ff.CreateCompatibleDC( &dc );
bm_ff.CreateCompatibleBitmap( &dc, m_Rect.Width(), m_Rect.Height() );
dc_ff.SelectObject( &bm_ff );
font = GetFont();
old_font = dc_ff.SelectObject( font );
// Could / Should be called here?
CWnd::DefWindowProc(WM_PAINT, (WPARAM)dc.m_hDC, 0);
old_mode = dc_ff.SetBkMode(TRANSPARENT);
dc_ff.FillSolidRect(m_Rect, dc_ff.GetBkColor());
DrawItems( &dc_ff ); // DrawItems() member function draws single nodes of CTreeCtrl
dc.BitBlt( m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height(), &dc_ff, 0, 0, SRCCOPY);
dc_ff.SelectObject( old_font );
dc_ff.SetBkMode( old_mode );
dc_ff.SelectObject( bm_old );
}
void MyDlg::DrawItems( CDC *pDC )
{
// draw items
HTREEITEM show_item, parent;
CRect rc_item;
CString name;
DWORD tree_style;
int count = 0;
int state;
bool selected;
bool has_children;
show_item = GetFirstVisibleItem();
if ( show_item == NULL )
return;
color = pDC->GetTextColor();
tree_style = ::GetWindowLong( m_hWnd, GWL_STYLE );
do
{
state = GetItemState( show_item, TVIF_STATE );
parent = GetParentItem( show_item );
has_children = ItemHasChildren( show_item ) || parent == NULL;
selected = (state & TVIS_SELECTED) && ((this == GetFocus()) ||
(tree_style & TVS_SHOWSELALWAYS));
if ( GetItemRect( show_item, rc_item, TRUE ) )
{
if ( has_children || selected )
{
if ( selected )
{
// HERE i need to
}
else
// do some stuff...
if ( has_children )
{
HICON icon;
// HERE I need to load CTreeCtrl nodes _DEFAULT_icon
icon = LoadIcon(NULL, IDI_ASTERISK);
if ( icon != NULL )
DrawIconEx( pDC->m_hDC, rc_item.left - 18, rc_item.top, icon, 16, 16,0,0, DI_NORMAL );
}
}
if ( !has_children )
{
HICON icon;
*// HERE I need to load CTreeCtrl nodes _DEFAULT_icon*
icon = LoadIcon(NULL, IDI_ASTERISK);
if ( icon != NULL )
DrawIconEx( pDC->m_hDC, rc_item.left - 18, rc_item.top, icon, 16, 16,0,0, DI_NORMAL );
}
name = GetItemText( show_item );
// ...
if ( selected )
{
pDC->DrawText( "Temp", rc_item, DT_LEFT );
}
else
{
pDC->DrawText( "Temp", rc_item, DT_LEFT );
}
//if ( state & TVIS_BOLD )
// pDC->SelectObject( font );
}
} while ( (show_item = GetNextVisibleItem( show_item )) != NULL );
}
All I need, is source code of an almost-standard CTreeCtrl::OnPaint() implementation.
Any suggestion/help is appreciated. :-)
Thanks
IT.
You don't need to overload onPaint. If you set a tree items text as LPSTR_TEXTCALLBACK, the CtreeCtrl will fire the message TVN_GETDISPINFO to retrieve new text every time that item is displayed. Regeister a message handler using ON_NOTIFY if it's in a parent window or ON_NOTIFY_REFLECT if you are subclassing CTreeCtrl. This message handler can assign the text you want but allow the treeCtrl to continue drawing as normal.
TVN_GETDISPINFO Documentation
If you went the parent Cwnd route, youd need
So you'd need to assign the message handler in the cpp file:
BEGIN_MESSAGE_MAP(MyCWnd, CWnd)
ON_NOTIFY(TVN_GETDISPINFO, tree_ctl_id, CustomTreeControl::OnGetdispinfo)
END_MESSAGE_MAP()
Function prototype in header
afx_msg void OnGetdispinfo( NMHDR* pNMHDR, LRESULT* pResult );
This at the end of your class definition
DECLARE_MESSAGE_MAP()
And the actual function to handle the request
void ColumnTreeControl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult)
{
NMTVDISPINFO * pDispInfo = (NMTVDISPINFO )pNMHDR;
TVITEM item = &pDispInfo->item;
if(item->mask & TVIF_TEXT )
{
item->pszText " YOUR CODE HERE";
}
*pResult = 0;
}