另一个WTL网格






4.94/5 (36投票s)
2003年6月2日
5分钟阅读

255932

8402
一个 WTL 网格,主要用于与数据库交互。
目录
引言
我正在使用 WTL 编写一个数据库应用程序,到目前为止,我一直使用标准的列表视图来查看数据,并使用单独的对话框进行编辑。市面上有很多不同的网格,但我不太喜欢 WTL 提供的那些。并不是说它们不好,只是它们不符合我的需求。与其修补和修复任何现有的网格以满足我的需求,不如自己做一个可能更快。
关于演示的几点说明。Northwind 演示需要一个位于 localhost 上的 SQL 服务器,并且安装了 northwind 数据库,sa 帐户没有密码。您可以修改 MainFrm.h 中的连接字符串并重新编译。这些解决方案是用 Visual Studio.NET 2003 创建的,因此它们无法在旧版本中打开,但创建一个新的空项目并添加文件应该可以正常工作。
特点
- 行数仅受内存限制。
- 我在我的 2 GHz 机器上测试了 100000 行,没有出现问题。这也将取决于列的数量以及您交互的代码。不过,请记住在使用
SetRedraw
添加许多行时。 - 单元格可以使用标准的编辑控件、组合框(下拉式或下拉列表式)或
DateTimePicker
控件进行编辑。 - 专为数据库用户而设计,因此所有内容都使用
_variant_t
(字符串使用_bstr_t
)。 - 组合框使用查找值来设置列的值。ID 字段放在网格中,网格显示并编辑信息性文本字段。
还有很多其他功能我可能还会添加到这个网格中,但目前这已经足够满足我的需求了。我欢迎任何关于改进的意见和建议。
如何使用
简单用法
我将向您展示如何创建最基本的网格。这里我从一个标准的 WTL AppWizard 应用程序开始,然后用一个网格替换主窗体视图。创建网格后,我设置样式以允许在网格中右键单击时显示上下文菜单。
创建网格
CGridCtrl m_view; LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // ... m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE); m_view.SetExtendedGridStyle(GS_EX_CONTEXTMENU); // ... }
添加列
m_view.AddColumn("Last Name",140,CGridCtrl::EDIT_TEXT); m_view.AddColumn("First Name",140,CGridCtrl::EDIT_TEXT);
查找列
现在我们将添加另一列,您可以在其中输入个人的性别。在这里,您将看到我们对 AddColumn
函数使用了更多的参数。第一个新参数是 `alignment`,最后一个参数是该列使用的数据类型。默认值是 VT_BSTR
,我们已用于前两列。现在我们将性别信息存储为整数,所以我们使用 VT_I4
。
我们还告诉网格,在添加到网格的组合框中可以选择什么。
m_view.AddColumn("Sex",100,CGridCtrl::EDIT_DROPDOWNLIST, CGridCtrl::CENTER,VT_I4); m_view.AddColumnLookup("Sex",1,"Male"); m_view.AddColumnLookup("Sex",2,"Female");
现在我们应该有一个网格,可以在其中输入一个人的姓氏、名字和性别。
添加行
您可以通过调用 AddRow
和 SetItem
来添加行。在此示例中,我在添加行之前和之后都使用了 SetRedraw
。仅添加一行时,这并非必需,但添加多行时这是必须的。
m_view.SetRedraw(FALSE); long nItem = m_view.AddRow(); m_view.SetItem(nItem,"Last Name","Henden"); m_view.SetItem(nItem,"First Name","Bjørnar"); m_view.SetItem(nItem,"Sex",1); m_view.SetRedraw(TRUE);
事件呢?
为了捕获事件,我创建了一个名为 CListener
的类,您可以继承它。此类不仅用于事件,还用于查询单元格背景颜色的信息。
class CListener { public: virtual bool OnRowChanging(UINT uID,long nRow); virtual void OnRowChanged(UINT uID,long nRow); virtual void OnEdit(UINT uID,long nRow); virtual bool OnDeleteRow(UINT uID,long nRow); virtual void OnNewRow(UINT uID,long nRow); virtual void OnModified(UINT uID,LPCTSTR pszColumn,_variant_t vtValue); virtual void OnRowActivate(UINT uID,long nRow); virtual COLORREF GetCellColor(UINT uID,long nRow,LPCTSTR pszColumn); virtual bool OnValidate(UINT uID); };
以下示例将向您展示如何在从网格中删除行时收到通知,并为已修改的行设置新的背景颜色。
首先,使 CMainFrame
继承自 CGridCtrl::Clistener
,然后重写您想要的函数。
class CMainFrame : public CFrameWindowImpl<CMainFrame>, ..., public CGridCtrl::CListener LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // ... m_view.SetListener(this); // ... } virtual bool OnDeleteRow(UINT uID,long nRow) { CString str; str.Format("Do you want to delete row %d?",nRow); // Returning false will abort the delete return IDYES==AtlMessageBox(m_hWnd,(LPCTSTR)str, IDR_MAINFRAME,MB_YESNO|MB_ICONQUESTION); } virtual COLORREF GetCellColor(UINT uID,long nRow,LPCTSTR pszColumn) { _variant_t vt = m_view.GetItem(nRow,"Sex"); if(!m_view.IsNull(vt)) { if((long)vt==1) // Blue-ish for males return RGB(192,192,255); else // And red-ish for females return RGB(255,192,192); } // Return (COLORREF)-1 to use default colors return (COLORREF)-1; }
函数参考
这是一个简短的函数参考。我只列出函数名,以及它功能的简短描述。
void AddColumn()
向网格添加列。如果网格中有行,则无法添加列。此函数的最后一个参数是列的名称,可用于其他函数的参数。如果省略,则使用列标题作为名称。
void AddColumnLookup()
向列添加查找值。这不一定是使用下拉列表的列,也可以是任何列。
long AddRow()
向网格添加一行并返回插入的行号。使用此返回值来设置此行上各个单元格的值。
void ClearModified()
编辑单元格时,它们会将行状态设置为已修改。调用此函数可将指定行重置为未修改。将 -1 指定给所有行。
void DeleteAllColumns()
删除所有列。
void DeleteAllItems()
删除所有行。
void EnsureVisible()
将行显示在网格的可见区域。
long GetColumnCount()
返回网格中的列数。
_variant_t GetEditItem()
在编辑模式下,调用此函数可获取正在编辑的单元格之一的当前值。
_variant_t GetItem()
返回行和单元格的值。
bool GetModified()
如果行已被修改,则返回 true
。将 -1 指定给所有行。
long GetRowCount()
返回网格中的行数。
long GetSelectedRow()
返回所选行的编号,如果没有选定行,则返回 -1。
bool IsNull()
一个静态函数,可用于检查 _variant_t
是否为 null。对于 VT_NULL
和 VT_EMPTY
,返回 true
。
BOOL PreTranslateMessage(MSG* pMsg)
应从主框架的 PreTranslateMessage
函数中调用此函数。没有它,单元格之间的 Tab 键将不起作用。如果您在模态对话框中使用此网格,Tab 键也将不起作用,因为无法调用 PreTranslateMessage
。将对话框模型化为非模态,并禁用父窗口。
void SetColumnFocus()
将焦点设置到列。仅在编辑模式下有效。当字段验证失败,并且您想聚焦缺失值时,此功能很有用。
void SetItem()
设置单元格的值。
void SetListener()
必须设置为继承自 CGridCtrl::CListener
的类。
void SetNull()
静态函数,可用于将 _variant_t
的值设置为 null。