Files
envi-code/SourceCode/Code2026/Dimension/WDGrid.h
T
2026-09-28 15:28:50 +08:00

1056 lines
34 KiB
C++

#pragma once
#include "PDList.h"
#include "SHList.h"
#include "DualPtrList.h"
#include "SHTable.h"
#include "WDictItem.h"
//表格控件
//WDGrid style
#define WDG_READ_ONLY 0x0001//只读
#define WDG_ROW_FIX_LENGTH 0x0002//不能添加、删除行
#define WDG_COL_FIX_LENGTH 0x0004//不能添加、删除列
#define WDG_ROW_UNSEL 0x0008//无行选择区
#define WDG_COL_UNSEL 0x0010//无列选择区
#define WDG_NO_SORT 0x0020//不响应排序操作
#define WDG_COL_FIX_WIDTH 0x0040//不响应调整列宽度操作
#define WDG_COL_POS_FIX 0x0080//不响应移动列操作
#define WDG_ROW_POS_FIX 0x0100//不响应移动行操作
#define WDG_NO_TREE_LINE 0x0200//父行与子行无连线
#define WDG_SINGLE_SEL_ROW 0x0400//行只能单选
#define WDG_NO_PASTE 0x0800//禁止粘贴
#define WDG_LABEL_SORT 0x1000//使用编号排序
#define WDG_FLAT_BUTTON 0x2000//扁平按钮
#define WDG_NO_APPEND_BUTTON 0x4000//有没有AppendRow行
#define WDG_NO_DEFAULT_MENU 0x8000//没有默认菜单
//col style
#define WDG_COL_READ_ONLY 0x0001//只读
#define WDG_COL_COMBO_EDIT 0x0002//用下拉表编辑
#define WDG_COL_COMBO_SEL 0x0004//用下拉表选择
#define WDG_COL_BUTTON_EDIT 0x0008//带右按钮编辑
#define WDG_COL_SPIN_EDIT 0x0010//带右spin编辑
#define WDG_COL_CENTER_ALIGN 0x0020//中心对齐
//row style
#define WDG_ROW_READ_ONLY 0x0001//只读
#define WDG_ROW_DEL_UNABLE 0x0002//禁止删除,如选择集中有一个此类型行,整个选择集将无法移动
#define WDG_ROW_UNFOLD 0x0010//展开的父行
//cell style
#define WDG_CELL_READ_ONLY 0x0001//只读单元格
//菜单ID
#define ID_WDGRID_INS_ROW 1
#define ID_WDGRID_DEL_ROW 2
#define ID_WDGRID_ADD_ROW 3
#define ID_WDGRID_SELECT_ALL 4
#define ID_WDGRID_COPY_ROW 5
#define ID_WDGRID_CUT_ROW 6
#define ID_WDGRID_PASTE_ROW 7
#define ID_WDGRID_INS_COL 8
#define ID_WDGRID_DEL_COL 9
#define ID_WDGRID_ADD_COL 10
#define ID_WDGRID_ARRANGE 11
#define ID_WDGRID_REVERSE 12
#define WDGRID_MENU_ID_USER_FIRST 100
class WDGridRow;
class WDGridCol;
class WDGridCell;
class WColSelector;
class WRowSelector;
class WDGActiveQuad;
class WCellCtrl;
class WCellEdit;
class WCellCombo;
class WRowData;
class WDGrid : public CWnd
{//表格控件
friend class WDGridRow;
friend class WDGridTreeRow;
friend class WDGridCol;
friend class WDGridCell;
friend class WColSelector;
friend class WRowSelector;
friend class WDGActiveQuad;
friend class WCellCtrl;
friend class WCellEdit;
friend class WCellCombo;
friend class WCellButtonEdit;
friend class WCellSpinEdit;
friend class WCellButton;
friend class WCellSpin;
DECLARE_DYNAMIC(WDGrid)
protected:
bool bTreeGrid;//是否支持树
int style;//属性
PDList<WDGridCol> colList;//列链
PDList<WDGridRow> rowList;//数据行链
PDList<WDGridRow> pasteList;//粘贴链
SHList<long>keyList;//鍵链,存储列索引,排序用
DualPtrList<long> rowSelList,colSelList;//当前选定行、列索引链
WDGridCell *pSelCell;//当前编辑单元格
WDGridCell *pSelCell2;//下一个需要编辑单元格
long defaultWidth;//默认列宽度,不设置列宽列将使用它
long rowHeight;//内部行高=文字高度+1(行下距)。
int rowSpace;//行上距
CFont font;//字体
CBrush brush;//背景刷
CPen pen;//分界线画笔
CDC *pDC;//全局CDC对象,窗口创建后内部自动维护,保持始终有效
WDGActiveQuad*pActiveQuad;//焦点指示器
WRowSelector*pRowSelector;//列操作器
WColSelector*pColSelector;//行操作器
WCellCtrl *pCurEdit;//当前的单元格编辑器
bool bVScroll,bHScroll;//是否有滚动条。
WDGridRow* m_pAppendRow;//最后增加新行
long m_iCurRow,m_iCurCol;//当前行
bool m_bModified;//是否已经修改
protected:
bool IsTreeGrid()const{return bTreeGrid;}
void SendParentNotify(WORD wNotify)const;//向窗口发送通知消息
bool IsValidWnd()const{return GetSafeHwnd()!=NULL;}//windows窗口是否已创建
CDC& GetDC(){return *pDC;}//得到当前全局CDC
CBrush& GetBrush(){return brush;}
void CreateFont();
void PrepareDC(CDC*pD=NULL);
void ClearDC(){if(pDC!=NULL)delete pDC;pDC=NULL;}
long GetColHeaderHeight();//行操作器高度
void GetUpCorner(CPoint&pt);//逻辑坐标系原点的设备坐标系坐标,左上边界线的交点
long GetLeft(){return 0;}//左边界线
long GetTop(){return 0;}//上边界线
long GetRight();//右边界线
long GetBottom(){return GetTop()+GetRowNum()*GetRowHeight()+(IsNoAppendButton()?0:GetRowHeight());}//下边界线
//逻辑坐标系中的数据区
void GetRect(CRect&rect){rect.left=GetLeft();rect.top=GetTop();rect.bottom=GetBottom();rect.right=GetRight();}
void GetClientRect(LPRECT lpRect);//数据区,客户区除去行列操作器
void PtToCell(CPoint pt,long&row,long&col);//设备坐标系
void ShowRect(CRect rect);//设备坐标系
void ClearSel(){rowSelList.Clear();colSelList.Clear();}
void FilterDelUnable();//将不能删除行从选择集中去除
bool IsSelDelUnable();//是否选择集中有不可删除行
void ClipSelect();
void Paste(long i);
void RefreshAppendRow();
protected:
DECLARE_MESSAGE_MAP()
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual INT_PTR OnToolHitTest(CPoint point,TOOLINFO*pTI)const;
afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnSetText(WPARAM wParam, LPARAM lParam);
afx_msg UINT OnGetDlgCode(void);
afx_msg void OnCancelMode(void);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnPaint();
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKillFocus(CWnd*pNewWnd);
afx_msg void OnSetFocus(CWnd*pOldWnd);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
protected:
//左键事件
virtual void OnDblClick(WDGridRow&row){}//ok
//右键事件
virtual void OnRClickCell(WDGridCell&cell,CPoint point){}//ok
virtual void OnRClickRow(WDGridRow&row,CPoint point);//ok
virtual void OnRClickCol(WDGridCol&col,CPoint pt);//ok
virtual void OnRClickQuad(CPoint pt);//ok
//编辑事件
virtual bool OnBeforeEdit(WDGridCell&cell,bool &bModified){return true;}//返回值代表是否继续编辑,如果在这个函数中修改了bModified设为true;
virtual WCellCtrl* OnGetCellEdit(WDGridCell&cell);//准备嵌入式单元编辑器
virtual void OnCellComboString(WDGridCell&cell,CComboBox&combo){}//准备下拉列表内容
virtual bool OnCellButtonDown(WDGridCell&cell,CString&res){return false;}//单元格按钮按下响应,返回值代表是否确定,res初始为编辑器内当前内容
virtual void OnCellSpinInit(WDGridCell&cell,CSpinButtonCtrl&spin){}//初始化Spin
virtual bool OnModified(WDGridCell&cell,CString &text){return true;}//单元内容将改变为text,返回值代表是否确定
virtual void OnDataChanged(){m_bModified=true;SendParentNotify(EN_CHANGE);}//内容改变,支持行列数变化、单元格内容变化
virtual void OnCurChanged();//当前行列变化,子类一定要调整用基类
//刷新事件
virtual void OnBeforeRefresh(WDGridCell&cell);//可以修改普通刷新时的文字着色
virtual bool OnRefresh(WDGridRow&row){return true;}//是否继续普通刷新
virtual bool OnRefresh(WDGridCell&cell){return true;}//是否继续普通刷新
//列事件
virtual bool OnBeforeInsertCol(long i,WDGridCol*&pNewCol){return true;}//将插入一列,返回值代表是否确定
virtual void OnInsertCol(WDGridCol&col){OnDataChanged();}//插入一列
virtual bool OnBeforeDeleteCol(){return true;}//返回值代表是否确定
virtual void OnEndDeleteCol(){}//删除列结束
virtual bool OnBeginMoveCol(){return true;}//返回值代表是否确定
virtual bool OnMovingCol(long i){return true;}//移动过程,返回值代表是否可以移动到此处
virtual bool OnMoveCol(long i){return OnMovingCol(i);}//返回值代表是否确定
virtual void OnEndMoveCol(){}//移动列结束
//行事件
virtual bool OnBeforeInsertRow(long i,WDGridRow*&pNewRow){return true;}//将插入一行
virtual bool OnBeforeInsertChild(WDGridTreeRow&row,long iChild,WDGridTreeRow*&pChild){return true;}//将插入一子行
virtual void OnInsertRow(WDGridRow&row){OnDataChanged();}//新插入一行
virtual bool OnBeforeDeleteRow(){return true;}//返回值代表是否确定 
virtual void OnEndDeleteRow(){}//删除行结束
virtual bool OnBeforeClip(){return true;}//返回值代表是否确定
virtual void OnEndClip(){}//剪切结束
virtual bool OnBeforeCopy(){return true;}//返回值代表是否确定
virtual void OnEndCopy(){}//复制结束
virtual bool OnBeforePaste(long i){return true;}//返回值代表是否确定
virtual bool OnBeforePasteChild(WDGridTreeRow&row){return true;}//返回值代表是否确定
virtual void OnEndPaste(){}//粘贴结束,include paste child
virtual bool OnBeginMoveRow(){return true;}//返回值代表是否确定
virtual bool OnMovingRow(long i){return true;}//移动过程,返回值代表是否可以移动到此处
virtual bool OnMoveRow(long i){return OnMovingRow(i);}//返回值代表是否确定
virtual void OnEndMoveRow(){}//移动行结束
//ToolTips
virtual bool OnCellTip(long row,long col,CString&res)const{return false;}
virtual bool OnRowTip(long row,CString&res)const{return false;}
virtual bool OnColTip(long col,CString&res)const{return false;}
virtual bool OnCellButtonTip(long row,long col,CString&res)const{return false;}//准备单元格按钮ToolTip
virtual bool OnActiveQuadTip(CString&res)const{return false;}
public:
//contruct/distruct
WDGrid(bool bTree=false,long colWidth=100);
virtual ~WDGrid();
BOOL Create(const RECT& rect,DWORD wStyle=WS_VISIBLE|WS_CHILD|WS_BORDER|WS_CLIPCHILDREN | WS_CLIPSIBLINGS|WS_HSCROLL|WS_VSCROLL,CWnd* pParentWnd=NULL);
BOOL Create(CWnd *pParent,UINT ID,DWORD wStyle=WS_VISIBLE|WS_TABSTOP|WS_CHILD|WS_BORDER|WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
//attribute
int GetStyle(){return style;}//ok
void SetStyle(int s){style|=s;}//ok
void SetDefaultWidth(long w){defaultWidth=w;}//ok
long GetDefaultWidth(){return defaultWidth;}//ok
void SetReadOnly(bool bRO=true);
void SetRowFixLength(bool bRFL=true);
void SetColFixLength(bool bCFL=true);
void SetRowSel(bool bRS=true);
void SetColSel(bool bCS=true);
void SetSortEnable(bool bSE=true);
void SetColFixWidth(bool bCFW=true);
void SetColPosFix(bool bCPF=true);
void SetRowPosFix(bool bRPF=true);
void SetTreeLine(bool bTL=true);
void SetSingleSelRow(bool bSS=true);
void SetNoPaste(bool bNP=true);
void SetLabelSort(bool bLS=true);
void SetFlatButton(bool bFB=true);
void SetNoAppendButton(bool bNAB=true);
void SetNoDefaultMenu(bool bNDM=true);
bool IsColSel(){return (style&WDG_COL_UNSEL)==0;}//ok
bool IsRowSel(){return (style&WDG_ROW_UNSEL)==0;}//ok
bool IsColFixWidth(){return (style&WDG_COL_FIX_WIDTH)!=0;}//ok
bool IsNeedTreeLine(){return (style&WDG_NO_TREE_LINE)==0;}//ok
bool IsReadOnly(){return (style&WDG_READ_ONLY)!=0;}//ok
bool IsRowFixLength(){return (style&WDG_ROW_FIX_LENGTH)!=0||IsReadOnly();}//ok
bool IsColFixLength(){return (style&WDG_COL_FIX_LENGTH)!=0||IsReadOnly();}//ok
bool IsColPosFix(){return (style&WDG_COL_POS_FIX)!=0||IsReadOnly();}//ok
bool IsRowPosFix(){return (style&WDG_ROW_POS_FIX)!=0||IsReadOnly();}//ok
bool IsSortEnable(){return (style&WDG_NO_SORT)==0&&!IsRowPosFix();}//ok
bool IsSingleSelRow(){return (style&WDG_SINGLE_SEL_ROW)!=0;}//ok
bool IsNoPaste(){return (style&WDG_NO_PASTE)!=0;}//ok
bool IsLabelSort(){return (style&WDG_LABEL_SORT)!=0;}//ok
bool IsFlatButton(){return (style&WDG_FLAT_BUTTON)!=0;}//ok
bool IsNoAppendButton(){return (style&WDG_NO_APPEND_BUTTON)!=0||IsRowFixLength();}//ok
bool IsNoDefaultMenu(){return (style&WDG_NO_DEFAULT_MENU)!=0;}//ok
//row
void Clear();
bool IsValidRow(long i)const{return rowList.IsValidIndex(i);}//ok
bool IsNewRow(long i)const{return i==rowList.GetLength();}//ok
bool IsEmpty()const{return rowList.IsEmpty();}//ok
void AppendRow(WDGridRow*pR=NULL);
void InsertRow(long i,WDGridRow*pR=NULL);//树行慎用!
void DelRow(long i);//不支持删除展开父行!
void DelRowEx(long i);//支持删除展开父行
void MoveRow(long from,long to);//树行慎用!
void SetRowNum(long n);//TreeGrid慎用
long GetRowNum()const{return rowList.GetLength();}//行数(不计被折叠子行)
long GetCurRowIndex(){return m_iCurRow;}//当前唯一选定行或当前编辑行,初始为-1,可能无效
void SetCurRowIndex(long iRow);//强制改变当前行
void MoveToFirst(){rowList.MoveToFirst();}//ok
void MoveToNext(){rowList.MoveToNext();}//ok
void MoveToPre(){rowList.MoveToPre();}//ok
void MoveTo(long i){rowList.MoveTo(i);}//ok
bool IsOut(){return rowList.IsOut();}//ok
WDGridRow* CurRow(){return rowList.GetCurData();}//ok
WDGridTreeRow* CurTreeRow(){return (WDGridTreeRow*)CurRow();}//ok
long GetCur(){return rowList.GetCur();}//ok
WDGridRow& GetRow(long row){return *rowList[row];}//ok
WDGridRow& operator[](long row){return GetRow(row);}//ok
WDGridTreeRow& GetTreeRow(long row){return (WDGridTreeRow&)GetRow(row);}//ok
//col
WDGridCol& GetCol(long i){return *colList[i];}//ok
bool IsColEmpty()const{return colList.IsEmpty();}//ok
bool IsValidCol(long i)const{return colList.IsValidIndex(i);}//ok
void SetColNum(long n);
long GetColNum()const{return colList.GetLength();}//ok
void InsertCol(long i,WDGridCol*pCol=NULL,long width=0);
void InsertCol(long i,const TCHAR*name,long width=0);
void AppendCol(WDGridCol*pCol=NULL,long width=0);
void AppendCol(const TCHAR*name,long width=0);
void DelCol(long i);
void MoveCol(long from,long to);
long GetCurColIndex(){return m_iCurCol;}///当前唯一选定列或当前编辑列,初始为-1,可能无效
//cell
WDGridCell &GetCell(long row,long col);
bool GetCurCell(long&row,long&col)const;
void BeginEditCell(long i,long j);
void EndEditCell();
void CancelEditCell();
void AutoEditCell(WDGridCell*pCell=NULL);//自动编辑和编辑锁定,pCell为NULL则锁定pSelCell
void AutoCloseCell(int iTime=0);
bool IsEditing()const{return pSelCell!=NULL;}//ok
bool IsCellLocking()const{return pSelCell2!=NULL;}//ok
//draw
void Invalidate(BOOL bErase=TRUE);//更新显示
void Refresh();//执行显示
void RecalcLayout(BOOL bRedraw = TRUE);//更新布局
bool FitLastCol();//如果总列宽小于窗口宽度,调整最后一行宽度使之恰好充满窗口
void MoveView(int cx,int cy);//新设备原点相对旧设备原点的偏移
long GetRowSpace(){return rowSpace;}//ok,行上距
void SetRowSpace(int space=3){rowSpace=space;RecalcLayout();}//ok
CFont& GetFont(){return font;}//ok
long GetRowHeight(){return rowHeight+rowSpace;}//ok,字高+行上距
void ShowAppendRow();
//select
void SelectRow(long i,bool bSel=true);
void SelectCol(long i,bool bSel=true);
void SelectAll();
void UnSelect();
bool IsColSelected(){return !colSelList.IsEmpty();}//ok
bool IsRowSelected(){return !rowSelList.IsEmpty();}//ok
bool IsColSelected(long col){return colSelList.Find(col)!=NOT_FOUND;}//ok
bool IsRowSelected(long row){return rowSelList.Find(row)!=NOT_FOUND;}//ok
long GetRowSelNum(){return rowSelList.GetLength();}//ok
long GetColSelNum(){return colSelList.GetLength();}//ok
WDGridRow& GetSelRow(long i){return GetRow(rowSelList[i]);}//ok
WDGridCol& GetSelCol(long i){return GetCol(colSelList[i]);}//ok
void GetSel(SHTable<WDGridRow*>&table);//当前行选择集
void GetSel(SHTable<WDGridCol*>&table);//当前列选择集
bool IsSelConnect();//选择集是否连续
bool IsSelFold();//选择集内的树行是否全部折叠
bool FindAndSel(const TCHAR*s,long iCol);//比较第iCol列,找行并选出
//arrange
long GetMainKey(){return keyList.IsEmpty()?-1:keyList[0];}//ok
void AppendKey(long i){keyList.AddTail(i);}//ok
void ClearKey(){keyList.Clear();}//ok
void Arrange(bool bIncrease=true);
//command
bool DoInsertCol();
bool DoAppendCol();
bool DoInsertColAfter();
bool DoInsertRow();
bool DoInsertRowAfter();
bool DoInsertTree();
bool DoInsertTreeAfter();
bool DoAppendRow(bool bSel=true);
bool DoAppendTree();
bool DoAppendChild();
bool DoDelete();
bool DoClip();
bool DoCopy();
bool DoPaste();
bool DoPasteChild();
//other
PDList<WDGridRow>& GetRowPaste(){return pasteList;}//ok,当前粘贴板内容
void ShowActive(bool bActive=true);//显示是否拥有输入焦点
bool IsMyFocus(const CWnd*pNewWnd)const;//判断当前焦点
bool IsModified()const{return m_bModified;}
void SetModify(bool bTrue){m_bModified=bTrue;}
};
class WDGridCol
{
friend class WDGrid;
friend class WDGridRow;
friend class WDGridCell;
friend class WColSelector;
friend class WRowSelector;
protected:
long index;//索引
int style;//属性
TString name;//列名
long left;//左分界线
long right;//右分界线
COLORREF backColor,textColor;//字体和背景色
CBrush brush;//背景刷
WDGrid& grid;//所属数据表格
protected:
void SetIndex(long i){index=i;}
void Move(long cx){left+=cx;right+=cx;}
void SetLeft(long l){left=l;}
void SetRight(long r){right=r;}
long GetLeft(){return left;}
long GetTop(){return grid.GetTop();}
long GetRight(){return right;}
long GetBottom(){return grid.GetBottom();}
void GetRect(CRect &rect)
{rect.left=GetLeft();rect.top=GetTop();rect.right=GetRight();rect.bottom=GetBottom();}
CBrush& GetBrush(){return brush;}//only for OnCtlColor
void Select(bool bSel=true);//翻转颜色
public:
//contruct/distruct
WDGridCol(const TCHAR*n,WDGrid& parent);
virtual ~WDGridCol(){}//ok
//attribute
bool IsReadOnly(){return (style&WDG_COL_READ_ONLY)!=0||grid.IsReadOnly();}//ok
bool IsComboEdit(){return (style&WDG_COL_COMBO_EDIT)!=0;}//ok
bool IsComboSel(){return (style&WDG_COL_COMBO_SEL)!=0;}//ok
bool IsRightButton(){return (style&WDG_COL_BUTTON_EDIT)!=0;}//ok
bool IsRightSpin(){return (style&WDG_COL_SPIN_EDIT)!=0;}//ok
bool IsCenterAlign(){return (style&WDG_COL_CENTER_ALIGN)!=0;}//ok
void SetReadOnly(bool bRO=true);
void SetComboEdit(bool bCE=true);
void SetComboSel(bool bCS=true);
void SetRightButton(bool bRB=true);
void SetRightSpin(bool bRS=true);
void SetCenterAlign(bool CA=true);
long GetIndex(){return index;}//ok
const TCHAR * GetName(){return name;}//ok
void SetName(const TCHAR*n){name=n;}//ok
long GetWidth(){return right-left;}//ok
int GetStyle(){return style;}//ok
void SetStyle(int s){style|=s;}//ok
COLORREF GetTextColor(){return textColor;}//ok
COLORREF GetBackColor(){return backColor;}//ok
void SetTextColor(COLORREF color){textColor=color;}//ok
void SetBackColor(COLORREF color){backColor=color;brush.DeleteObject();brush.CreateSolidBrush(color);}//ok
//compare
bool operator>(WDGridCol&col){return index>col.GetIndex();}//ok
bool operator<(WDGridCol&col){return index<col.GetIndex();}//ok
};
//行的扩展数据
class WRowData
{
public:
virtual ~WRowData(){}
};
class WDGridRow
{
friend class WDGrid;
friend class WDGridCol;
friend class WDGridTreeRow;
friend class WDGridCell;
friend class WColSelector;
friend class WRowSelector;
protected:
WRowData *pData;//扩展数据
long index;//索引
int style;//属性
PDList<WDGridCell> cellList;//单元格链
WDGrid& grid;
protected:
virtual void InsertCol(long i,WDGridCol&col);
virtual void AppendCol(WDGridCol&col);
virtual void DelCol(long i){cellList.Del(i);}
virtual void MoveCol(long from,long to){cellList.Move(from,to);}
int GetStyle(){return style;}
void SetIndex(long id){index=id;}
long GetLeft(){return grid.GetLeft();}
long GetTop(){return grid.GetTop()+index*grid.GetRowHeight();}
long GetRight(){return grid.GetRight();}
long GetBottom(){return grid.GetTop()+(index+1)*grid.GetRowHeight();}
void GetRect(CRect &rect)
{rect.left=GetLeft();rect.top=GetTop();rect.right=GetRight();rect.bottom=GetBottom();}
void Select(bool bSel=true);//颜色翻转,参数无用
public:
//construct/distruct
WDGridRow(WDGrid&grid);
WDGridRow& operator=(WDGridRow&row);//exclude index
virtual ~WDGridRow();//ok
//attribute
virtual bool IsParentRow(){return false;}//ok
virtual bool IsChildRow(){return false;}//ok
virtual bool IsTreeRow(){return false;}//ok
long GetIndex(){return index;}//ok
bool IsReadOnly(){return (style&WDG_ROW_READ_ONLY)!=0||grid.IsReadOnly();}//ok
bool IsDelUnable(){return (style&WDG_ROW_DEL_UNABLE)!=0||IsReadOnly();}//ok
void SetReadOnly(bool bRO=true);
void SetDelUnable(bool bDU=true);
void SetExtendData(WRowData*p);
WRowData* GetExtendData(){return pData;}//ok
//cell
WDGridCell&operator[](long col){return *cellList[col];}//ok
//draw
virtual void Refresh();//对所有Cell调用Refresh();
//compare
bool operator>(WDGridRow&row);
bool operator<(WDGridRow&row);
};
class WDGridTreeRow:public WDGridRow
{
friend class WDGrid;
friend class WDGridCell;
protected:
PDList<WDGridTreeRow> childRow;
WDGridTreeRow*pParent;
protected:
virtual void InsertCol(long i,WDGridCol&col);
virtual void AppendCol(WDGridCol&col);
virtual void DelCol(long i);
virtual void MoveCol(long from,long to);
long GetGlobalChildIndex(long i);//取第i个子行的grid index
long GetChildIndex(WDGridTreeRow*pRow);
void GetTreeQuad(CRect&rect);
bool IsPtInTreeQuad(CPoint&pt){CRect rect;GetTreeQuad(rect);return rect.PtInRect(pt)==TRUE;}//ok
public:
//construct/distruct
WDGridTreeRow(WDGrid&grid);
WDGridTreeRow(WDGridTreeRow*parent);
WDGridTreeRow&operator=(WDGridTreeRow&row);
void operator<<(WDGridTreeRow&row);//除了拷贝,还取下扩展数据.
virtual ~WDGridTreeRow(){}//ok
//attribute
virtual bool IsParentRow(){return !childRow.IsEmpty();}//ok
virtual bool IsChildRow(){return pParent!=NULL;}//ok
virtual bool IsTreeRow(){return true;}//ok
bool IsRootRow(){return !IsChildRow();}//ok
bool IsFold(){return (style&WDG_ROW_UNFOLD)==0;}//ok
void SetUnFoldFlag(bool bUF=true);
void SetParent(WDGridTreeRow*p){pParent=p;}//ok
WDGridTreeRow& GetParent(){return *pParent;}//ok
WDGridTreeRow* Parent(){return pParent;}//ok
WDGridTreeRow* RootRow();
bool IsVisible(){return index!=-1;}//ok,是否已经插入到grid
bool IsChildVisible(){return GetChild(0).IsVisible();}//ok
long GetParentNum();//父行数
long GetChildNum(){return childRow.GetLength();}//ok,直接子行数
long GetOffspringNum();//后代总数
long GetRowNum();//实际占用的行数(包括自身),不考虑是否自身已经插入grid
void MoveToFirst(){childRow.MoveToFirst();}//ok
void MoveToNext(){childRow.MoveToNext();}//ok
void MoveToPre(){childRow.MoveToPre();}//ok
bool IsOut(){return childRow.IsOut();}//ok
WDGridTreeRow* CurChild(){return childRow.GetCurData();}//ok
WDGridTreeRow& GetChild(long i){return *childRow[i];}//ok
WDGridTreeRow& GetLastChild(){childRow.MoveToLast();return *childRow.GetCurData();}//ok
//child row
void InsertChild(long i,WDGridTreeRow*pRow=NULL);
void AppendChild(WDGridTreeRow*pRow=NULL){InsertChild(GetChildNum(),pRow);}//ok
void DelChild(long i);
void ClearChild();
//operator
void Fold();
void UnFold();
void FoldAll();
void UnFoldAll();
void ArrangeChild(bool bIncrease=true);
bool FindAndSel(const TCHAR*sId,long iCol);
};
class WDGridCell
{
friend class WDGridRow;
friend class WDGridTreeRow;
friend class WDGridCol;
friend class WDGrid;
friend class WColSelector;
friend class WRowSelector;
protected:
TString text;//数据
int style;//特性
WDGridRow&row;//所属行
WDGridCol&col;//所属列
WDGrid&grid;//所属表格
public:
//contruct/distruct
WDGridCell(WDGrid&g,WDGridRow&r,WDGridCol&c);
WDGridCell&operator=(WDGridCell&cell);//all data
virtual ~WDGridCell(){}
//attribute
bool IsReadOnly(){return (style&WDG_CELL_READ_ONLY)!=0||col.IsReadOnly()||row.IsReadOnly()||grid.IsReadOnly();}//ok
void SetReadOnly(bool bRO=true);
//data
void SetText(const TCHAR* s){text=s;}//ok
TString& GetText(){return text;}//ok
operator const TCHAR*(){return text;}//ok
operator double(){return text;}//ok
operator int(){return text;}//ok
WDGridRow& GetRow(){return row;}//ok
WDGridCol& GetCol(){return col;}//ok
WDGrid& GetGrid(){return grid;}//ok
long GetRowIndex(){return row.GetIndex();}//ok
long GetColIndex(){return col.GetIndex();}//ok
//draw
void Select(bool bSel=true);//bSel参数实际无用
void Refresh();
void GetRect(CRect &rect)//ok,包含分界线
{rect.left=col.GetLeft();rect.top=row.GetTop();rect.right=col.GetRight();rect.bottom=row.GetBottom();}
void GetTextRect(CRect&rect)//ok,不包含分界线
{rect.left=col.GetLeft()+1;rect.top=row.GetTop()+1;rect.right=col.GetRight();rect.bottom=row.GetBottom();}
//compare
bool operator>(WDGridCell&cell){return text>cell.GetText();}//ok
bool operator<(WDGridCell&cell){return text<cell.GetText();}//ok
};
class WColSelector:public CWnd
{//列选择器
protected:
WDGrid&grid;//所属
CBrush brush;//背景刷
bool bDragCol,bDragEdge;//拖动状态
int dragColIndex;//当前调整宽度列的索引
CPoint oldPoint;//旧拖动线位置
inline long PtToCol(CPoint pt)const;//设备坐标
public:
WColSelector(WDGrid&g);
virtual ~WColSelector(){}
virtual INT_PTR OnToolHitTest(CPoint point,TOOLINFO*pTI)const;
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
};
class WRowSelector:public CWnd
{//行选择器
protected:
WDGrid&grid;//所属表格
CBrush brush;//背景刷
bool bDragRow;//拖动状态
CPoint oldPoint;//旧的拖动线位置
long rowStart;//拖动时的起始位置
long PtToRow(CPoint pt)const;//pt为设备坐标系
long m_iCurRow;
public:
WRowSelector(WDGrid&g);
virtual ~WRowSelector(){}
void OnCurRowChanged();
virtual INT_PTR OnToolHitTest(CPoint point,TOOLINFO*pTI)const;
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
};
class WDGActiveQuad:public CWnd
{//焦点指示块
protected:
bool bActive;
WDGrid&grid;
public:
WDGActiveQuad(WDGrid&g);
virtual ~WDGActiveQuad(){}
void ShowActive(bool bA=true){bActive=bA;Invalidate();}
public:
virtual INT_PTR OnToolHitTest(CPoint point,TOOLINFO*pTI)const;
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
};
class WCellCtrl
{
friend class WDGridCol;
friend class WDGridRow;
friend class WDGridCell;
friend class WDGrid;
protected:
WDGridCell&cell;
public:
//construct/distruct
WCellCtrl(WDGridCell&c):cell(c){}
virtual ~WCellCtrl(){}
virtual CWnd* GetWnd()=0;
virtual void Create(CRect&rect)=0;
virtual bool IsModified()=0;
virtual void GetNewText(CString&text)=0;
virtual bool IsLeftEnd()=0;
virtual bool IsRightEnd()=0;
virtual bool IsUpEnd()=0;
virtual bool IsDownEnd()=0;
virtual void SetModified(bool bM=true){}//For WCellButton,WCellSpin
virtual void SetNewText(const TCHAR*text){};//For WCellButton,WCellSpin
bool IsMyFocus(CWnd*pNewWnd);
void Destroy();
void Hide();
WDGridCell& GetCell(){return cell;}//ok
};
class WCellEdit:public CEdit,public WCellCtrl
{
public:
WCellEdit(WDGridCell&c);
virtual CWnd* GetWnd();
virtual void Create(CRect&rect);
virtual bool IsModified();
virtual void SetModified(bool bM=true);
virtual void SetNewText(const TCHAR*text);
virtual void GetNewText(CString&text);
virtual bool IsLeftEnd();
virtual bool IsRightEnd();
virtual bool IsUpEnd();
virtual bool IsDownEnd();
virtual void PostNcDestroy();
protected:
afx_msg void OnKillFocus(CWnd*pNewWnd);
afx_msg void OnSetFocus(CWnd*pOldWnd);
DECLARE_MESSAGE_MAP()
};
class WCellCombo:public CComboBox,public WCellCtrl
{
protected:
bool bModified;
bool bEditable;
public:
WCellCombo(WDGridCell&c,bool bE);
virtual CWnd* GetWnd();
virtual void Create(CRect&rect);
virtual bool IsModified();
virtual void GetNewText(CString&text);
virtual bool IsLeftEnd();
virtual bool IsRightEnd();
virtual bool IsUpEnd();
virtual bool IsDownEnd();
virtual void PostNcDestroy();
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnCbnKillfocus();
afx_msg void OnCbnSetfocus();
afx_msg void OnCbnEditchange();
afx_msg void OnCbnSelchange();
};
class WCellButton:public CButton
{
protected:
WCellCtrl*pCellEdit;
public:
bool Create();
void SetCellEdit(WCellCtrl* pEdit);
public:
virtual INT_PTR OnToolHitTest(CPoint point,TOOLINFO*pTI)const;
DECLARE_MESSAGE_MAP()
afx_msg void OnBnClicked();
};
class WCellButtonEdit:public WCellEdit
{
protected:
WCellButton button;
public:
WCellButtonEdit(WDGridCell&c);
void Create(CRect&rect);
};
class WCellSpin:public CSpinButtonCtrl
{
protected:
WCellCtrl*pCellEdit;
public:
bool Create();
void SetCellEdit(WCellCtrl* pEdit);
};
class WCellSpinEdit:public WCellEdit
{
protected:
WCellSpin spin;
public:
WCellSpinEdit(WDGridCell&c);
void Create(CRect&rect);
DECLARE_MESSAGE_MAP()
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnEnChange();
};
inline void WDGrid::SetReadOnly(bool bRO)//ok
{
if(bRO)
style|=WDG_READ_ONLY;
else
style&=~WDG_READ_ONLY;
}
inline void WDGrid::SetSortEnable(bool bSE)//ok
{
if(!bSE)
style|=WDG_NO_SORT;
else
style&=~WDG_NO_SORT;
}
inline void WDGrid::SetRowFixLength(bool bRFL)//ok
{
if(bRFL)
style|=WDG_ROW_FIX_LENGTH;
else
style&=~WDG_ROW_FIX_LENGTH;
}
inline void WDGrid::SetColFixLength(bool bCFL)//ok
{
if(bCFL)
style|=WDG_COL_FIX_LENGTH;
else
style&=~WDG_COL_FIX_LENGTH;
}
inline void WDGrid::SetColFixWidth(bool bCFW)//ok
{
if(bCFW)
style|=WDG_COL_FIX_WIDTH;
else
style&=~WDG_COL_FIX_WIDTH;
}
inline void WDGrid::SetColPosFix(bool bCPF)//ok
{
if(bCPF)
style|=WDG_COL_POS_FIX;
else
style&=~WDG_COL_POS_FIX;
}
inline void WDGrid::SetRowPosFix(bool bRPF)//ok
{
if(bRPF)
style|=WDG_ROW_POS_FIX;
else
style&=~WDG_ROW_POS_FIX;
}
inline void WDGrid::SetRowSel(bool bRS)//ok
{
if(!bRS)
style|=WDG_ROW_UNSEL;
else
style&=~WDG_ROW_UNSEL;
RecalcLayout();
}
inline void WDGrid::SetColSel(bool bCS)//ok
{
if(!bCS)
style|=WDG_COL_UNSEL;
else
style&=~WDG_COL_UNSEL;
RecalcLayout();
}
inline void WDGrid::SetTreeLine(bool bTL)//ok
{
if(!bTL)
style|=WDG_NO_TREE_LINE;
else
style&=~WDG_NO_TREE_LINE;
if(IsValidWnd())
Invalidate();
}
inline void WDGrid::SetSingleSelRow(bool bSS)//ok
{
if(bSS)
style|=WDG_SINGLE_SEL_ROW;
else
style&=~WDG_SINGLE_SEL_ROW;
}
inline void WDGrid::SetNoPaste(bool bNP)//ok
{
if(bNP)
style|=WDG_NO_PASTE;
else
style&=~WDG_NO_PASTE;
}
inline void WDGrid::SetLabelSort(bool bLS)//ok
{
if(bLS)
style|=WDG_LABEL_SORT;
else
style&=~WDG_LABEL_SORT;
}
inline void WDGrid::SetFlatButton(bool bFB)
{
if(bFB)
style|=WDG_FLAT_BUTTON;
else
style&=~WDG_FLAT_BUTTON;
}
inline void WDGrid::SetNoAppendButton(bool bNAB)
{
if(bNAB)
style|=WDG_NO_APPEND_BUTTON;
else
style&=~WDG_NO_APPEND_BUTTON;
}
inline void WDGrid::SetNoDefaultMenu(bool bNDM)
{
if(bNDM)
style|=WDG_NO_DEFAULT_MENU;
else
style&=~WDG_NO_DEFAULT_MENU;
}
inline void WDGridCol::SetReadOnly(bool bRO)//ok
{
if(bRO)
style|=WDG_COL_READ_ONLY;
else
style&=~WDG_COL_READ_ONLY;
}
inline void WDGridCol::SetComboEdit(bool bCE)//ok
{
if(bCE)
style|=WDG_COL_COMBO_EDIT;
else
style&=~WDG_COL_COMBO_EDIT;
}
inline void WDGridCol::SetComboSel(bool bCS)//ok
{
if(bCS)
style|=WDG_COL_COMBO_SEL;
else
style&=~WDG_COL_COMBO_SEL;
}
inline void WDGridCol::SetRightButton(bool bRB)//ok
{
if(bRB)
style|=WDG_COL_BUTTON_EDIT;
else
style&=~WDG_COL_BUTTON_EDIT;
}
inline void WDGridCol::SetRightSpin(bool bRS)//ok
{
if(bRS)
style|=WDG_COL_SPIN_EDIT;
else
style&=~WDG_COL_SPIN_EDIT;
}
inline void WDGridCol::SetCenterAlign(bool bCA)//ok
{
if(bCA)
style|=WDG_COL_CENTER_ALIGN;
else
style&=~WDG_COL_CENTER_ALIGN;
}
inline void WDGridRow::SetReadOnly(bool bRO)//ok
{
if(bRO)
style|=WDG_ROW_READ_ONLY;
else
style&=~WDG_ROW_READ_ONLY;
}
inline void WDGridRow::SetDelUnable(bool bDU)//ok
{
if(bDU)
style|=WDG_ROW_DEL_UNABLE;
else
style&=~WDG_ROW_DEL_UNABLE;
}
inline void WDGridTreeRow::SetUnFoldFlag(bool bUF)//ok
{
if(bUF)
style|=WDG_ROW_UNFOLD;
else
style&=~WDG_ROW_UNFOLD;
}
inline void WDGridCell::SetReadOnly(bool bRO)//ok
{
if(bRO)
style|=WDG_CELL_READ_ONLY;
else
style&=~WDG_CELL_READ_ONLY;
}
inline bool WDGrid::GetCurCell(long&row,long&col)const
{
if(!IsEditing())
return FALSE;
row=pSelCell->GetRowIndex();
col=pSelCell->GetColIndex();
return TRUE;
}
//数据区(除去行列选择器)的客户区设置坐标系表示
inline void WDGrid::GetClientRect(LPRECT lpRect)//ok
{
CWnd::GetClientRect(lpRect);
if(IsRowSel())
lpRect->left+=GetRowHeight();
if(IsColSel())
lpRect->top+=GetColHeaderHeight();
}
//数据区的左上角,逻辑坐标系原点在设备坐标系的表示
inline void WDGrid::GetUpCorner(CPoint&pt)
{
int x=bHScroll?GetScrollPos(SB_HORZ):0;
int y=bVScroll?GetScrollPos(SB_VERT):0;
CRect rect;
GetClientRect(&rect);
pt.x=-x+rect.left;
pt.y=-y+rect.top;
}
inline void WDGrid::SendParentNotify(WORD wNotify)const
{
UINT id=GetDlgCtrlID();
if(GetParent()!=NULL)
GetParent()->SendMessage(WM_COMMAND,MAKEWPARAM(id,wNotify),(LPARAM)GetSafeHwnd());
}
inline WDGridCell& WDGrid::GetCell(long row,long col){return GetRow(row)[col];}//ok
//pt为设备坐标系
inline long WColSelector::PtToCol(CPoint pt)const
{
long row,col;
if(grid.IsRowSel())
pt.x+=grid.GetRowHeight();
grid.PtToCell(pt,row,col);
return col;
}
//pt为设备坐标系
inline long WRowSelector::PtToRow(CPoint pt)const
{
long row,col;
if(grid.IsColSel())
pt.y+=grid.GetColHeaderHeight();
grid.PtToCell(pt,row,col);
return row;
}
inline void WDGrid::ShowActive(bool bActive)//ok
{
if(pActiveQuad!=NULL)
pActiveQuad->ShowActive(bActive);
}
inline long WDGrid::GetRight()
{
if(colList.IsEmpty())
return GetLeft();
colList.MoveToLast();
return colList.GetCurData()->GetRight();
}
class DictRowData : public WRowData
{
public:
int nType;
DualPtrList<CString > lstStr;
};
class DictGrid : public WDGrid
{
public:
DictGrid();
void SetModified(bool bModified = false);
bool IsModified();
void DictToGrid(WDict *pDict);
void GridToDict(WDict *pDict);
virtual void OnCellComboString(WDGridCell&cell, CComboBox&combo);
virtual bool OnBeforeEdit(WDGridCell&cell, bool &bModified);
virtual bool OnModified(WDGridCell&cell, CString &text);
virtual bool OnBeforeInsertChild(WDGridTreeRow&row, long iChild, WDGridTreeRow*&pChild);//将插入一子行
virtual void OnInsertRow(WDGridRow&row);
// add by xly on 110408 截获鼠标滚轴
BOOL PreTranslateMessage(MSG* pMsg);
protected:
bool m_bModified;
int GetTypeIndex(CString szType);
void DictToTreeRow(WDict *pDict, WDGridTreeRow *pRow);
void DictToRow(WDict *pDict, WDGridTreeRow *pRow);
void TreeRowToDict(WDGridTreeRow &row, WDict *pDict);
void RowToDict(WDGridTreeRow &row, WDict *pDict);
};