📄 gridctrl.cpp
字号:
// GridCtrl.cpp : implementation file
//
// MFC Grid Control v2.26
//
// Written by Chris Maunder <chris@codeproject.com>
// Copyright (c) 1998-2005. All Rights Reserved.
/
// The code contained in this file was based on the original
// WorldCom Grid control written by Joe Willcoxson,
// mailto:chinajoe@aol.com
// http://users.aol.com/chinajoe
// (These addresses may be out of date) The code has gone through
// so many modifications that I'm not sure if there is even a single
// original line of code. In any case Joe's code was a great
// framework on which to build.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact.
//
// An email letting me know how you are using it would be nice as well.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// Expect bugs!
//
// Please use and enjoy, and let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into
// this file.
//
// History:
// --------
// This control is constantly evolving, sometimes due to new features that I
// feel are necessary, and sometimes due to existing bugs. Where possible I
// have credited the changes to those who contributed code corrections or
// enhancements (names in brackets) or code suggestions (suggested by...)
//
// 1.0 - 1.13 20 Feb 1998 - 6 May 1999
// First release version. Progressed from being a basic
// grid based on the original WorldCom Grid control
// written by Joe Willcoxson (mailto:chinajoe@aol.com,
// http://users.aol.com/chinajoe) to something a little
// more feature rich. Rewritten so many times I doubt
// there is a single line of Joe's code left. Many, many,
// MANY people sent in bug reports and fixes. Thank you
// all.
//
// 2.0 1 Feb 2000
// Rewritten to make the grid more object oriented, in
// that the CGridCell class now takes care of cell-specific
// tasks. This makes the code more robust, but more
// importantly it allows the simple insertion of other
// types of cells.
//
// 2.10 11 Mar 2000 - Ken Bertelson and Chris Maunder
// - Additions for virtual CGridCell support of embedded tree
// & cell buttons implementation
// - Optional WYSIWYG printing
// - Awareness of hidden (0 width/height) rows and columns for
// key movements, cut, copy, paste, and autosizing
// - CGridCell can make title tips display any text rather than
// cell text only
// - Minor vis bug fixes
// - CGridCtrl now works with CGridCellBase instead of CGridCell
// This is a taste of things to come.
//
// 2.20 30 Jul 2000 - Chris Maunder
// - Font storage optimised (suggested by Martin Richter)
// - AutoSizeColumn works on either column header, data or both
// - EnsureVisible. The saga continues... (Ken)
// - Rewrote exception handling
// - Added TrackFocusCell and FrameFocusCell properties, as well as
// ExpandLastColumn (suggested by Bruce E. Stemplewski).
// - InsertColumn now allows you to insert columns at the end of the
// column range (David Weibel)
// - Shift-cell-selection more intuitive
// - API change: Set/GetGridColor now Set/GetGridLineColor
// - API change: Set/GetBkColor now Set/GetGridBkColor
// - API change: Set/GetTextColor, Set/GetTextBkColor depricated
// - API change: Set/GetFixedTextColor, Set/GetFixedBkColor depricated
// - Stupid DDX_GridControl workaround removed.
// - Added "virtual mode" via Set/GetVirtualMode
// - Added SetCallbackFunc to allow callback functions in virtual mode
// - Added Set/GetAutoSizeStyle
// - AutoSize() bug fixed
// - added GVIS_FIXEDROW, GVIS_FIXEDCOL states
// - added Get/SetFixed[Row|Column]Selection
// - cell "Get" methods now const'd. Sorry folks...
// - GetMouseScrollLines now uses win98/W2K friendly code
// - WS_EX_CLIENTEDGE style now implicit
//
// [ Only the latest version and major version changes will be shown ]
////
// 2.25 13 Mar 2004 - Chris Maunder
// - Minor changes so it will compile in VS.NET (inc. Whidbey)
// - Fixed minor bug in EnsureVisible - Junlin Xu
// - Changed AfxGetInstanceHandle for AfxGetResourceHandle in RegisterWindowClass
// - Various changes thanks to Yogurt
//
// 2.26 13 Dec 2005 - Pierre Couderc
// - Added sort in Virtual mode
// - Change row/column order programatically or via drag and drop
// - Added save/restore layer (for undoing row/column order changes)
//
// TODO: 1) Implement sparse grids (super easy now)
// 2) Fix it so that as you drag select, the speed of selection increases
// with time.
// 3) Scrolling is still a little dodgy (too much grey area). I know there
// is a simple fix but it's been a low priority
//
// ISSUES: 1) WindowFromPoint seems to do weird things in W2K. Causing problems for
// the rigt-click-on-titletip code.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MemDC.h"
#include "GridCtrl.h"
#include <algorithm>
// OLE stuff for clipboard operations
#include <afxadv.h> // For CSharedFile
#include <afxconv.h> // For LPTSTR -> LPSTR macros
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Spit out some messages as a sanity check for programmers
#ifdef GRIDCONTROL_NO_TITLETIPS
#pragma message(" -- CGridCtrl: No titletips for cells with large data")
#endif
#ifdef GRIDCONTROL_NO_DRAGDROP
#pragma message(" -- CGridCtrl: No OLE drag and drop")
#endif
#ifdef GRIDCONTROL_NO_CLIPBOARD
#pragma message(" -- CGridCtrl: No clipboard support")
#endif
#ifdef GRIDCONTROL_NO_PRINTING
#pragma message(" -- CGridCtrl: No printing support")
#endif
IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
// Get the number of lines to scroll with each mouse wheel notch
// Why doesn't windows give us this function???
UINT GetMouseScrollLines()
{
int nScrollLines = 3; // reasonable default
#ifndef _WIN32_WCE
// Do things the hard way in win95
OSVERSIONINFO VersionInfo;
VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&VersionInfo) ||
(VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && VersionInfo.dwMinorVersion == 0))
{
HKEY hKey;
if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
TCHAR szData[128];
DWORD dwKeyDataType;
DWORD dwDataBufSize = sizeof(szData);
if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
(LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
{
nScrollLines = _tcstoul(szData, NULL, 10);
}
RegCloseKey(hKey);
}
}
// win98 or greater
else
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
#endif
return nScrollLines;
}
/////////////////////////////////////////////////////////////////////////////
// CGridCtrl
CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
{
RegisterWindowClass();
#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm && !AfxOleInit())
AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
#endif
// Store the system colours in case they change. The gridctrl uses
// these colours, and in OnSysColorChange we can check to see if
// the gridctrl colours have been changed from the system colours.
// If they have, then leave them, otherwise change them to reflect
// the new system colours.
m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
m_crGridLineColour = RGB(192,192,192);
m_nRows = 0;
m_nCols = 0;
m_nFixedRows = 0;
m_nFixedCols = 0;
m_InDestructor = false;
m_bVirtualMode = FALSE;
m_pfnCallback = NULL;
m_nVScrollMax = 0; // Scroll position
m_nHScrollMax = 0;
m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
// per mouse wheel notch to scroll
m_nBarState = GVL_NONE;
m_MouseMode = MOUSE_NOTHING;
m_nGridLines = GVL_BOTH;
m_bEditable = TRUE;
m_bListMode = FALSE;
m_bSingleRowSelection = FALSE;
m_bSingleColSelection = FALSE;
m_bLMouseButtonDown = FALSE;
m_bRMouseButtonDown = FALSE;
m_bAllowDraw = TRUE; // allow draw updates
m_bEnableSelection = TRUE;
m_bFixedColumnSelection = TRUE;
m_bFixedRowSelection = TRUE;
m_bAllowRowResize = TRUE;
m_bAllowColumnResize = TRUE;
m_bSortOnClick = FALSE; // Sort on header row click
m_bHandleTabKey = TRUE;
#ifdef _WIN32_WCE
m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
#else
m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
#endif
m_bTitleTips = TRUE; // show cell title tips
m_bWysiwygPrinting = FALSE; // use size-to-width printing
m_bHiddenColUnhide = TRUE; // 0-width columns can be expanded via mouse
m_bHiddenRowUnhide = TRUE; // 0-Height rows can be expanded via mouse
m_bAllowColHide = TRUE; // Columns can be contracted to 0-width via mouse
m_bAllowRowHide = TRUE; // Rows can be contracted to 0-height via mouse
m_bAscending = TRUE; // sorting stuff
m_nSortColumn = -1;
m_pfnCompare = NULL;
m_pfnVirtualCompare = NULL;
m_nAutoSizeColumnStyle = GVS_BOTH; // Autosize grid using header and data info
m_nTimerID = 0; // For drag-selection
m_nTimerInterval = 25; // (in milliseconds)
m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
// within +/-3 pixels of the dividing line for
// resizing to be possible
m_pImageList = NULL; // Images in the grid
m_bAllowDragAndDrop = FALSE; // for drag and drop - EFW - off by default
m_bTrackFocusCell = TRUE; // Track Focus cell?
m_bFrameFocus = TRUE; // Frame the selected cell?
m_AllowReorderColumn = false;
m_QuitFocusOnTab = false;
m_AllowSelectRowInFixedCol = false;
m_bDragRowMode = TRUE; // allow to drop a line over another one to change row order
m_pRtcDefault = RUNTIME_CLASS(CGridCell);
SetupDefaultCells();
SetGridBkColor(m_crShadow);
// Set up the initial grid size
SetRowCount(nRows);
SetColumnCount(nCols);
SetFixedRowCount(nFixedRows);
SetFixedColumnCount(nFixedCols);
SetTitleTipTextClr(CLR_DEFAULT); //FNA
SetTitleTipBackClr(CLR_DEFAULT);
// set initial selection range (ie. none)
m_SelectedCellMap.RemoveAll();
m_PrevSelectedCellMap.RemoveAll();
#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
// EFW - Added to support shaded/unshaded printout and
// user-definable margins.
m_bShadedPrintOut = TRUE;
SetPrintMarginInfo(2, 2, 4, 4, 1, 1, 1);
#endif
}
CGridCtrl::~CGridCtrl()
{
m_InDestructor = true;
DeleteAllItems();
#ifndef GRIDCONTROL_NO_TITLETIPS
if (m_bTitleTips && ::IsWindow(m_TitleTip.GetSafeHwnd()))
m_TitleTip.DestroyWindow();
#endif
DestroyWindow();
#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
// BUG FIX - EFW
COleDataSource *pSource = COleDataSource::GetClipboardOwner();
if(pSource)
COleDataSource::FlushClipboard();
#endif
}
// Register the window class if it has not already been registered.
BOOL CGridCtrl::RegisterWindowClass()
{
WNDCLASS wndcls;
//HINSTANCE hInst = AfxGetInstanceHandle();
HINSTANCE hInst = AfxGetResourceHandle();
if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
#ifndef _WIN32_WCE_NO_CURSOR
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
#else
wndcls.hCursor = 0;
#endif
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
BOOL CGridCtrl::Initialise()
{
// Stop re-entry problems
static BOOL bInProcedure = FALSE;
if (bInProcedure)
return FALSE;
bInProcedure = TRUE;
#ifndef GRIDCONTROL_NO_TITLETIPS
m_TitleTip.SetParentWnd(this);
#endif
// This would be a good place to register the droptarget but
// unfortunately this causes problems if you are using the
// grid in a view.
// Moved from OnSize.
//#ifndef GRIDCONTROL_NO_DRAGDROP
// m_DropTarget.Register(this);
//#endif
if (::IsWindow(m_hWnd))
ModifyStyleEx(0, WS_EX_CLIENTEDGE);
// Kludge: Make sure the client edge shows
// This is so horrible it makes my eyes water.
CRect rect;
GetWindowRect(rect);
CWnd* pParent = GetParent();
if (pParent != NULL)
pParent->ScreenToClient(rect);
rect.InflateRect(1,1); MoveWindow(rect);
rect.DeflateRect(1,1); MoveWindow(rect);
bInProcedure = FALSE;
return TRUE;
}
// creates the control - use like any other window create control
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -