📄 gridctrl.cpp
字号:
// GridCtrl.cpp : implementation file
//
// MFC Grid Control
//
// Written by Chris Maunder
// mailto:chrismaunder@codeguru.com
//
// Copyright (c) 1998-1999.
//
// The code contained in this file is based on the original
// WorldCom Grid control written by Joe Willcoxson,
// mailto:chinajoe@aol.com
// http://users.aol.com/chinajoe
// 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 framewaork 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. If the source code in this file is used in
// any commercial application then a statement along the lines of
// "Portions copyright (c) Chris Maunder, 1998" must be included in
// the startup banner, "About" box or printed documentation. An email
// letting me know that you are using it would be nice as well. That's
// not much to ask considering the amount of work that went into this.
//
// 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 20 Feb 1998 First release version.
// 1.01 24 Feb 1998 Memory leak fix (Jens Bohlmann)
// Fixec typo (my fault!) in CMemDC.h - Claus Arend-Schneider)
// Bug in GetSelectedCount (Lyn Newton)
// 1.02 4 Mar 1998 Scrolling a little neater (less dead area)
// Cell selection via OnTimer correctly updates Focus cell (Suggested by Lyn Newton)
// 1.03 17 Mar 1998 Clipboard functions added, Intellimouse support
// Using 32 bit scroll pos functions instead of 16 bit ("cronos")
// Added OLE drag and drop.
// 1.04 6 Apr 1998 Added Ctrl-A = Select All, fixed CGridDropTarget
// problem, minor bug in CopyTextFromGrid (assert on
// empty string). Cleaned up reponse to m_bEditable
// (OnDrop and Ctrl-X disabled)
// 1.05 10 May 1998 Memory leak fixed. (Yuheng Zhao)
// Changed OLE initialisation (Carlo Comino)
// Added separate fore + background cell colours (Suggested by John Crane)
// ExpandToFit etc cleaned up - now decreases and
// increases cell sizes to fit client area.
// Added notification messages for the grid's parent (Suggested by
// Added GVIS_READONLY state
// 1.06 20 May 1998 Added TAB key handling. (Daniela Rybarova)
// Intellimouse code correction for whole page scrolling (Paul Grant)
// Fixed 16 bit thumb track problems (now 32 bit) (Paul Grant)
// Fixed accelerator key problem in CInPlaceEdit (Matt Weagle)
// Fixed Stupid ClassWizard code parsing problem (Michael A. Barnhart)
// Double buffering now programmatically selectable
// Workaround for win95 drag and drop registration problem
// Corrected UNICODE implementation of clipboard stuff
// Dragging and dropping from a selection onto itself no
// no longer causes the cells to be emptied
// 1.07 28 Jul 1998 Added EnsureVisible. (Roelf Werkman)
// Fixed delete key problem on read-only cells. (Serge Weinstock)
// OnEndInPlaceEdit sends notification AFTER storing
// the modified text in the cell.
// Added CreateInPlaceEditControl to make it easier to
// change the way cells are edited. (suggested by Chris Clark)
// Added Set/GetGridColor.
// CopyTextToClipboard and PasteTextToGrid problem with
// blank cells fixed, and CopyTextToClipboard tweaked.
// SetModified called when cutting text or hitting DEL. (Jonathan Watters)
// Focus cell made visible when editing begins.
// Blank lines now treated correctly when pasting data.
// Removed ES_MULTILINE style from the default edit control.
// Added virtual CreateCell(row, col) function.
// Fonts now specified on a per-cell basis using Get/SetItemFont.
// 1.08 6 Aug 1998 Ctrl+arrows now allows cell navigation. Modified
// CreateInPlaceEditControl to accept ID of control.
// Added Titletips to grid cells. (Added EnableTitleTips / GetTitleTips)
// 1.09 12 Sep 1998 When printing, parent window title is printed in header - Gert Rijs
// GetNextItem search with GVNI_DROPHILITED now returns
// cells with GVIS_DROPHILITED set, instead of GVIS_FOCUSED (Franco Bez)
// (Also fixed minor bug in GetNextItem) (Franco Bez)
// Cell selection using Shift+arrows works - Franco Bez
// SetModified called after edits ONLY if contents changed (Franco Bez)
// Cell colours now dithered in 256 colour screens.
// Support for MSVC 4.2 (Graham Cheetham)
// 1.10 30 Nov 1998 Titletips now disappear on a scroll event. Compiler errors
// fixed. Grid lines drawing fixed (Graham Cheetham).
// Cell focus fix on Isert Row/Col (Jochen Kauffmann)
// Added DeleteNonFixedRows() (John Rackley)
// Message #define conflict fixed (Oskar Wieland)
// Titletips & cell insert/delete fix (Ramesh Dhar)
// Titletips repeat-creation bug fixed.
// GVN_SELCHANGED message now sends current cell ID
// Font resource leak in GetTextExtent fixed (Gavin Jerman)
// More TAB fixes (Andreas Ruh)
// 1.11 1 Dec 1998 GetNextItem bug fix (suggested by Francis Fu)
// InsertColumn (-1) fix (Roy Hopkins)
// Was too liberal with the "IsEditable"'s. oops. (Michel Hete)
// 1.11a 4 Jan 1999 Compiler errors in VC6 fixed.
// 1.12 10 Apr 1999 Cleanup to allow GRIDCONTROL_NO_CLIPBOARD define
// CE #defines added. (Thanks to Frank Uzzolino for a start on this)
// TitleTip display fixed for cells with images, plus it now uses cell font
// Added GetTextRect and IsCellFixed
// Focus change problem when resizing columns fixed (Sergey Nikiforenko)
// Grid line drawing problem in fixed cells fixed (Sergey Nikiforenko)
// CreateCell format persistance bug fixed (Sergey Nikiforenko)
// DeleteColumn now returns TRUE (oops) (R. Elmer)
// Enter, Tab and Esc key problem (finally) fixed - Darren Webb and Koay Kah Hoe
// OnSize infinite loop fixed - Steve Kowald
// GVN_SELCHANGING and GVN_SELCHANGED values changed to avoid conflicts (Hiroaki Watanabe)
// Added single row selection mode (Yao Cai)
// Fixed image drawing clip problem
// Reduced unnecessary redraws significantly
// GetNextItem additions and bug fix, and GVNI_AREA search option (Franco Bez)
// Added GVIS_MODIFIED style for cells, so individual cells can have their
// modification status queried. (Franco Bez)
// 1.12a 15 Apr 1999 Removed the SetModified/GetModified inlines (no compiler warning!)
// Renamed IDC_INPLACE_CONTROL to IDC_INPLACE_CONTROL and moved
// to the header
//
// TODO:
// - OnOutOfMemory function instead of exceptions
// - Decrease timer interval over time to speed up selection over time
//
// NOTE: Grid data is stored row-by-row, so all operations on large numbers
// of cells should be done row-by-row as well.
//
// KNOWN ISSUES TO BE ADDRESSED (Please don't send bug reports):
// * Killfocus comes to late when a command is selected by the Menu.
// When you are editing a cell and choose a Menuitem that searches for all the
// modified cells it is not found. When you chose the menu a second time it is
// found. I assume that the Menu command is executed before the cell receives the
// KillFocus event. Expect similar Problems with accelerators. (Franco Bez)
// * When you select a cell and move the mouse around (with the Left button down
// i.e continuing with your selection) - if the mouse is over the Fixed column
// or Row the drawing of the selected region is strange - in particular as you
// move up and down say the Left Fixed Column notice the behaviour of the Focus
// Cell - it is out of sync. (Vinay Desai)
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MemDC.h"
#include "GridCtrl.h"
#include "InPlaceEdit.h"
// 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
#define HEADER_HEIGHT 2 // For printing
#define FOOTER_HEIGHT 2
#define LEFT_MARGIN 4
#define RIGHT_MARGIN 4
#define TOP_MARGIN 1
#define BOTTOM_MARGIN 1
#define GAP 1
#define SELECTED_CELL_FONT_WEIGHT 600 // weight of text for selected items
IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
void AFXAPI DDX_GridControl(CDataExchange* pDX, int nIDC, CGridCtrl& rControl)
{
if (rControl.GetSafeHwnd() == NULL) // not subclassed yet
{
ASSERT(!pDX->m_bSaveAndValidate);
HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
if (!rControl.SubclassWindow(hWndCtrl))
{
ASSERT(FALSE); // possibly trying to subclass twice?
AfxThrowNotSupportedException();
}
#ifndef _AFX_NO_OCC_SUPPORT
else
{
// If the control has reparented itself (e.g., invisible control),
// make sure that the CWnd gets properly wired to its control site.
if (pDX->m_pDlgWnd->GetSafeHwnd() != ::GetParent(rControl.GetSafeHwnd()))
rControl.AttachControlSite(pDX->m_pDlgWnd);
}
#endif //!_AFX_NO_OCC_SUPPORT
}
}
// 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
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);
}
return nScrollLines;
}
/////////////////////////////////////////////////////////////////////////////
// CGridCtrl
CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
{
RegisterWindowClass();
// Initialize OLE libraries
m_bMustUninitOLE = FALSE;
#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm)
{
SCODE sc = ::OleInitialize(NULL);
if (FAILED(sc))
AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
else
m_bMustUninitOLE = TRUE;
}
#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_crGridColour = RGB(192,192,192);
m_nRows = 0;
m_nCols = 0;
m_nFixedRows = 0;
m_nFixedCols = 0;
m_nDefCellHeight = 10; // These will get changed to something meaningful
m_nDefCellWidth = 30; // when the window is created or subclassed
m_nVScrollMax = 0; // Scroll position
m_nHScrollMax = 0;
m_nMargin = 0; // cell padding
m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
// per mouse wheel notch to scroll
m_MouseMode = MOUSE_NOTHING;
m_nGridLines = GVL_BOTH;
m_bEditable = TRUE;
m_bListMode = FALSE;
m_bSingleRowSelection = FALSE;
m_bAllowDraw = TRUE; // allow draw updates
m_bEnableSelection = TRUE;
m_bAllowRowResize = TRUE;
m_bAllowColumnResize = TRUE;
m_bSortOnClick = TRUE; // Sort on header row click if in list mode
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_bAscending = TRUE; // sorting stuff
m_SortColumn = -1;
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;
m_bAllowDragAndDrop = FALSE; // for drag and drop
#ifndef _WIN32_WCE
// Initially use the system message font for the GridCtrl font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
memcpy(&m_Logfont, &(ncm.lfMessageFont), sizeof(LOGFONT));
#else
LOGFONT lf;
GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
memcpy(&m_Logfont, &lf, sizeof(LOGFONT));
#endif
// Set up the initial grid size
SetRowCount(nRows);
SetColumnCount(nCols);
SetFixedRowCount(nFixedRows);
SetFixedColumnCount(nFixedCols);
// Set the colours
SetTextColor(m_crWindowText);
SetTextBkColor(m_crWindowColour);
SetBkColor(m_crShadow);
SetFixedTextColor(m_crWindowText);
SetFixedBkColor(m_cr3DFace);
// set initial selection range (ie. none)
m_SelectedCellMap.RemoveAll();
m_PrevSelectedCellMap.RemoveAll();
}
CGridCtrl::~CGridCtrl()
{
DeleteAllItems();
DestroyWindow();
m_Font.DeleteObject();
#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
// Uninitialize OLE support
if (m_bMustUninitOLE)
::OleUninitialize();
#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -