65.9K
CodeProject 正在变化。 阅读更多。
Home

智能网格

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (6投票s)

2000年4月6日

viewsIcon

405340

downloadIcon

7295

使用 ATL、STL 和 Win32 API 构建网格。

引言

这是一个使用 ATL 3.0、STL 和 Win32 API 构建的数据网格。本文档提供了一些关于网格功能的说明。我不会详细描述我的网格的实现,因为代码量很大,我不认为任何人都有足够的耐心来阅读这样的内容。源代码已注释,这应该足够了。

Smart Grid

数据类型

正如您所见,网格的每一列都有一个关联的数据类型。这意味着同一列中的每个值都将具有相同的类型。可用类型是

   // These are the data types
   typedef [v1_enum] enum DataType 
   {
      DataType_Empty = 0,      // Not specified
      DataType_Null = 1,      // NULL
      DataType_I2 = 2,      // 2-byte signed int
      DataType_I4 = 3,      // 4-byte signed int
      DataType_R4 = 4,      // 4-byte real
      DataType_R8 = 5,      // 8-byte real
      DataType_Cy = 6,      // Currency
      DataType_Date = 7,      // Date
      DataType_BStr = 8,      // Binary string
      DataType_Dispatch = 9,   // IDispatch FAR*
      DataType_Error = 10,   // Scodes
      DataType_Bool = 11,      // Boolean; True=-1, False=0
      DataType_Variant = 12,   // VARIANT FAR*
      DataType_Unknown = 13,   // IUnknown FAR*
      DataType_UI1 = 17,      // Unsigned char   
      
      // My types
      DataType_Option = 0x0100,    // Combo box
      DataType_StrictOption     // Drop down list

   } DataType;

正如大家所见,这些类型实际上几乎都是 VARTYPE。如果用户尝试用与列关联的类型不兼容的值更改单元格的值,则单元格的值将不会改变。我还添加了一些自定义类型,例如 OptionStrictOption。这些类型的数据使用组合框和下拉列表进行编辑,正如您在下图中所看到的。

Smart Grid

范围规范

每列都有一个类型和一个值范围。这意味着您可以在单元格中输入与列关联的类型且在指定范围内的值。例如,您可以为数值指定范围:“18,49”,或者您可以为 OptionStrictOption 类型指定可用选项:“Male|Female”。对于数值,指定范围的可能性是

  • ",nMax"

    这意味着该列中的值将被限制为小于或等于 nMax

  • "nMin,"

    该列中的值将被限制为大于或等于 nMax

  • "nMin,nMax"

    该列中的值不能由用户更改,以使其不超出区间 [nMin,nMax]

用户操作

也支持行选择。您可以使用右键单击选择网格中的多行。单击网格的左上角会选择网格中的所有行。双击同一区域会取消选择所有行。例如,从 VB,您可以测试一行是否被选中。可以选择在左侧标题行上显示行号。按 Enter 键或 F2 键将网格置于编辑模式。根据所选单元格中数据的类型,编辑模式会打开一个编辑控件、组合框、下拉列表,或者值会自动更改(布尔值)。支持排序。如果列的 AllowUserToSort 属性设置为 TRUE,那么双击该列将根据该列的值对行进行排序。如果用户修改了该列并且内容变得未排序,按 F5 键将重新排序。

Smart Grid

顶部标题高度、左侧标题宽度、行高和列宽都支持静态和动态调整。在上一张图中,我用红点标记了可用于调整大小的点。

Smart Grid

颜色是完全可定制的。您可以为网格项选择您喜欢的颜色组合,正如您在屏幕截图中看到的。

数据源

您可以通过代码(VB 是操作此网格的最简单方式)向网格填充数据。此外,还有另外两种输入数据到网格的方法:以前打开的 ADO Recordset、连接字符串或 SQL SELECT 语句。不幸的是,在此版本的网格中,数据库在单元格值更改时不会自动更新。这将在下一版本中完成。

   // This are data source types
   typedef [v1_enum] enum
   {
      DataSourceType_None = 0,
      DataSourceType_ADORecordset,
      DataSourceType_SQLStatement,
   } DataSourceType;

数据库连接目前实现得不是很好,所以我建议该网格与 DataSourceType_None 一起使用。

网格操作

现在我将描述可用于操作网格元素的接口。

ISmartGrid

   // Use this to manipulate grid properties
   interace ISmartGrid : IDispatch;

ISmartGrid 接口用于操作网格的通用属性。ISmartGrid 是一个很大的接口,所以我将描述它的方法和属性,而不会在此处插入 IDL 代码。

方法

AddColumn( [in] Name, [in] Type, [in, optional] ReadOnly, 
     [in, optional] Range, [out, optional] Column )
InsertColumn( [in] Name, [in] Type, [in] Position, [in, optional] ReadOnly, 
     [in, optional] Range, [out, optional] Column )
RemoveColumn( [in] Position )
      
AddRow( [out, optional] Row )
InsertRow( [in] Position, [out, optional] Row )
RemoveRow( [in] Position )
      
SelectAllRows()
UnselectAllRows()
Requery()

属性

// State
ActiveColumn
ActiveRow
NumberOfColumns
NumberOfRows
ReadOnly
UILocked
      
// Data access
Column
ConnectionString
CursorType
DataSource
DataSourceType
LockType
Row
      
// User interface
ActiveRowColor
ContentBkColor
      
      
ContentForeColor
ContentLinesColor
      
DefaultColumnWidth
Font
HeaderBkCOlor
HeaderForeColor
HeaderLinesColor
LeftHeaderVisible
LeftHeaderWidth      
RowHeight
SelectedItemColor
TopHeaderHeight
TopHeaderVisible

使用 ISmartGrid 接口的方法,可以向网格添加列和行。添加列或行时,可以选择返回对它的引用,以便在插入后立即使用。我将网格的属性分为三个部分。第一个称为 **State**,我在这里将所有引用网格状态的属性分组。第二个组称为 **Data Access**,第三组属性可用于自定义 **User Interface**。

ICell

   [
      helpstring("ICell interface is used to access cells"),
      uuid(C6462BB2-E639-11d3-8138-0000B49DBD2E),
      pointer_default(unique)
   ]
   interface ICell : IUnknown
   {
      [propget, helpstring("property Value")] 
         HRESULT Value([out, retval] VARIANT *pVal);      
      [propput, helpstring("property Value")] 
         HRESULT Value([in] VARIANT newVal);
   };

正如您所见,ICell 接口用于操作单个单元格。单元格具有一个 Value 属性,用于读取或设置单元格的值。

IRow

[
  helpstring("IRow interface used to access rows from grid"),
  uuid(E18D7A91-E639-11d3-8138-0000B49DBD2E),
  pointer_default(unique)
]
interface IRow : IUnknown
{      
  [propget, helpstring("Get the specified cell of this row")] 
    HRESULT Cell(long nIndex, [out, retval] ICell **pVal);
      
  [propget, helpstring("Returs TRUE if this row is active and false otherwise")] 
    HRESULT Active([out, retval] BOOL *pVal);
  [propput, helpstring("Put this property TRUE if you wanna activate this row")] 
    HRESULT Active([in] BOOL newVal);
      
  [propget, helpstring("TRUE if this row is selected")] 
    HRESULT Selected([out, retval] BOOL *pVal);
  [propput, helpstring("Put this property on TRUE if you want to select this row")] 
    HRESULT Selected([in] BOOL newVal);
      
  [propget, helpstring("Returns the index of this row")] 
    HRESULT Index([out, retval] long *pVal);
};

IRow 接口可用于操作每一行。一行由单元格组成。您可以通过列索引从给定行获取对单元格的引用。一次只能激活一行。可以通过 Active 属性检索或更改此行。可以选中一行或多行。您可以通过 Selected 属性选择或查找一行是否被选中。可以通过 Index 属性读取行的索引。

IColumn

   [
      helpstring("IColumn interface used to access columns individually"),
      uuid(506580C1-E643-11d3-8138-0000B49DBD2E),
      pointer_default(unique)
   ]
   interface IColumn : IUnknown
   {
      [propget, helpstring("Access a cell from this column")] 
         HRESULT Cell(long nIndex, [out, retval] ICell** pVal);
      
      [propget, helpstring("Get the width of the column in pixels")] 
         HRESULT Width([out, retval] long *pVal);
      [propput, helpstring("Put the width of the column in pixels")] 
         HRESULT Width([in] long newVal);

      [propget, helpstring("Get the label of the column")] 
         HRESULT Name([out, retval] BSTR *pVal);
      [propput, helpstring("Put the label of the column")] 
         HRESULT Name([in] BSTR newVal);

      [propget, helpstring("Get data type used for this column")]
         HRESULT DataType([out, retval] DataType *pVal);

      [propget, helpstring("Put the values range")] 
         HRESULT Range([out, retval] BSTR *pVal);
      [propput, helpstring("Get the values range")] 
         HRESULT Range([in] BSTR newVal);

      [propget, helpstring("Get the index of the column")] 
         HRESULT Index([out, retval] long *pVal);
      
      [propget, helpstring("Get the ReadOnly state of the column")] 
         HRESULT ReadOnly([out, retval] BOOL *pVal);
      [propput, helpstring("Changes the ReadOnly state of the column")] 
         HRESULT ReadOnly([in] BOOL newVal);

      [propget, helpstring("Get SortOrder property of this column")] 
         HRESULT SortOrder([out, retval] SortOrder *pVal);
      [propput, helpstring("Changes the SortOrder property of the column")] 
         HRESULT SortOrder([in] SortOrder newVal);

      [propget, helpstring("Returns AllowUserToSort value")] 
         HRESULT AllowUserToSort([out, retval] BOOL *pVal);
      [propput, helpstring("Sets AllowUserToSort value")] 
         HRESULT AllowUserToSort([in] BOOL newVal);

      [helpstring("Resorts the grid data, by this column content")]
         HRESULT Resort();
   };

IColumn 接口可用于读取或更改每一列的属性。就像行一样,您可以通过 Cell 属性访问列中的单元格,前提是您指定了单元格在列中的索引。一列具有以下属性:Width(以像素为单位)、Name(显示在顶部标题上的标签)、DataType(只读属性,用于检索与列关联的数据类型)。Index 是该列在网格中的零基索引,ReadyOnly 是一个布尔属性,可用于使列仅可查看。即使网格不是完全只读的。

事件

当发生某些操作时,网格会引发一些事件。这些事件可以在以下 dispinterface 中看到

   [
      uuid(855D88AF-C9BD-11D3-A34E-0080AD303A9A),
      helpstring("_ISmartGridEvents Interface")
   ]
   dispinterface _ISmartGridEvents
   {
      properties:
      
      methods:
      [id(1), helpstring("Raised when the active row has changed")] 
         HRESULT RowChanged(long nPrevious, long nNew);
      [id(2), helpstring("Raised when the active column has changed")] 
         HRESULT ColumnChanged(long nPrevious, long nNew);
      [id(3), helpstring("Raised when the active cell has changed")] 
         HRESULT CellChanged(long nPreviousRow, long nPreviousColumn, 
         long nNewRow, long nNewColumn);

      // Cell content changing events
      [id(4), helpstring("Raised before edit begins")] 
         VARIANT_BOOL BeginCellEdit(long nRow, long nColumn, ICell*);
      [id(5), helpstring("Raised after edit is ended")] 
         HRESULT EndCellEdit(long nRow, long nColumn, ICell*);
      [id(6), helpstring("Raised after cell content is updated")] 
         HRESULT CellUpdated(long nRow, long nColumn, ICell*);
   };

我使用 **Microsoft Visual Basic 6.0** 测试了这个 DLL。存档中包含了我用于测试此 ActiveX 控件的 VB 项目。

此控件不依赖于 MFC。

历史

  • 发布日期:2000 年 3 月 28 日

  • 更新日期:2000 年 4 月 12 日

    • 添加了 DataType_OptionDataType_StrictOption,它们使用组合框和下拉列表进行编辑。
    • 为每列的值添加了“范围规范”。这将为用户在网格单元格中输入的值提供更好的控制。
    • ReadOnly 属性可用于列和整个网格。
    • 添加行或列时,我们可以选择性地接收对已添加对象(行或列)的引用,以便我们可以立即更改其属性。
    • 添加了一些事件触发。
    • 错误修复。
  • 更新日期:2000 年 4 月 28 日

    • 添加了排序功能。双击列标题会根据该列对网格内容进行排序(如果允许该列排序)。F5 键可用于重新排序。
    • 错误修复。
  • 更新日期:2000 年 5 月 16 日

    • 添加了三个事件:BeginCellEditEndCellEditCellUpdated
    • 修复了错误(包括截至 2000 年 5 月 16 日在评论中报告的错误)。
  • 更新日期:2000 年 5 月 18 日

    • 添加了事件 ValueNotInRange,当用户输入的价值不在指定范围内时会触发该事件。
    • 错误修复。
© . All rights reserved.