Re: Is there any method to make the scrollbar work exactly?
hi,all
Oh, i just want to know how to and a scroolbar to the CCtrlListWnd.
my ability is poor. so i want to learn. your suggestion is very useful.
/********************************************************************************************/
// Author: sound_of_nature
// Email: sound_of_nature@hotmail.com
// Verion: 1.0
// Date: 5/12/2008
/********************************************************************************************/
// CtrlListWnd.h : header file
//
#pragma once
#define CUSTOM_ITEMCHANGED 1
#define MIN_HEIGHT 18
enum ItemCtrlType{EditCTL,PICCTL,ListCTL,LinkCtl};
///////////////////////////////////////////////////////////////////////////////////////
//ITEMINFOR
////
class ITEMINFOR
{
public:
ItemCtrlType m_ctlType;
unsigned int m_nPos;
int m_nHeight;
DWORD m_nStyle;
public:
ITEMINFOR& operator=(ITEMINFOR itemInfo)
{
m_ctlType = itemInfo.m_ctlType;
m_nHeight = itemInfo.m_nHeight;
m_nPos = itemInfo.m_nPos;
m_nStyle = itemInfo.m_nStyle;
return (*this);
};
};
///////////////////////////////////////////////////////////////////////////////////////
//ITEM
////
class ITEM
{
friend class CCtrlListWnd;
public:
ITEM()
{
m_ctlType = EditCTL;
m_nPos = 0;
m_nHeight = MIN_HEIGHT;
m_pControl = NULL;
};
~ITEM()
{
delete m_pControl;
m_pControl = NULL;
};
private:
ItemCtrlType m_ctlType;
unsigned int m_nPos;
int m_nHeight;
CWnd *m_pControl;
};
//////////////////////////////////////////////////////////////////////////////////////
// CExtensibleEdit
////
class CExtensibleEdit : public CEdit
{
friend class CCtrlListWnd;
DECLARE_DYNAMIC(CExtensibleEdit)
protected:
CExtensibleEdit();
virtual ~CExtensibleEdit();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnEnUpdate();
virtual void PreSubclassWindow();
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID);
private:
ITEMINFOR m_ItemInfo;
};
////////////////////////////////////////////////////////////////////////////////////////
// CCtrlListWnd
////
class CCtrlListWnd : public CWnd
{
DECLARE_DYNAMIC(CCtrlListWnd)
public:
CCtrlListWnd();
virtual ~CCtrlListWnd();
protected:
DECLARE_MESSAGE_MAP()
ITEM *CreateControl(ITEMINFOR* lpItemInfo);
void RepositionItems(ITEMINFOR *pItemInfor);
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM
lParam);
public:
BOOL InsertItem(ITEMINFOR* lpItemInfo);
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID, CCreateContext* pContext = NULL);
virtual BOOL CreateEx(DWORD dwExStyle, DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL);
//afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar);
afx_msg void OnSize(UINT nType, int cx, int cy);
private:
CMap <unsigned int,unsigned int ,ITEM* ,ITEM* > m_mapItem;
CString m_classname;
};
/********************************************************************************************/
// Author: sound_of_nature
// Email: sound_of_nature@hotmail.com
// Verion: 1.0
// Date: 5/12/2008
/********************************************************************************************/
// CtrlListWnd.cpp : implementation file
//
#include "stdafx.h"
#include "CtrlListWnd.h"
/////////////////////////////////////////////////////////////////////////////////////////////
// CExtensibleEdit
////
IMPLEMENT_DYNAMIC(CExtensibleEdit, CEdit)
CExtensibleEdit::CExtensibleEdit()
{
}
CExtensibleEdit::~CExtensibleEdit()
{
}
BEGIN_MESSAGE_MAP(CExtensibleEdit, CEdit)
ON_CONTROL_REFLECT(EN_UPDATE, &CExtensibleEdit::OnEnUpdate)
END_MESSAGE_MAP()
// CExtensibleEdit message handlers
BOOL CExtensibleEdit::Create(DWORD dwStyle, const RECT& rect, CWnd*
pParentWnd, UINT nID)
{
// TODO: Add your specialized code here and/or call the base class
dwStyle&=~ES_AUTOHSCROLL;
dwStyle|=WS_VISIBLE|WS_CHILD|WS_BORDER;
return CEdit::Create(dwStyle, rect, pParentWnd, nID);
}
void CExtensibleEdit::OnEnUpdate()
{
CClientDC dc(this);
//get the size of the text
CFont *pOldFont = dc.SelectObject(GetFont());
CString Str;
GetWindowText(Str);
CSize sizeText = dc.GetTextExtent(Str);
long TextHeight = sizeText.cy;
dc.SelectObject(pOldFont);
//get the inside size of the edit
CRect Rect;
GetRect(&Rect);
//get the external size of the edit
CRect wRect;
GetWindowRect(&wRect);
sizeText.cy *= GetLineCount();
CRect rcParentClient;
GetParent()->GetClientRect(rcParentClient);
Rect.bottom = Rect.top+sizeText.cy+MIN_HEIGHT;
Rect.right = Rect.left+rcParentClient.Width();
CalcWindowRect(&Rect);
m_ItemInfo.m_nHeight = Rect.Height();
TRACE("OldHeight=%d,NewHeight=%d\n",wRect.Height(), Rect.Height());
if(wRect.Height() != Rect.Height())
{
NMHDR nmh;
nmh.code = CUSTOM_ITEMCHANGED; // Message type defined by
control.
nmh.idFrom = GetDlgCtrlID();
nmh.hwndFrom = m_hWnd;
GetParent()->SendMessage(WM_NOTIFY,(WPARAM)(&m_ItemInfo),(LPARAM)(&nmh));
}
}
void CExtensibleEdit::PreSubclassWindow()
{
ASSERT( (GetStyle() & ES_AUTOHSCROLL) == 0);
CEdit::PreSubclassWindow();
}
//////////////////////////////////////////////////////////////////////////////////////
// CCtrlListWnd
////
IMPLEMENT_DYNAMIC(CCtrlListWnd, CWnd)
CCtrlListWnd::CCtrlListWnd()
{
}
CCtrlListWnd::~CCtrlListWnd()
{
POSITION pos = m_mapItem.GetStartPosition();
unsigned int nkey;
ITEM* pItem = NULL;
while (pos != NULL)
{
m_mapItem.GetNextAssoc(pos, nkey, pItem);
delete pItem;
pItem = NULL;
}
}
BEGIN_MESSAGE_MAP(CCtrlListWnd, CWnd)
//ON_WM_VSCROLL()
ON_WM_SIZE()
END_MESSAGE_MAP()
// CCtrlListWnd message handlers
ITEM *CCtrlListWnd::CreateControl(ITEMINFOR* lpItemInfo)
{
if (lpItemInfo==NULL)return NULL;
ITEM *lpItem = new ITEM;
if (lpItem == NULL)return NULL;
switch (lpItemInfo->m_ctlType)
{
case EditCTL:
{
CExtensibleEdit *pCtl = new CExtensibleEdit;
if (pCtl!=NULL)
{
CRect rcClient;
GetClientRect(rcClient);
if
(!pCtl->Create(lpItemInfo->m_nStyle,CRect(0,0,0,0),this,lpItemInfo->m_nPos))
{
delete lpItem;
lpItem = NULL;
delete pCtl;
pCtl = NULL;
}else
{
lpItemInfo->m_nHeight =
(lpItemInfo->m_nHeight>MIN_HEIGHT)?lpItemInfo->m_nHeight:MIN_HEIGHT;
pCtl->m_ItemInfo = (*lpItemInfo);
lpItem->m_ctlType = EditCTL;
lpItem->m_nHeight = lpItemInfo->m_nHeight;
lpItem->m_nPos = lpItemInfo->m_nPos;
lpItem->m_pControl = pCtl;
return lpItem;
}
}
}
break;
case PICCTL: break;
case ListCTL: break;
case LinkCtl: break;
}
return NULL;
}
BOOL CCtrlListWnd::InsertItem(ITEMINFOR* lpItemInfo)
{
ITEM *lpItem = CreateControl(lpItemInfo);
if(lpItem==NULL)return FALSE;
ITEM *tpItem = NULL;
unsigned int ipos = lpItem->m_nPos;
unsigned int size = m_mapItem.GetSize();
if(ipos==-1)
{
lpItemInfo->m_nPos = size;
lpItem->m_nPos = size;
m_mapItem[size]=lpItem;
RepositionItems(lpItemInfo);
return TRUE;
}
m_mapItem.Lookup(ipos,tpItem);
if(tpItem==NULL)
{
m_mapItem[ipos]=lpItem;
}else
{
for(unsigned int ct = size;ct>ipos;ct--)
{
m_mapItem.Lookup(ct-1,tpItem);
m_mapItem[ct]=tpItem;
}
m_mapItem[ipos]=lpItem;
}
RepositionItems(lpItemInfo);
return TRUE;
}
void CCtrlListWnd::RepositionItems(ITEMINFOR *pItemInfor)
{
unsigned int size = m_mapItem.GetSize();
if (size<=0)return ;
CRect rcClient,rcReDraw;
GetClientRect(rcClient);
rcReDraw = rcClient;
unsigned int nWndWidth = rcClient.Width();
unsigned int nWndHeight = 1;
int nWndPos = 1;
/*int ncurrPos = GetScrollPos(SB_VERT);
nWndPos-=ncurrPos;*/
for(unsigned int ct =0;ct<size;ct++)
{
ITEM *tpItem = NULL;
m_mapItem.Lookup(ct,tpItem);
ENSURE(tpItem!=NULL);
ENSURE(tpItem->m_pControl!=NULL);
if (ct<pItemInfor->m_nPos)
{
nWndHeight+=tpItem->m_nHeight+1;
nWndPos+=tpItem->m_nHeight+1;
}else if (ct==pItemInfor->m_nPos)
{
tpItem->m_nHeight = pItemInfor->m_nHeight;
tpItem->m_pControl->SetWindowPos(this,-2,nWndPos,nWndWidth+4,pItemInfor->m_nHeight,SWP_SHOWWINDOW|SWP_NOZORDER);
rcReDraw.top = nWndPos;
nWndHeight+=pItemInfor->m_nHeight+1;
nWndPos+=tpItem->m_nHeight+1;
}else
{
tpItem->m_pControl->SetWindowPos(this,-2,nWndPos,nWndWidth+4,tpItem->m_nHeight,SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOZORDER);
nWndHeight+=tpItem->m_nHeight+1;
nWndPos+=tpItem->m_nHeight+1;
}
}
/*SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_PAGE | SIF_TRACKPOS |SIF_RANGE;
info.nMin = 0;
info.nMax = nWndHeight;
info.nPage = rcClient.Height();
info.nTrackPos = 2;
SetScrollInfo(SB_VERT,&info);*/
ShowWindow(SW_SHOW);
InvalidateRect(&rcReDraw);
UpdateWindow();
}
BOOL CCtrlListWnd::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
if (m_classname.IsEmpty())
{
// Register your unique class name that you wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL
defaults
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
//you can specify your own window procedure
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hIcon = LoadIcon(wndcls.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
wndcls.hCursor = LoadCursor(wndcls.hInstance,
MAKEINTRESOURCE(IDC_ARROW));
wndcls.hbrBackground = (HBRUSH)(::GetStockObject(WHITE_BRUSH));
wndcls.lpszMenuName = NULL;
// Specify your own class name for using FindWindow later
wndcls.lpszClassName = _T("CtrlListWnd");
m_classname = _T("CtrlListWnd");
// Register the new class and trace if it fails
if(!AfxRegisterClass(&wndcls))
{
TRACE("Class Registration Failed\n");
return FALSE;
}
}
return CWnd::Create(m_classname , NULL, dwStyle, rect, pParentWnd, nID,
pContext);
}
BOOL CCtrlListWnd::CreateEx(DWORD dwExStyle,DWORD dwStyle, const RECT& rect,
CWnd* pParentWnd, UINT nID, LPVOID lpParam)
{
// TODO: Add your specialized code here and/or call the base class
if (m_classname.IsEmpty())
{
// Register your unique class name that you wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL
defaults
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
//you can specify your own window procedure
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hIcon = LoadIcon(wndcls.hInstance,
MAKEINTRESOURCE(IDI_APPLICATION));
wndcls.hCursor = LoadCursor(wndcls.hInstance,
MAKEINTRESOURCE(IDC_ARROW));
wndcls.hbrBackground = (HBRUSH)(::GetStockObject(WHITE_BRUSH));
wndcls.lpszMenuName = NULL;
// Specify your own class name for using FindWindow later
wndcls.lpszClassName = _T("CtrlListWnd");
m_classname = _T("CtrlListWnd");
// Register the new class and trace if it fails
if(!AfxRegisterClass(&wndcls))
{
TRACE("Class Registration Failed\n");
return FALSE;
}
}
return CWnd::CreateEx(dwExStyle, _T("CtrlListWnd") , NULL, dwStyle,
rect, pParentWnd, nID, lpParam);
}
void CCtrlListWnd::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
/*SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_PAGE | SIF_TRACKPOS;
info.nPage = cy;
info.nTrackPos = 2;
SetScrollInfo(SB_VERT,&info);*/
}
LRESULT CCtrlListWnd::DefWindowProc(UINT message, WPARAM wParam, LPARAM
lParam)
{
// TODO: Add your specialized code here and/or call the base class
switch (message)
{
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case CUSTOM_ITEMCHANGED:
if (((ITEMINFOR*)wParam)->m_nHeight <=0)
return FALSE;
else
RepositionItems((ITEMINFOR*)wParam);
break;
}
break;
}
return CWnd::DefWindowProc(message, wParam, lParam);
}
/*void CCtrlListWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar)
{
// TODO: Add your message handler code here and/or call default
int minpos;
int maxpos;
GetScrollRange(SB_VERT, &minpos, &maxpos);
maxpos = GetScrollLimit(SB_VERT);
// Get the current position of scroll box.
int curpos = GetScrollPos(SB_VERT);
int oldPos = curpos;
// Determine the new position of scroll box.
switch (nSBCode)
{
case SB_TOP: // Scroll to far left.
curpos = minpos;
break;
case SB_BOTTOM: // Scroll to far right.
curpos = maxpos;
break;
case SB_ENDSCROLL: // End scroll.
break;
case SB_LINEUP: // Scroll left.
if (curpos > minpos)
curpos--;
break;
case SB_LINEDOWN: // Scroll right.
if (curpos < maxpos)
curpos++;
break;
case SB_PAGEUP: // Scroll one page left.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_VERT, &info, SIF_ALL);
if (curpos > minpos)
curpos = max(minpos, curpos - (int) info.nPage);
}
break;
case SB_PAGEDOWN: // Scroll one page right.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_VERT, &info, SIF_ALL);
if (curpos < maxpos)
curpos = min(maxpos, curpos + (int) info.nPage);
}
break;
case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position
curpos = nPos; // of the scroll box at the end of the drag operation.
break;
case SB_THUMBTRACK: // Drag scroll box to specified position. nPos is the
curpos = nPos; // position that the scroll box has been dragged to.
break;
}
// Set the new position of the thumb (scroll box).
ScrollWindow(0,oldPos-curpos,NULL,NULL);
UpdateWindow();
SetScrollPos(SB_VERT, curpos);
CWnd::OnVScroll(nSBCode, curpos, pScrollBar);
}