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