SftTree/DLL 7.5 - Tree Control
SftBox/OCX 5.0 - Combo Box Control
SftButton/OCX 3.0 - Button Control
SftMask/OCX 7.0 - Masked Edit Control
SftTabs/OCX 6.5 - Tab Control (VB6 only)
SftTree/OCX 7.5 - Tree Control
SftPrintPreview/DLL 2.0 - Print Preview Control (discontinued)
SftTree/DLL 7.5 - Tree Control
SftBox/OCX 5.0 - Combo Box Control
SftButton/OCX 3.0 - Button Control
SftDirectory 3.5 - File/Folder Control (discontinued)
SftMask/OCX 7.0 - Masked Edit Control
SftOptions 1.0 - Registry/INI Control (discontinued)
SftPrintPreview/OCX 1.0 - Print Preview Control (discontinued)
SftTabs/OCX 6.5 - Tab Control (VB6 only)
SftTree/OCX 7.5 - Tree Control
SftTabs/NET 6.0 - Tab Control (discontinued)
SftTree/NET 2.0 - Tree Control
This sample illustrates owner-draw cells and column headers.
The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\MFC\OwnerDraw\SamplVw.cpp or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\MFC\OwnerDraw\SamplVw.cpp (on 32-bit Windows versions).
/****************************************************************************/ /* SftTree/DLL 7.5 - Tree Control for C/C++ */ /* Copyright (C) 1995, 2016 Softel vdm, Inc. All Rights Reserved. */ /****************************************************************************/ #include "stdafx.h" #include "OwnerDraw.h" #include "sampldoc.h" #include "samplvw.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CSampleView IMPLEMENT_DYNCREATE(CSampleView, CView) BEGIN_MESSAGE_MAP(CSampleView, CView) //{{AFX_MSG_MAP(CSampleView) ON_WM_CREATE() ON_WM_SIZE() //}}AFX_MSG_MAP ON_SFTTREEN_LBUTTONDBLCLK_TEXT(IDC_TREE, OnLButtonExpandCollapse) ON_SFTTREEN_LBUTTONDOWN_BUTTON(IDC_TREE, OnLButtonExpandCollapse) ON_SFTTREEN_LBUTTONDBLCLK_BUTTON(IDC_TREE, OnLButtonExpandCollapse) ON_SFTTREEN_EXPANDALL(IDC_TREE, OnExpandAll) ON_SFTTREEN_LBUTTONDBLCLK_COLUMNRES(IDC_TREE, OnLButtonDblClkColumnResize) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSampleView construction/destruction CSampleView::CSampleView() { // create a vertical font LOGFONT lf; CFont* pGuiFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT)); pGuiFont->GetLogFont(&lf); lf.lfEscapement = 900; lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; lf.lfCharSet = DEFAULT_CHARSET; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = FF_DONTCARE; lstrcpy(lf.lfFaceName, _T("Arial")); m_hFontVertical.CreateFontIndirect(&lf); // load sample bitmap m_hBitmap.LoadBitmap(IDB_LOGO); } CSampleView::~CSampleView() { } ///////////////////////////////////////////////////////////////////////////// // CSampleView drawing void CSampleView::OnDraw(CDC* pDC) { CSampleDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); } ///////////////////////////////////////////////////////////////////////////// // CSampleView diagnostics #ifdef _DEBUG void CSampleView::AssertValid() const { CView::AssertValid(); } void CSampleView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CSampleDoc* CSampleView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSampleDoc))); return (CSampleDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CSampleView message handlers int CSampleView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; if (!m_Tree.CreateEx( WS_EX_CLIENTEDGE, SFTTREESTYLE_NOTIFY | /* Notify parent window */ SFTTREESTYLE_VARIABLE | /* Variable height items */ SFTTREESTYLE_LEFTBUTTONONLY | /* Only respond to left mouse button */ SFTTREESTYLE_SCROLL | /* Honor WS_H/VSCROLL */ WS_HSCROLL | WS_VSCROLL | /* Vertical and horizontal scrollbars */ WS_VISIBLE | WS_CHILD, /* Visible, child window */ CRect(0,0,0,0), /* Location */ this, /* Parent window */ IDC_TREE)) /* Tree control ID */ return -1; m_Tree.SetShowHeader(TRUE); /* Show column headers */ /* Register the item pictures. These pictures are used */ /* for all items in the tree control. All three pictures */ /* must be the same size. */ { SFT_PICTURE aPic[3]; Sft_InitPicture(&aPic[0]); Sft_InitPicture(&aPic[1]); Sft_InitPicture(&aPic[2]); m_aThreeItemBitmaps[0].LoadBitmap(IDB_EXPANDABLE);/* Expandable bitmap */ Sft_SetPictureBitmap(&aPic[0], m_aThreeItemBitmaps[0]);/* Assign bitmap */ m_aThreeItemBitmaps[1].LoadBitmap(IDB_EXPANDED);/* Expanded bitmap */ Sft_SetPictureBitmap(&aPic[1], m_aThreeItemBitmaps[1]);/* Assign bitmap */ m_aThreeItemBitmaps[2].LoadBitmap(IDB_LEAF);/* Leaf bitmap */ Sft_SetPictureBitmap(&aPic[2], m_aThreeItemBitmaps[2]);/* Assign bitmap */ m_Tree.SetPictures(aPic); /* Use item pictures */ } m_Tree.SetItemPictureAlign(TRUE); /* Align item bitmaps */ m_Tree.SetTreeLineStyle(SFTTREE_TREELINE_AUTOMATIC0);/* Dotted tree lines (incl. level 0) */ m_Tree.SetShowButtons(TRUE); /* Expand/collapse buttons (level 1..n) */ m_Tree.SetShowButton0(TRUE); /* Show expand/collapse buttons (level 0) */ m_Tree.SetButtons(SFTTREE_BUTTON_AUTOMATIC3);/* Automatic button style 3 */ m_Tree.SetShowGrid(TRUE); /* Show grid */ m_Tree.SetGridStyle(SFTTREE_GRID_BOTH_DOT);/* Dotted grid lines */ m_Tree.SetShowTruncated(TRUE); /* Show ... if truncated */ m_Tree.SetSelectionStyle(SFTTREE_SELECTION_CELL1 | SFTTREE_SELECTION_OUTLINE);/* Select first cell only using outline */ m_Tree.SetSelectionArea(SFTTREE_SELECTIONAREA_ALLCELLS);/* Selection changes by clicking on an item's cells */ m_Tree.SetFlyby(TRUE); /* Flyby highlighting */ m_Tree.SetUpdateCaretExpandCollapse(FALSE);/* don't update caret location when expand/collapse button clicked */ m_Tree.SetScrollTips(TRUE); /* Show Scrolltips */ m_Tree.SetInheritBgColor(TRUE); /* Inherit background color of first cell */ m_Tree.SetReorderColumns(TRUE); /* Column reordering */ m_Tree.SetOpenEnded(TRUE); /* Last column width */ m_Tree.SetShowHeaderButtons(TRUE); /* Show column header as buttons */ /* Define columns */ { SFTTREE_COLUMN_EX aCol[3] = { { 0, 0, /* Reserved */ 221, /* Width (in pixels) */ ES_LEFT | SFTTREE_TOOLTIP, /* Cell alignment */ ES_LEFT | SFTTREE_HEADER_UP, /* Title style */ _T("Vertical Titles"), /* Column header title */ NULL, NULL, /* Reserved field and bitmap handle */ SFTTREE_BMP_RIGHT, /* Picture alignment */ 0, 0, 0, /* Reserved fields */ SFTTREE_NOCOLOR, /* Cell background color */ SFTTREE_NOCOLOR, /* Cell foreground color */ SFTTREE_NOCOLOR, /* Selected cell background color */ SFTTREE_NOCOLOR, /* Selected cell foreground color */ 0, /* Real column position (set by SetColumns call) */ 0, /* Display column number (display position) */ 0, /* Column flag */ 0, /* Minimum column width */ }, { 0, 0, /* Reserved */ 253, /* Width (in pixels) */ ES_LEFT | SFTTREE_TOOLTIP, /* Cell alignment */ ES_LEFT | SFTTREE_HEADER_UP, /* Title style */ _T("Second Column"), /* Column header title */ NULL, NULL, /* Reserved field and bitmap handle */ SFTTREE_BMP_RIGHT, /* Picture alignment */ 0, 0, 0, /* Reserved fields */ SFTTREE_NOCOLOR, /* Cell background color */ SFTTREE_NOCOLOR, /* Cell foreground color */ SFTTREE_NOCOLOR, /* Selected cell background color */ SFTTREE_NOCOLOR, /* Selected cell foreground color */ 0, /* Real column position (set by SetColumns call) */ 1, /* Display column number (display position) */ 0, /* Column flag */ 0, /* Minimum column width */ }, { 0, 0, /* Reserved */ 100, /* Width (in pixels) */ ES_LEFT | SFTTREE_TOOLTIP, /* Cell alignment */ ES_LEFT | SFTTREE_HEADER_UP, /* Title style */ _T("Third Column"), /* Column header title */ NULL, NULL, /* Reserved field and bitmap handle */ SFTTREE_BMP_RIGHT, /* Picture alignment */ 0, 0, 0, /* Reserved fields */ SFTTREE_NOCOLOR, /* Cell background color */ SFTTREE_NOCOLOR, /* Cell foreground color */ SFTTREE_NOCOLOR, /* Selected cell background color */ SFTTREE_NOCOLOR, /* Selected cell foreground color */ 0, /* Real column position (set by SetColumns call) */ 2, /* Display column number (display position) */ 0, /* Column flag */ 0, /* Minimum column width */ } }; m_Tree.SetColumns(3, aCol); /* Set column attributes */ } m_Tree.SetShowRowHeader(SFTTREE_ROWSTYLE_BUTTONCOUNT1);/* Row style */ m_Tree.SetRowColHeaderText(_T("?")); /* Row/column header text */ m_Tree.SetRowColHeaderStyle(ES_LEFT | SFTTREE_HEADER_UP);/* Row/column header style */ m_Tree.SetCharSearchMode(SFTTREE_CHARSEARCH_ALLCHARS, -1);/* Consider all characters typed */ /* Use an ownerdraw callback routine */ { SFTTREE_OWNERDRAWPARM Parm; /* Parameter list */ Parm.lpfnOwnerDrawProc = (LPFNSFTTREE_OWNERDRAWPROC) CSampleView::OwnerDrawCallback;/* User supplied drawing routine */ Parm.OwnerDrawUserData = (SFTTREE_DWORD_PTR)this;/* User supplied data */ m_Tree.SetOwnerDrawCallback(&Parm); } /* Change the default colors */ { SFTTREE_COLORS Colors; m_Tree.GetCtlColors(&Colors); /* Get current color settings */ Colors.colorTreeLines = COLOR_3DDKSHADOW | 0x80000000L;/* Tree line color */ Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */ Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */ m_Tree.SetCtlColors(&Colors); /* Set new colors */ } /*------------------------------------------------------------------------------*/ /* Add a few items. */ /*------------------------------------------------------------------------------*/ for (int i = 0 ; i < 50 ; ++i) { int index; index = m_Tree.AddString(_T("An item"));/* Add an item */ m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */ m_Tree.SetText(index, 2, _T("3nd Column"));/* Set text in next column */ index = m_Tree.AddString(_T("Another item"));/* Add another item */ m_Tree.SetItemLevel(index, 1);/* change level */ m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */ m_Tree.SetText(index, 2, _T("3nd Column"));/* Set text in next column */ /* Set an item's row header text using: */ m_Tree.SetRowText(index, _T("?"));/* Row header text */ index = m_Tree.AddString(_T("A third item"));/* Add another item */ m_Tree.SetItemLevel(index, 2);/* change level */ m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */ m_Tree.SetText(index, 2, _T("3nd Column"));/* Set text in next column */ index = m_Tree.AddString(_T("A fourth item"));/* Add another item */ m_Tree.SetItemLevel(index, 1);/* change level */ m_Tree.SetText(index, 1, _T("2nd Column"));/* Set text in next column */ m_Tree.SetText(index, 2, _T("3nd Column"));/* Set text in next column */ } /*------------------------------------------------------------------------------*/ /* Once ALL TREE CONTROL ITEMS HAVE BEEN ADDED, you can set additional tree */ /* control attributes. */ /*------------------------------------------------------------------------------*/ /* Make all column widths optimal, so text and pictures are */ /* not clipped horizontally. */ m_Tree.MakeColumnOptimal(-1, 0, FALSE);/* Make column widths optimal */ /* Make row header width optimal, so text and pictures are */ /* not clipped horizontally. */ m_Tree.MakeRowHeaderOptimal(0, FALSE);/* Make row header width optimal */ m_Tree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */ m_Tree.SetCurSel(4); // select the 4th item m_Tree.SetCaretIndex(4); // and make it current m_Tree.SetTopIndex(0); // show the first item return 0; } void CSampleView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); m_Tree.MoveWindow(0, 0, cx, cy); } /* Respond to events as the user clicks on different tree */ /* components. The events handled here can be changed to */ /* suit your application. */ void CSampleView::OnLButtonExpandCollapse() { /* get index of item to expand/collapse */ int index = m_Tree.GetExpandCollapseIndex(); /* get current expand/collapsed status */ BOOL fExpanded = m_Tree.GetItemExpand(index); /* if control key is used we'll expand all dependents */ BOOL fDepth = (::GetKeyState(VK_CONTROL)&0x8000); if (fExpanded) m_Tree.Collapse(index, TRUE); else m_Tree.Expand(index, TRUE, fDepth); } /* Respond to numeric keypad multiply key. */ void CSampleView::OnExpandAll() { /* get index of item to expand/collapse */ int index = m_Tree.GetExpandCollapseIndex(); m_Tree.Expand(index, TRUE, TRUE); } /* Respond to events as the user double-clicks on the */ /* column resizing area. The events handled here can be */ /* changed to suit your application. */ void CSampleView::OnLButtonDblClkColumnResize() { /* Resize column optimally */ int realCol = m_Tree.GetResizeColumn(); if (realCol >= 0) { m_Tree.MakeColumnOptimal(realCol);/* Make column width optimal */ m_Tree.RecalcHorizontalExtent(0, FALSE);/* Update horizontal scroll bar */ } } /**********************************************************************/ /* Ownerdraw Callback */ /**********************************************************************/ void CSampleView::OwnerDraw_Column_Header(LPSFTTREE_OWNERDRAW lpInfo) { // This function paints the column header using a vertical font // it even takes themes into consideration, so it's a bit more complicated // than the average application. // get general information about tree control and columns LPSFTTREE_COLUMN_EX lpCol; int nCols = m_Tree.GetColumns(&lpCol);/* Get column attributes */ // Set up CDC CDC* pDC = CDC::FromHandle(lpInfo->hDC); // calculate the text size RECT rect, textRect; int len = lstrlen(lpCol[lpInfo->col].lpszTitle); // column title COLORREF clrFg = pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT)); int mode = pDC->SetBkMode(TRANSPARENT); CFont* pOldFont = (CFont*) pDC->SelectObject(&m_hFontVertical); SetRectEmpty(&rect); pDC->DrawText(lpCol[lpInfo->col].lpszTitle, len, &rect, DT_CALCRECT|DT_LEFT); SetRect(&textRect, rect.top, rect.left, rect.bottom, rect.right); if (lpInfo->style == SFTTREE_OD_CALC) { // we need to return just the size of the header we want to paint rect = textRect; if (lpInfo->fThemed) { // Windows themes are used RECT extentRect; GetThemeBackgroundExtent(lpInfo->hThemeHeader, lpInfo->hDC, HP_HEADERITEM, HIS_NORMAL, &rect, &extentRect); rect = extentRect; InflateRect(&rect, 3, 6); // leave a slight gap } else { // No windows themes InflateRect(&rect, 4, 4); // leave a slight gap } lpInfo->DrawRect.bottom = rect.bottom-rect.top; lpInfo->DrawRect.right = rect.right-rect.left; } else { // we need to paint the header int xOffs, yOffs; if (lpInfo->fThemed) { // Windows themes are used int iPartId = HP_HEADERITEM; int iStateId = HIS_NORMAL; if (lpInfo->fSelected) iStateId = HIS_PRESSED; if (lpInfo->fFlyby) iStateId = HIS_HOT; DrawThemeBackground(lpInfo->hThemeHeader, lpInfo->hDC, iPartId, iStateId, &lpInfo->DrawRect, &lpInfo->DrawRect); GetThemeBackgroundContentRect(lpInfo->hThemeHeader, lpInfo->hDC, iPartId, iStateId, &lpInfo->DrawRect, &rect); } else { // No windows themes pDC->DrawFrameControl(&lpInfo->DrawRect, DFC_BUTTON, DFCS_BUTTONPUSH | (lpInfo->fSelected ? DFCS_PUSHED : 0)); rect = lpInfo->DrawRect; } xOffs = max(0, ((lpInfo->DrawRect.right-lpInfo->DrawRect.left) - (textRect.right-textRect.left))/2); yOffs = max(0, ((lpInfo->DrawRect.bottom-lpInfo->DrawRect.top) - (textRect.bottom-textRect.top))/2); if (lpInfo->fSelected) { xOffs++; yOffs--; } pDC->ExtTextOut(lpInfo->DrawRect.left+xOffs, lpInfo->DrawRect.bottom-yOffs, 0, &lpInfo->DrawRect, lpCol[lpInfo->col].lpszTitle, len, NULL); } pDC->SelectObject(pOldFont); pDC->SetBkMode(mode); pDC->SetTextColor(clrFg); } void CSampleView::OwnerDraw_Cell(LPSFTTREE_OWNERDRAW lpInfo) { // calculate the cell size RECT rect; BITMAP bm; // Set up CDC CDC* pDC = CDC::FromHandle(lpInfo->hDC); CDC DCTemp; DCTemp.CreateCompatibleDC(pDC); CBitmap* pOldBitmap = (CBitmap*) DCTemp.SelectObject(&m_hBitmap); // Select the bitmap m_hBitmap.GetObject(sizeof(BITMAP), &bm); SetRect(&rect, 0, 0, bm.bmWidth, bm.bmHeight); if (lpInfo->style == SFTTREE_OD_CALC) { // we need to return just the size of the cell we want to paint lpInfo->DrawRect = rect; } else { // we need to paint the cell ::FillRect(*pDC, &lpInfo->DrawRect, (HBRUSH) (COLOR_WINDOW+1)); pDC->BitBlt(lpInfo->DrawRect.left, lpInfo->DrawRect.top, lpInfo->DrawRect.right-lpInfo->DrawRect.left, lpInfo->DrawRect.bottom-lpInfo->DrawRect.top, &DCTemp, 0, 0, SRCCOPY); } DCTemp.SelectObject(pOldBitmap); } void CSampleView::OwnerDraw_Text(LPSFTTREE_OWNERDRAW lpInfo) { CString strText; // Set up CDC for painting CDC* pDC = CDC::FromHandle(lpInfo->hDC); CSftTree* pTree = (CSftTree*) CWnd::FromHandle(lpInfo->hwndCtl); ASSERT(pTree); CFont* pFont = pTree->GetFont(); CFont* pOldFont = pDC->SelectObject(pFont); pOldFont = pDC->SelectObject(pFont); pTree->GetText(lpInfo->index, lpInfo->col, strText); // retrieve the cell text if (lpInfo->style == SFTTREE_OD_CALC) { // we need to return just the size of the cell we want to paint RECT r; SetRectEmpty(&r); pDC->DrawText(strText, &r, DT_CALCRECT | DT_LEFT | DT_SINGLELINE); InflateRect(&r, lpInfo->gap/2, 0); lpInfo->DrawRect = r; } else { // we need to paint the cell RECT r; CBrush br; br.CreateSysColorBrush(COLOR_3DFACE); pDC->FillRect(&lpInfo->DrawRect, &br); if (lpInfo->fSelected) pTree->DrawSelectionOutline(lpInfo->hDC, &lpInfo->DrawRect, RGB(128,0,0), RGB(255,100,100), RGB(255,255,255), RGB(255,0,0)); r = lpInfo->DrawRect; InflateRect(&r, -lpInfo->gap/2, 0); pDC->DrawText(strText, &r, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } pDC->SelectObject(pOldFont); } BOOL CALLBACK CSampleView::OwnerDrawCallback(HWND hwnd, LPSFTTREE_OWNERDRAW lpInfo, SFTTREE_DWORD_PTR UserData) { CSampleView* pThis = (CSampleView*) UserData; // we defined CSampleView this pointer as user data in SetOwnerDrawCallback call if (lpInfo->itemType == SFTTREE_OD_COLHEADER) { pThis->OwnerDraw_Column_Header(lpInfo); return TRUE; } if ((lpInfo->itemType == SFTTREE_OD_CELL || lpInfo->itemType == SFTTREE_OD_CELLTOOLTIP) && lpInfo->col == 1) { if ((lpInfo->index % 5) == 0) { pThis->OwnerDraw_Cell(lpInfo); return TRUE; } else if ((lpInfo->index % 4) == 0) { pThis->OwnerDraw_Text(lpInfo); return TRUE; } } return FALSE; }