分类: C/C++
2008-08-04 09:33:40
一、窗口如何分割
切分窗口既适用于SDI应用程序,也适宜于MDI应用程序。它通常驻是以类 CSplitterWnd来表示,对 Windows 来说,CSplitterWnd
是一个真正的窗口,它完全占用框架窗口的客户区域而视图占用切分窗口的窗格区域。 动态切分与静态切分
动态切分允许用户须任何时候对窗口进行切分,用户既可以通过选取菜单也可以通过拖动滚动条中的切分框来进行切分。动态切分窗口使用的是一个视图类。
静态切分,当窗口第一次被创建时,窗格就已经被切他好了,它们不能再被改变。用户可以移动窗格边框,但此时不能再对窗口进行合并或再划分。静态切分窗口允许使用多个视图类,并且可以创建时对这些视图类进行配置。在静态切分窗口中,每个窗格都有自己的滚动条。
动态切分比较简单,不实用,下面看静态切分。
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { CRect rect; GetClientRect(&rect); m_wndSplitter1.CreateStatic(this,1,2); m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CClassTreeView),CSize(150,150),pContext); m_wndSplitter2.CreateStatic(&m_wndSplitter1, 2,1,WS_CHILD|WS_VISIBLE, m_wndSplitter1.IdFromRowCol(0,1)); m_wndSplitter2.CreateView(1,0,RUNTIME_CLASS(CDagDetialView),CSize(0,0),pContext); m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CDagView),CSize(0,0),pContext); m_wndSplitter2.SetRowInfo(0,rect.Height()/2,0); return true; //重载时不能调用基类的OnCreateClient() }以上是本程序DEMO使用的方法。关于切分详细信息,请查阅MSDN.
CMainFrame* pFrame=static_cast(AfxGetMainWnd());//茯得主框架 CDagDetialView* pDagDetialView = static_cast (pFrame->m_wndSplitter2.GetPane(1,0));
以上有一点,我觉得最好采用以上形式,虽说通过C的强制转换语法也行,但最好还是使用C 的语法比较好。
茯得视图指针后你就可以do anything that you want to do
顺便说一下,通信细节有一些牵连到效率的地方,一定要妥善处理。上面的demo程式,没有考虑过多。因为我觉得这比较适合大家看明白意思,如果程式模块分散开来,程式看起来是简洁了不少,但不太方便看清程序流程。请见谅。
三、列表视图的操作及事件处理
说句实话,列表的属性参数很多,标准的、扩展的风格参数一大堆,看看那些英文文档,在其中苦苦搜寻,找一条自己需要的特性,其中的滋味别提了。还好我很有耐心:)熟练了就好了,都记住了一大半,还怕什么。列表控件显示数据,要用LVS_REPORT风格,比较好看,就像DataGrid一样。设置窗口风格需要用SetWindowLong这个API函数。这个函数是通用的。参数也一大堆。处理列表的单击事件即是处理消息NM_CLICK,处理选择改变时的事件即是处理LVN_ITEMCHANGED,不同的消息可能参数不同,需区别对待。
void CDagView::OnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here CListCtrl& refListCtrl=GetListCtrl(); if(pNMListView->uNewState&LVIS_SELECTED) …//选取列表项时,事件触发 pResult=0; }同样的方法处理单击,双击等事件,不再嗷述。
pRS->MoveFirst(); _variant_t var; CString strTableName,strTableCode; HTREEITEM hChildItem; while(!pRS->adoEOF) { var=pRS->GetCollect("menucode"); if(var.vt != VT_NULL) strTableCode = (LPCSTR)_bstr_t(var); //此即函数递归出口 if(!strTableCode.Find(strParent,0) && strTableCode.GetLength()==strParent.GetLength() 2) { hChildItem=refTree.InsertItem(strTableName,hTreeNode,TVI_LAST); InitTree(refTree,hChildItem,strTableCode); } pRS->MoveNext(); }递归时充分利用树形结构的特点。然后结合递归思想,融合在一起,就行了。这里就是理论和实际的结合点。不同的开发语言提供的操作接口是不同的,如Delphi、.dotnet。我呈在在.net也实现了一个类似的树,算法思想一样,只是具体操作不同,因为dotnet提供的接口不同。
void CClassTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; // TODO: Add your control notification handler code here CTreeCtrl& refTreeCtrl=GetTreeCtrl(); HTREEITEM hSelected=pNMTreeView->itemNew.hItem; if(hSelected!=NULL) { m_strMenuName=refTreeCtrl.GetItemText(hSelected); if(AfxGetMainWnd()->IsWindowEnabled()) UpdateDagView(); } //----------- *pResult = 0; }五、实现主从表的显示
myTable.Rows[CurrnetRowIndex][“pkey1”].ToString();当然如果你后面不是直接绑定一个DataTable,而是一个结果经过虑后的结果,那么可能会稍烦琐一点。这里不对这种情况进行计讨论。下面看一下VC下是怎么处里的,(如果有更好的方法,请通知我,先谢了)
int CDagView::GetColumnIndex(CListCtrl &ref,LPCTSTR strCol) { CHeaderCtrl * pHeader=ref.GetHeaderCtrl(); int nCount=pHeader->GetItemCount(); TCHAR lpBuffer[256]; bool fFound = false; HDITEM hdi; hdi.mask = HDI_TEXT; hdi.pszText = lpBuffer; hdi.cchTextMax = 256; int index=-1; for (int i=0;!fFound && (i < nCount);i ) { pHeader->GetItem(i, &hdi); if (strcmp(hdi.pszText, strCol) == 0) { index=i; fFound = true; } } return index; } iSubItem=GetColumnIndex(refListCtrl); CString strValue=refListCtrl.GetItemText(iCurrent,iSubItem);先取得列号然后取得行号,最后取这个值......好了,就写这么多吧,具体细节再看代码。