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 sorting, column reordering, responding to column header clicks, context menus, controlling expand/collapse buttons and plus/minus graphics.
The source code is located at C:\Program Files (x86)\Softelvdm\SftTree OCX 7.5\Samples\VC++\BookTable\BookTableDlg.cpp or C:\Program Files\Softelvdm\SftTree OCX 7.5\Samples\VC++\BookTable\BookTableDlg.cpp (on 32-bit Windows versions).
// BookTableDlg.cpp : implementation file // #include "stdafx.h" #include "BookTable.h" #include "BookTableDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CBookTableDlg dialog CBookTableDlg::CBookTableDlg(CWnd* pParent /*=NULL*/) : CDialog(CBookTableDlg::IDD, pParent) { //{{AFX_DATA_INIT(CBookTableDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // load all bitmaps m_BookClosed.LoadBitmap(IDB_EXPANDABLE); m_BookOpen.LoadBitmap(IDB_EXPANDED); m_Topic.LoadBitmap(IDB_LEAF); m_Plus.LoadBitmap(IDB_PLUS); m_Minus.LoadBitmap(IDB_MINUS); m_Plain.LoadBitmap(IDB_PLAIN); } void CBookTableDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CBookTableDlg) DDX_Control(pDX, IDC_CHECKUSEPLAIN, m_CheckUsePlain); DDX_Control(pDX, IDC_CHECKSHOWPLUSMIN, m_CheckPlusMin); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CBookTableDlg, CDialog) ON_COMMAND(ITEMMENU_ENTRY, OnMenu_ItemMenu_Entry) ON_COMMAND(HEADERMENU_SHOWALL, OnMenu_HeaderMenu_ShowAll) ON_COMMAND_RANGE(HEADERMENU_IDS+0, HEADERMENU_IDS+99, OnMenu_HeaderMenu_Entry) //{{AFX_MSG_MAP(CBookTableDlg) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_CHECKSHOWPLUSMIN, OnCheckShowPlusMinClicked) ON_BN_CLICKED(IDC_CHECKUSEPLAIN, OnCheckUsePlainClicked) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CBookTableDlg message handlers BOOL CBookTableDlg::OnInitDialog() { CDialog::OnInitDialog(); // 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 m_vTree = GetDlgItem(IDC_SFTTREE1)->GetControlUnknown(); ASSERT(m_vTree != NULL); #if 0 // This shows how to dynamically create a tree control. If created dynamically, // all properties must also be set dynamically. CWnd* pTree = new CWnd(); pTree->CreateControl(_T("SftTreeOCX75.SftTree.1"), _T(""), WS_CHILD|WS_VISIBLE, CRect(0,0,300,300), this, 123, NULL, FALSE, NULL); m_vTree = pTree->GetControlUnknown(); ASSERT(m_vTree != NULL); #endif // random numbers srand(0); m_vTree->BulkUpdate = VARIANT_TRUE; // Mass update // set default item graphic. This can also be done at design time m_vTree->Items->ItemImageExpandable->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_BookClosed); m_vTree->Items->ItemImageExpanded->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_BookOpen); m_vTree->Items->ItemImageLeaf->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Topic); // set the column header sort indicators m_vTree->Headers->SortIndicators = headerSortIndicatorsSftTreeAuto; m_vTree->Header[0]->SortIndicator = sortIndicatorSftTreeAscending; // make a copy of the tree control's font and make a bold // font for certain cells IFontPtr pFont = m_vTree->GetFont(); IFontPtr pCellFont; HRESULT hr = pFont->Clone(&pCellFont); ASSERT(SUCCEEDED(hr)); pCellFont->put_Bold(TRUE); // Add all available options for (int bk = 1 ; bk <= 4 ; ++bk) { // add a book CString str; str.Format(_T("Book %d"), bk); long BookIndex = m_vTree->Items->Add(_bstr_t(str)); str.Format(_T("Description for book %d"), bk); m_vTree->Cell[BookIndex][1]->Text = (_bstr_t)str; int size = (rand() % 999) + 1; str.Format(_T("%d"), size); m_vTree->Cell[BookIndex][2]->Text = (_bstr_t)str; m_vTree->Item[BookIndex]->Data = size; // add chapters for (int ch = 1 ; ch <= 2 ; ++ch) { str.Format(_T("Chapter %d"), ch); long Index = m_vTree->Items->Add((_bstr_t)str); m_vTree->Item[Index]->Level = 1; // add sections for (int sect = 1 ; sect <= 2 ; ++sect) { str.Format(_T("Section %d"), sect); Index = m_vTree->Items->Add((_bstr_t)str); m_vTree->Item[Index]->Level = 2; } } // after adding the book and all dependent items, we // collapse the item, so it's up to the user to expand it m_vTree->Item[BookIndex]->Collapse(VARIANT_FALSE); // set font IFontDispPtr pFontDisp = pCellFont; m_vTree->Cell[BookIndex][0]->PutFont(pFontDisp); } // End of Mass-Update m_vTree->BulkUpdate = VARIANT_FALSE; // Make columns optimal m_vTree->ColumnsObj->MakeOptimal(); // allow horizontal scrolling m_vTree->Items->RecalcHorizontalExtent(); return TRUE; // return TRUE unless you set the focus to a control } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CBookTableDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CBookTableDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CBookTableDlg::OnCancel() { CDialog::OnCancel(); } void CBookTableDlg::OnCheckShowPlusMinClicked() { if (m_CheckPlusMin.GetCheck()) { m_vTree->Items->PlusMinusImageExpandable->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Plus); m_vTree->Items->PlusMinusImageExpanded->PutBitmapHandle((OLE_HANDLE)(HBITMAP)m_Minus); } else { m_vTree->Items->PlusMinusImageExpandable->Clear(); m_vTree->Items->PlusMinusImageExpanded->Clear(); } } void CBookTableDlg::OnCheckUsePlainClicked() { if (m_CheckUsePlain.GetCheck()) m_vTree->PutButtonPictureH((OLE_HANDLE)(HBITMAP)m_Plain); else m_vTree->PutButtonPictureH(NULL); } void CBookTableDlg::SortHeader(short colIndex) { // get the new, sorted column int sortedColumn = m_vTree->Headers->SortedColumn; // Sort the data based on the sort indicator // Note that column 2 is sorted by Item.Data, which is an integer value (book size in pages) if (m_vTree->Header[sortedColumn]->SortIndicator == sortIndicatorSftTreeAscending) { if (sortedColumn == 2) m_vTree->Items->SortDependents(-1, sortedColumn, sortSftTreeAscItemData); else m_vTree->Items->SortDependents(-1, sortedColumn, sortSftTreeAscending); } else { if (sortedColumn == 2) m_vTree->Items->SortDependents(-1, sortedColumn, sortSftTreeDscItemData); else m_vTree->Items->SortDependents(-1, sortedColumn, sortSftTreeDescending); } } void CBookTableDlg::HeaderMenu(CPoint pt) { m_HeaderMenu.DestroyMenu(); m_HeaderMenu.CreatePopupMenu(); int count = 0; for (short c = 0 ; c < m_vTree->ColumnsObj->Count ; ++c) { m_HeaderMenu.AppendMenu(MF_STRING, HEADERMENU_IDS + c, m_vTree->Header[c]->Text); if (m_vTree->Column[c]->WidthPix > 0) { m_HeaderMenu.CheckMenuItem(HEADERMENU_IDS + c, MF_CHECKED|MF_BYCOMMAND); ++count; } else m_HeaderMenu.CheckMenuItem(HEADERMENU_IDS + c, MF_UNCHECKED|MF_BYCOMMAND); } if (count <= 1) { for (short c = 0 ; c < m_vTree->ColumnsObj->Count ; ++c) { if (m_HeaderMenu.GetMenuState(HEADERMENU_IDS + c, MF_CHECKED)) m_HeaderMenu.EnableMenuItem(HEADERMENU_IDS + c, MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); else m_HeaderMenu.EnableMenuItem(HEADERMENU_IDS + c, MF_ENABLED|MF_BYCOMMAND); } } m_HeaderMenu.AppendMenu(MF_SEPARATOR); m_HeaderMenu.AppendMenu(MF_STRING, HEADERMENU_SHOWALL, _T("&Show All")); if (count < m_vTree->ColumnsObj->Count) m_HeaderMenu.EnableMenuItem(HEADERMENU_SHOWALL, MF_ENABLED|MF_BYCOMMAND); else m_HeaderMenu.EnableMenuItem(HEADERMENU_SHOWALL, MF_DISABLED|MF_GRAYED|MF_BYCOMMAND); m_vTree->CancelMode(); m_HeaderMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, this); } void CBookTableDlg::ItemMenu(CPoint pt) { m_ItemMenu.DestroyMenu(); m_ItemMenu.CreatePopupMenu(); m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Edit")); m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Insert")); m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Append")); m_ItemMenu.AppendMenu(MF_STRING, ITEMMENU_ENTRY, _T("Delete")); m_vTree->CancelMode(); m_ItemMenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, this); } void CBookTableDlg::OnContextMenuSftTree1(short Button, short Shift, long x, long y) { CPoint pt(x, y); ::MapWindowPoints((HWND) m_vTree->hWnd, NULL, &pt, 1); // Determine click context menu for header or item long l, t, w, h; m_vTree->Headers->GetPositionPix(&l, &t, &w, &h); if (x >= l && x < l + w && y >= t && y <= t + h) { HeaderMenu(pt); return; } // determine item right-clicked long ItemIndex; ItemIndex = m_vTree->Items->HitTestPix(x, y); if (ItemIndex >= 0 && ItemIndex < m_vTree->Items->Count) { m_vTree->Items->Current = ItemIndex; m_vTree->Item[ItemIndex]->Selected = VARIANT_TRUE; ItemMenu(pt); return; } } void CBookTableDlg::OnItemClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) { if (AreaType == constSftTreeColumn && Button == constSftTreeLeftButton) SortHeader(ColIndex); else if (AreaType == constSftTreeExpandAll) m_vTree->Item[ItemIndex]->Expand(VARIANT_FALSE, VARIANT_TRUE); } void CBookTableDlg::OnItemDblClickSftTree1(long ItemIndex, short ColIndex, short AreaType, short Button, short Shift) { if (AreaType == constSftTreeColumnRes && Button == constSftTreeLeftButton) { m_vTree->Column[ColIndex]->MakeOptimal(); m_vTree->Items->RecalcHorizontalExtent(); } else if (AreaType == constSftTreeColumn && Button == constSftTreeLeftButton) SortHeader(ColIndex); } afx_msg void CBookTableDlg::OnMenu_ItemMenu_Entry() { AfxMessageBox(_T("This sample doesn't implement any actions for the item menu. Try the column headers instead.")); } afx_msg void CBookTableDlg::OnMenu_HeaderMenu_ShowAll() { m_vTree->ColumnsObj->MakeOptimal(); } afx_msg void CBookTableDlg::OnMenu_HeaderMenu_Entry(UINT nID) { short colIndex = (short) (nID - HEADERMENU_IDS); if (m_HeaderMenu.GetMenuState(nID, MF_CHECKED)) m_vTree->Column[colIndex]->WidthPix = 0; else m_vTree->Column[colIndex]->MakeOptimal(); m_vTree->Items->RecalcHorizontalExtent(); } BEGIN_EVENTSINK_MAP(CBookTableDlg, CDialog) //{{AFX_EVENTSINK_MAP(CBookTableDlg) ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 35 /* ContextMenu */, OnContextMenuSftTree1, VTS_I2 VTS_I2 VTS_I4 VTS_I4) ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 4 /* ItemClick */, OnItemClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2) ON_EVENT(CBookTableDlg, IDC_SFTTREE1, 5 /* ItemDblClick */, OnItemDblClickSftTree1, VTS_I4 VTS_I2 VTS_I2 VTS_I2 VTS_I2) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP()