CDialogBar的创建和使用 (转载自百度文库)

来源:互联网 发布:matlab矩阵点乘 编辑:程序博客网 时间:2024/04/29 10:56

一个朋友让我看一个关于DialogBar的程序,问题是在一个DialogBar中添加一个Tree Control控件,在初始化函数OnInitDialog中使用InsertItem添加一项,结果运行后,始终在DialogBar中显示不出来,后来我又加入了一个Button测试,结果Button是灰色的,根本不能点击。在OnInitDialog中加入断点,程序根本执行不到这个函数。按理说,界面已经显示出来了,早应该调用OnInitDialog函数了。当时百思不得其解。

后来在网上查了一下,才知道CDialogBar根本没有重载OnInitDialog这个函数(你查一下MSDN,就知道CDialog是重载了这个函数的),所以导致我虽然有这个函数,但是始终不调用。这就需要我手动添加这个消息映射。我通过ON_MESSAGE宏,映射了这个消息响应函数,运行结果没问题,Tree Control中有我添加的项了。

剩下的就是Button不能用的问题了。通过网上和自己试验,知道在DialogBar中,Button发出的消息根本就不通过DialogBar,而是直接发到MainFrame中,所以只要在MainFrame中进行响应或者把消息再转发到DialogBar中就可以了。我在CMainFrame类中重载了OnCmdMsg这个函数,在这个函数中,先用DialogBar去拦截消息,这样,只需要在DialogBar中取相应Button的消息就可以了。

下面是我做试验的大致过程:

1创建一个单文档的MFC工程,名为MyDialogBar

2要使用DialogBar,当然首先要在ResourceView中添加一个DialogBar了。添加好了DialogBarID采用默认的IDD_DIALOGBAR,至于它的properties,就采用默认的好了。

3添加一个Tree ControlIDIDC_TREE,在它的properties对话框Styles选项卡中选择Has buttonsHas linesLines at root三个选项,看起来就比较正常了。

4然后为这个DialogBar添加一个类,类名为CDlgBar,继承自CDialog,因为在向导中没有CDialogBar这个基类。然后把它的WM_INITDIALOG消息响应函数加上,记住这时我们的DialogBar还是一个CDialog的子类呢。然后给Tree Control映射变量m_tree

5下面就轮到对我们自己的DialogBar动手脚了。

1)首先中把CDlgBar的基类改成CDialogBar,然后在.cpp文件中,把CDialogBar的构造函数的对CDialog的构造函数去掉,即:

CDlgBar::CDlgBar(CWnd* pParent/*=NULL*/):CDialog(CDlgBar::IDD, pParent)修改为

CDlgBar::CDlgBar(CWnd* pParent /*=NULL*/)

2)然后把DoDataExchange函数中的CDialog::DoDataExchange(pDX);一句改成CDialogBar::DoDataExchange(pDX);

3)把BEGIN_MESSAGE_MAP(CDlgBar,CDialog)中的CDialog改成CDialogBar

4)把OnInitDialog函数中的CDialog::OnInitDialog();一句去掉。

6OnInitDialog中添加向TreeControl中插入数据的语句:

BOOLCDlgBar::OnInitDialog()

{

HTREEITEM hParent =m_tree.InsertItem("parent");

m_tree.InsertItem("boy",hParent);

m_tree.InsertItem("girl",hParent);

return TRUE; // return TRUE unless you setthe focus to a control

// EXCEPTION: OCX Property Pages should returnFALSE

}

7CMainFrame中添加一个变量:CDlgBar m_wndDlgBar;,当然不能忘了include进头文件DlgBar.h。然后在它的OnCreate函数中创建DialogBar。添加如下语句:

if(!m_wnd DlgBar.Create(this, IDD_DIALOGBAR, WS_CHILD |WS_VISIBLE |

CBRS_LEFT | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |

CBRS_SIZE_DYNAMIC, IDD_DIALOGBAR))

{

TRACE0("Failed to create dialogbar\n");

return -1; // fail to create

}

m_wndDlgBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_wndDlgBar);

这是你可以运行一下,就会看到DialogBar虽然已经加入了,但是里面的tree control中什么都没有。在CDlgBarOnInitDialog函数中设置断点,调试,也进入不到这个函数中。

8这时,你可以在CDlgBar中为WM_INITDIALOG消息映射我们的OnInitDialog函数。这样,当WM_INITDIALOG消息发送到CDlgBar中就可以响应了。

BEGIN_MESSAGE_MAP(CDlgBar,CDialogBar)

//{{AFX_MSG_MAP(CDlgBar)

ON_MESSAGE(WM_INITDIALOG, OnInitDialog)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

这时,你运行一下,就会看到一个断言错误。

OnInitDialog函数中一开始添加UpdateData(FALSE);,这时你再运行,就会看到我们的tree control中有东西了。

那么这个UpdateData(FALSE);到底干了什么呢?MSDN上说当参数为FALSE时,会调用DoDataExchange函数,对控件进行初始化,当参数为TRUE时,从控件中获取值。

9ResourceViewDialogBar中添加一个按钮,IDIDC_BTN_TEST,并添加单击响应函数OnBtnTest。里面使用MessageBox(“OK”)来表示响应单击消息。

运行一下,可以看到,按钮是灰色的。

10原因是Button的消息发送到了MainFrame,到底有些什么消息,我还不是很清楚。这个问题的解决方法就是在CMainFrame中重载一个函数OnCmdMsg,并在这里面拦截消息发送到我们的CDlgBar中。

BOOLCMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo)

{

if(m_wndDlgBar.OnCmdMsg(nID, nCode, pExtra,pHandlerInfo))

{

return TRUE;

}

return CFrameWnd::OnCmdMsg(nID, nCode,pExtra, pHandlerInfo);

}

运行一下我们的程序,就可以看到没有问题了。

11顺便添加一个tree control的选择消息TVN_SELCHANGED响应函数。在向导里面,选择IDC_TREE,添加它的TVN_SELCHANGED响应函数OnSelchangedTree。如下代码:

voidCDlgBar::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult)

{

NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

HTREEITEM hSelItem = pNMTreeView->itemNew.hItem;//选择的项

CStringstrSelText = m_tree.GetItemText(hSelItem);

MessageBox(strSelText);

*pResult = 0;

}

图标创建

CImagelist*m_imagelist;
m_imagelist=newCImageList();
m_imagelist->Create(16,16,TRUE,2,2);

// BOOLCreate(intcx,intcy,UINTnFlags,intnInitial,intnGrow);

nInitial 创建的图标个数

nGrow 一般等于nIntial

HICON hIcon;

HTREEITEM htem;

TV_INSERTSTRUCT Instru;

hIcon=AfxGetApp()->LoadIcon(IDI_ICON2);

m_imagelist->Add(hIcon);

hIcon=AfxGetApp()->LoadIcon(IDI_ICON1);

m_imagelist->Add(hIcon);

m_treeList.ShowWindow(SW_HIDE);

m_treeList.SetImageList(m_imagelist,TVSIL_NORMAL);

htem=m_treeList.InsertItem("北京太格服务器",0,0);

m_treeList.InsertItem("北京太格通道一",1,1,htem);//参数2.图标索引.参数3.TreeList项目被选中是显示的图标索引,参数4.父节点

m_treeList.InsertItem("北京太格通道二",1,1,htem);

// HTREEITEMInsertItem(LPTVINSERTSTRUCTlpInsertStruct);

//HTREEITEM InsertItem(LPCTSTRlpszItem, HTREEITEM hParent = TVI_ROOT,HTREEITEMhInsertAfter = TVI_LAST );

//HTREEITEM InsertItem(LPCTSTRlpszItem, int nImage, int nSelectedImage,HTREEITEM hParent = TVI_ROOT, HTREEITEMhInsertAfter= TVI_LAST);

// HTREEITEMInsertItem(LPTVINSERTSTRUCTlpInsertStruct);

Instru.hParent=NULL;

Instru.item.iImage=0;

Instru.item.iSelectedImage=0;

Instru.item.mask=TVIF_CHILDREN|TVIF_IMAGE|TVIF_TEXT;

Instru.item.pszText="测试服务器";

m_treeList.InsertItem(&Instru);

m_treeList.SetBkColor(RGB(193,255,255));

m_treeList.SetTextColor(RGB(255,0,0));

主要用到的类有:CListCtrl,CTreeCtrl,CImageList,CFileFind和函数SHGetFileInfo()
简述步骤如下:
1
、增加 TreeCtrl TVS_HASBUTTONSTVS_HASLINESTVS_LINESATROOT Style,代码如下:
   DWORD dwStyle =GetWindowLong(m_tree.m_hWnd,GWL_STYLE);
   dwStyle |= TVS_HASBUTTONS | TVS_HASLINES |TVS_LINESATROOT;
   SetWindowLong(m_tree.m_hWnd,GWL_STYLE,dwStyle);
2
、为TreeCtrl添加Root项:
   m_hRoot = m_tree.InsertItem("我的电脑");
   InsertItem()的函数原形为
   HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEMhParent = TVI_ROOT,
   HTREEITEM hInsertAfter = TVI_LAST );

3、获取本地逻辑驱动器,并添加:

void CTreeViewDlg::GetLogicalDrives(HTREEITEM hParent)
   {
   size_t szAllDriveStrings =GetLogicalDriveStrings(0,NULL);
  char *pDriveStrings = new char[szAllDriveStrings +sizeof(_T(""))];
  GetLogicalDriveStrings(szAllDriveStrings,pDriveStrings);
  size_t szDriveString = strlen(pDriveStrings);
  while(szDriveString 0)
  {
  m_tree.InsertItem(pDriveStrings,hParent);
  pDriveStrings += szDriveString + 1;
  szDriveString = strlen(pDriveStrings);
  }
   }

4、添加TVN_EXPANDED消息处理函数,当一项展开时,为其子项添加下一级目录:

voidCTreeViewDlg::OnItemexpandedTree(NMHDR* pNMHDR, LRESULT* pResult)
   {
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  // TODO: Add your control notification handler codehere
  TVITEM item = pNMTreeView-itemNew;
  if(item.hItem == m_hRoot)
  return;
   HTREEITEM hChild = m_tree.GetChildItem(item.hItem);
  while(hChild)
  {
  AddSubDir(hChild);
  hChild = m_tree.GetNextItem(hChild,TVGN_NEXT);
  }
  *pResult = 0;
   }
AddSubDir
函数功能添加子项,具体代码见示例。

5、添加TVN_SELCHANGED消息处理函数,在这个函数里,GetFullPath()取得选中项的绝对路径(GetFullPath()具体代码看示例),ListCtrl中添加文件而非文件夹的图标:

voidCTreeViewDlg::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult)
   {
  m_list.DeleteAllItems();
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  TVITEM item = pNMTreeView-itemNew;
  if(item.hItem == m_hRoot)
  return;
  CString str = GetFullPath(item.hItem);
   if(str.Right(1) != "\\")
   str += "\\";
  str += "*.*";
  CFileFind file;
  BOOL bContinue = file.FindFile(str);
  while(bContinue)
  {
  bContinue = file.FindNextFile();
  if(!file.IsDirectory() && !file.IsDots())
  {
   SHFILEINFO info;
  CString temp = str;
  int index = temp.Find("*.*");
  temp.Delete(index,3);
   SHGetFileInfo(temp + file.GetFileName(),
   0,
   &info,sizeof(&info),
   SHGFI_DISPLAYNAME | SHGFI_ICON);
   int i = m_ImageList.Add(info.hIcon);
   m_list.InsertItem(i,info.szDisplayName,i);
  }
  }
  *pResult = 0;
   }
  这只是一个简单的例子,你可以在 ListCtrl 中添加鼠标双击消息的处理函数, Process 打开该选中的文件;  该示例在VC6,xp下编译通过。