⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 doublelistpicker.cpp

📁 一个可以管理当前窗口显示和隐藏的完整程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////////////////////////////////////////
// File:	DoubleListPicker.cpp
// Version:	2
// Created:	07-Feb-2003
//
// Author:	Paul S. Vickery
// E-mail:	paul@vickeryhome.freeserve.co.uk
//
// CStatic derived control to encapsulate two lists, and buttons, to allow 
// users to pick from one list and add to the other
//
// You are free to use or modify this code, with no restrictions, other than
// you continue to acknowledge me as the original author in this source code,
// or any code derived from it.
//
// If you use this code, or use it as a base for your own code, it would be 
// nice to hear from you simply so I know it's not been a waste of time!
//
// Copyright (c) 2002-2003 Paul S. Vickery
//
////////////////////////////////////////////////////////////////////////////
// Version History:
//
// Version 2 - 07-Feb-2003
// =======================
// Added facility to show the lists horizontally. Uses code based on code by 
// Anneke Sicherer-Roetman (drawing to a bitmap device context) and Stefan 
// Schwedt (drawing rotated text)
//
// Version 1 - 31-Jul-2002
// =======================
// Initial version
// 
////////////////////////////////////////////////////////////////////////////
// PLEASE LEAVE THIS HEADER INTACT
////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DoubleListPicker.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define CX_BTN	30
#define CY_BTN	20

#define TITLE_LABEL_GAP	3
#define EDGE_GAP_X	0
#define EDGE_GAP_Y	0
#define LABEL_LIST_GAP	0
#define LIST_BTN_GAP	5
#define BTN_BTN_GAP	10
#define BTN_BTN_GAP_SML	2

#define CY_LABEL	14

const DWORD dwStyleCommon = WS_CHILD;
const DWORD dwStyleCommonTab = dwStyleCommon | WS_TABSTOP;
const DWORD dwStyleLabel = dwStyleCommon;
const DWORD dwStyleTitle = dwStyleCommon;
const DWORD dwStyleButton = dwStyleCommonTab | BS_PUSHBUTTON;
const DWORD dwStyleList = dwStyleCommonTab | WS_BORDER | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY | WS_VSCROLL;

/////////////////////////////////////////////////////////////////////////////
// Helper functions

// recreate the list box by copying styles etc, and list items
// and applying them to a newly created control
static BOOL RecreateListBox(CListBox* pList, LPVOID lpParam = NULL)
{
	if (pList == NULL)
		return FALSE;
	if (pList->GetSafeHwnd() == NULL)
		return FALSE;

	CWnd* pParent = pList->GetParent();
	if (pParent == NULL)
		return FALSE;

	// get current attributes
	DWORD dwStyle = pList->GetStyle();
	DWORD dwStyleEx = pList->GetExStyle();
	CRect rc;
	pList->GetWindowRect(&rc);
	pParent->ScreenToClient(&rc);	// map to client co-ords
	UINT nID = pList->GetDlgCtrlID();
	CFont* pFont = pList->GetFont();
	CWnd* pWndAfter = pList->GetNextWindow(GW_HWNDPREV);

	// create the new list box and copy the old list box items 
	// into a new listbox along with each item's data, and selection state
	CListBox listNew;
	if (! listNew.CreateEx(dwStyleEx, _T("LISTBOX"), _T(""), dwStyle, rc, pParent, nID, lpParam))
	  return FALSE;
	listNew.SetFont(pFont);
	int nNumItems = pList->GetCount();
	BOOL bMultiSel = (dwStyle & LBS_MULTIPLESEL || dwStyle & LBS_EXTENDEDSEL);
	for (int n = 0; n < nNumItems; n++)
	{
		CString sText;
		pList->GetText(n, sText);
		int nNewIndex = listNew.AddString(sText);
		listNew.SetItemData(nNewIndex, pList->GetItemData(n));
		if (bMultiSel && pList->GetSel(n))
			listNew.SetSel(nNewIndex);
	}
	if (! bMultiSel)
	{
		int nCurSel = pList->GetCurSel();
		if (nCurSel != -1)
		{
			CString sSelText;
			// get the selection in the old list
			pList->GetText(nCurSel, sSelText);
			// now find and select it in the new list
			listNew.SetCurSel(listNew.FindStringExact(-1, sSelText));
		}
	}
	// destroy the existing window, then attach the new one
	pList->DestroyWindow();
	HWND hwnd = listNew.Detach();
	pList->Attach(hwnd);

	// position correctly in z-order
	pList->SetWindowPos(pWndAfter == NULL ? &CWnd::wndBottom : pWndAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CDoubleListPicker

CDoubleListPicker::CDoubleListPicker()
{
	m_bSortListLeft = TRUE;
	m_bSortListRight = TRUE;
	m_bMultiSelLeft = TRUE;
	m_bMultiSelRight = TRUE;

	m_apCtrls[0] = &m_labelTitle;
	m_apCtrls[1] = &m_labelLeft;
	m_apCtrls[2] = &m_listLeft;
	m_apCtrls[3] = &m_btnMoveRight;
	m_apCtrls[4] = &m_btnMoveAllRight;
	m_apCtrls[5] = &m_btnMoveLeft;
	m_apCtrls[6] = &m_btnMoveAllLeft;
	m_apCtrls[7] = &m_labelRight;
	m_apCtrls[8] = &m_listRight;

	m_btnMoveRight.m_pPicker = this;
	m_btnMoveAllRight.m_pPicker = this;
	m_btnMoveLeft.m_pPicker = this;
	m_btnMoveAllLeft.m_pPicker = this;
	m_listLeft.m_pPicker = this;
	m_listRight.m_pPicker = this;

	m_bHorizontal = FALSE;
}

BEGIN_MESSAGE_MAP(CDoubleListPicker, CStatic)
	//{{AFX_MSG_MAP(CDoubleListPicker)
	ON_WM_CREATE()
	ON_WM_SETFOCUS()
	ON_WM_ENABLE()
	ON_WM_SHOWWINDOW()
	ON_WM_WINDOWPOSCHANGED()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CDoubleListPicker::CButtonDLP, CButton)
	ON_CONTROL_REFLECT_EX(BN_CLICKED, CDoubleListPicker::CButtonDLP::OnClick)
END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP(CDoubleListPicker::CListBoxDLP, CListBox)
	ON_CONTROL_REFLECT_EX(LBN_DBLCLK, CDoubleListPicker::CListBoxDLP::OnDblClk)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDoubleListPicker message handlers

BOOL CDoubleListPicker::Create(LPCTSTR lpszTitle, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	m_sTitle = lpszTitle;
	dwStyle |= WS_CHILD;
	return CStatic::Create("", dwStyle, rect, pParentWnd, nID);
}

BOOL CDoubleListPicker::CreateList(BOOL bLeft, CWnd* pParent)
{
	CRect rc(0, 0, 0, 0);
	CListBox& list = GetListCtrl(bLeft);
	int nID = ID_LIST_LEFT;
	BOOL bSort = m_bSortListLeft;
	BOOL bMulti = m_bMultiSelLeft;
	if (! bLeft)
	{
		nID = ID_LIST_RIGHT;
		bSort = m_bSortListRight;
		bMulti = m_bMultiSelRight;
	}
	DWORD dwStyle = dwStyleList | (bSort ? LBS_SORT : 0) | (bMulti ? LBS_EXTENDEDSEL : 0);
	dwStyle |= (GetStyle() & WS_VISIBLE);
	if (! list.Create(dwStyle, rc, pParent, nID))
		return FALSE;
	list.ModifyStyleEx(0, WS_EX_CLIENTEDGE);
	return TRUE;
}

static void SetZOrder(CWnd* pCtrl, const CWnd* pWndAfter)
{
	if (pCtrl != NULL && pWndAfter != NULL)
		pCtrl->SetWindowPos(pWndAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

void CDoubleListPicker::SetHorizontal(BOOL bHorizontal/*=TRUE*/)
{
	if (::IsWindow(m_hWnd) && ! bHorizontal != ! m_bHorizontal)
	{
		m_bHorizontal = bHorizontal;
		if (bHorizontal)
		{
			SetRotatedButtonText(m_btnMoveRight);
			SetRotatedButtonText(m_btnMoveAllRight);
			SetRotatedButtonText(m_btnMoveLeft);
			SetRotatedButtonText(m_btnMoveAllLeft);
		}
		else
		{
			m_btnMoveRight.SetBitmap(NULL);
			m_btnMoveAllRight.SetBitmap(NULL);
			m_btnMoveLeft.SetBitmap(NULL);
			m_btnMoveAllLeft.SetBitmap(NULL);
			m_btnMoveRight.ModifyStyle(BS_BITMAP, 0);
			m_btnMoveAllRight.ModifyStyle(BS_BITMAP, 0);
			m_btnMoveLeft.ModifyStyle(BS_BITMAP, 0);
			m_btnMoveAllLeft.ModifyStyle(BS_BITMAP, 0);
		}
		DoSizing();
	}
	m_bHorizontal = bHorizontal;
}

void CDoubleListPicker::SetRotatedButtonText(CButton& btn, LPCTSTR lpszText/*=NULL*/, int nAngle/*=270*/)
{
	CString sText(lpszText);
	if (sText.IsEmpty())
		btn.GetWindowText(sText);
	btn.ModifyStyle(0, BS_BITMAP);

	// code for drawing to a bitmap device context from code by Anneke Sicherer-Roetman
	// (see http://www.codeproject.com/bitmap/bitmapdc.asp)
	CDC dc;
	CWindowDC dcWin(NULL);
	CBitmap bmp;
	VERIFY(bmp.CreateCompatibleBitmap(&dcWin, CX_BTN, CY_BTN)); 
	VERIFY(dc.CreateCompatibleDC(&dcWin));
	int nSavedDC = dc.SaveDC();
	dc.SelectObject(&bmp);
	dc.SetMapMode(dcWin.GetMapMode());
	dc.FillSolidRect(0, 0, CX_BTN, CY_BTN, GetSysColor(COLOR_BTNFACE));

	// code to draw rotated text from code by Stefan Schwedt
	// (see http://www.codeproject.com/gdi/textrotation.asp)
	// get the centre of the rotated text
	// (only works for true-type fonts, or angles not divisible by 90)
	LOGFONT lf;
	CFont font;
	font.CreateStockObject(DEFAULT_GUI_FONT);
	font.GetLogFont(&lf);
	// can't use MS Sans Serif, so use a true-type font
	// that is likely to be found on all platforms, and 
	// that looks OK. (On 2K/XP the default should be OK.)
	if (stricmp(lf.lfFaceName, "MS Sans Serif") == 0)
	  strcpy(lf.lfFaceName, "Tahoma");
	font.DeleteObject();
	lf.lfEscapement = lf.lfOrientation = 2700;		// = 90 degrees clockwise
	VERIFY(font.CreateFontIndirect(&lf));
	dc.SelectObject(&font);
	CRect rcText(0, 0, CX_BTN, CY_BTN);
	CSize TextSize = dc.GetTextExtent(sText);
	CPoint rcenter;
	rcenter.x = TextSize.cy / 2;
	rcenter.y = -(TextSize.cx / 2);
	// draw the text and move it to the centre of the rectangle
	dc.SetTextAlign(TA_BOTTOM);
	dc.SetBkMode(TRANSPARENT);
	dc.ExtTextOut(rcText.left + rcText.Width() / 2 - rcenter.x, 
		      rcText.top + rcText.Height() / 2 + rcenter.y,
		      0, rcText, sText, NULL);

	dc.RestoreDC(nSavedDC);

	// now associate the bitmap with the button
	btn.SetBitmap((HBITMAP)bmp.Detach());
}

BOOL CDoubleListPicker::CreateChildControls()
{
	if (m_labelTitle.GetSafeHwnd() != NULL)
		return TRUE;  // already created controls

	CWnd* pParent = GetParent();
	if (pParent == NULL)
		return FALSE;

	// create child controls
	CRect rc(0, 0, 0, 0);
	if (! m_labelTitle.Create(m_sTitle, dwStyleTitle, rc, pParent, ID_TITLE) || 
	    ! m_labelLeft.Create(m_sLabelLeft, dwStyleLabel, rc, pParent, ID_LABEL_LEFT) || 
	    ! CreateList(TRUE, pParent) || 
	    ! m_btnMoveRight.Create(">", dwStyleButton, rc, pParent, ID_BTN_MOVE_RIGHT) || 
	    ! m_btnMoveAllRight.Create(">>", dwStyleButton, rc, pParent, ID_BTN_MOVE_ALL_RIGHT) || 
	    ! m_btnMoveLeft.Create("<", dwStyleButton, rc, pParent, ID_BTN_MOVE_LEFT) || 
	    ! m_btnMoveAllLeft.Create("<<", dwStyleButton, rc, pParent, ID_BTN_MOVE_ALL_LEFT) || 
	    ! m_labelRight.Create(m_sLabelRight, dwStyleLabel, rc, pParent, ID_LABEL_RIGHT) || 
	    ! CreateList(FALSE, pParent))
		return FALSE;

	CFont* pFont = GetFont();
	BOOL bEnable = IsWindowEnabled();
	BOOL bShow = (GetStyle() & WS_VISIBLE);

	// set font, z-order, visibility, and enabled state
	for (int n = 0; n < NUM_CTRLS; n++)
	{
		m_apCtrls[n]->SetFont(pFont);
		SetZOrder(m_apCtrls[n], n == 0 ? this : m_apCtrls[n - 1]);
		m_apCtrls[n]->EnableWindow(bEnable);
		m_apCtrls[n]->ShowWindow(bShow ? SW_SHOW : SW_HIDE);
	}

	BOOL bHorizontal = m_bHorizontal;
	m_bHorizontal = FALSE;
	SetHorizontal(bHorizontal);

	return TRUE;
}

int CDoubleListPicker::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CStatic::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (! CreateChildControls())
		return -1;
  
	return 0;
}

void CDoubleListPicker::DoSizing()
{
	// put child controls in the correct places
	if (m_labelTitle.GetSafeHwnd() == NULL)
		return; // controls not yet created

	if (GetParent() == NULL)
		return;

	CRect rc;
	GetWindowRect(&rc);
	GetParent()->ScreenToClient(&rc);

	int nTitleLabelGap = 0;
	if (! m_sTitle.IsEmpty())
	{
		// title extends full width, bar the offsets
		m_labelTitle.ShowWindow(GetStyle() & WS_VISIBLE ? SW_SHOW : SW_HIDE);
		int nTitleWidth = rc.Width() - (EDGE_GAP_X * 2);
		CRect rcTitle(0, 0, nTitleWidth, rc.Height());
		CDC* pDC = m_labelTitle.GetDC();
		ASSERT(pDC);
		CFont* pOldFont = (CFont*)pDC->SelectObject(m_labelTitle.GetFont());
		int nTitleHeight = pDC->DrawText(m_sTitle, &rcTitle, 
			      DT_CALCRECT | DT_EXTERNALLEADING | DT_WORDBREAK | DT_LEFT | DT_NOPREFIX);
		pDC->SelectObject(pOldFont);
		m_labelTitle.MoveWindow(rc.left + EDGE_GAP_X, rc.top + EDGE_GAP_Y, nTitleWidth, nTitleHeight);
		m_labelTitle.SetWindowText(m_sTitle);
		rc.top += nTitleHeight + EDGE_GAP_Y;
		nTitleLabelGap = TITLE_LABEL_GAP;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -