非模态(Modalless)对话框,又叫做无模式对话框,当用户打开非模态对话框时,依然可以操作其他窗口。非模态对话框允许用户在处理非模态对话框的同时处理目标对话框。上次的练习已经说明了Modalless与Modal的区别,此处就不赘述。
这次将做一个窗口使看见某目录下的文件,以C盘为例。
Ⅰ、创建对话框类并且添加控件
1>在Resource的IDR_DIALOGTYPE里,在“查看”里添加菜单项,取名“非模态对话框(&E)”
2>如下创建对话框,并设置相关属性
ID | 控件 | 属性 |
---|---|---|
IDC_TREE | Tree Control | 选中Has buttons、Has lines和Lines at root |
IDC_LIST | List Control | Styles|View: Report |
IDC_OK | Button | Caption:OK |
IDC_CANCEL | Button | Caption:Cancel |
Ⅱ、显示非模态对话框
由于模态对话框生存周期较长,通常和父级窗口一样长。为此,我们使用非模态对话框指针,在父级窗口类的构造函数当中或菜单响应函数中动态为指针分配空间并显示对话框。最后记得在CDialogView的析构函数当中释放指针的空间。
1>在DialogView.h里添加#include "DialogModalless.h"
2>在CDialogView里Add member variable,添加类型为CDialogModalless*,名称为m_pModallessDlg
3>按下Ctrl+W,并在Class name里选CDialogView,在Object IDs里选ID_VIEW_MODALLESSDIALOG,在Message里选COMMAND,最后以默认函数名Add Function并进行Edit Code。相关代码如下:
void CDialogView::OnViewModallessdialog()
{
// TODO: Add your command handler code here
if(NULL == m_pModallessDlg)
{
m_pModallessDlg = new CDialogModalless;
m_pModallessDlg->Create(IDD_MODALLESS_DIALOG,this);
}
m_pModallessDlg->ShowWindow(SW_SHOW);//显示非模态对话框
}
4>修改视类的构造与析构函数
CDialogView::CDialogView()
{
// TODO: add construction code here
m_pModallessDlg = NULL;
}
CDialogView::~CDialogView()
{
if(NULL == m_pModallessDlg)
delete m_pModallessDlg;
}
Ⅲ、实现对话框功能
1>为之前添加的相关控件添加变量如下
控件 | Type | Member |
IDC_LIST | ClistCtrl | m_List |
IDC_Tree | CteeCtrl | m_Tree |
2>按下Ctrl+W,在Class name里选中CDialogModalless,在Object IDs里选中CDialogModalless,在Message里选中WM_INITDIALOG,最后Add Function
3>在Object IDs里选中ID_OK、ID_CANCEL和IDC_TREE,在Message里分别选中BN_CLICKED(OK与CANCEL)与TVN_SELCHANGED,添加OnOK()、OnCancel()和OnSelchangedTree()函数。相关代码添加如下:
BOOL CDialogModalless::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
//往List控件中加入一列
m_List.InsertColumn(0,"文件名",LVCFMT_LEFT,150,-1);
TV_INSERTSTRUCT TreeItem;
HTREEITEM hTreeItem;
TreeItem.hInsertAfter = TVI_LAST;
TreeItem.item.mask = TVIF_TEXT|TVIF_PARAM;
//第一级
CString str = "C:\\";
TreeItem.hParent = TVI_ROOT;//父级为根部
TreeItem.item.pszText = str.GetBuffer(50);//设置缓冲区大小并赋值
TreeItem.item.lParam = 1;//对于根目录,设置为
hTreeItem = m_Tree.InsertItem(&TreeItem);//插入Tree控件
int number = 0;//计算文件个数
CFileFind file;
BOOL bfind;
CString temp;
//第二级
TreeItem.hParent = hTreeItem;
TreeItem.item.lParam = 10;//对于子目录,设置为10
bfind = file.FindFile("C:\\*.*");//查找C:盘下所有文件和目录
while(bfind)//发现文件
{
bfind = file.FindNextFile();//寻找下一个
if(file.IsDirectory())//判断是否为目录
{
strcpy(TreeItem.item.pszText, file.GetFileName());//拷贝目录名
hTreeItem = m_Tree.InsertItem(&TreeItem);//插入Tree插件
}
else//不是目录,插入List控件
{
temp = file.GetFileName();//获取文件名
m_List.InsertItem(number, temp);//将文件插入第number行
++number;
}
}
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDialogModalless::OnOK()
{
// TODO: Add extra validation here
CDialog::OnOK();
}
void CDialogModalless::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
CString temp,str;
//获取当前被选的tree view项
HTREEITEM CurItem = m_Tree.GetSelectedItem();
TV_ITEM TreeItem;
TreeItem.hItem = CurItem;
m_Tree.GetItem(&TreeItem);//获取指定的tree view属性
temp = m_Tree.GetItemText(m_Tree.GetSelectedItem());//获取当前条目的序号
long CurlParam = TreeItem.lParam;//当前条目序号
if (1 != CurlParam)//若为子目录
{
//获取当前被选项的父亲
TreeItem.hItem = m_Tree.GetParentItem(m_Tree.GetSelectedItem());
m_Tree.GetItem(&TreeItem);
CurItem = TreeItem.hItem;
//获取当前选中项的文本
str = m_Tree.GetItemText(CurItem);
str += temp;
str += "\\";
}
else str = temp;
m_List.DeleteAllItems();//删除控件中所有的项
CFileFind file;
BOOL bFind;
int number = 0;
str += "*.*";
bFind = file.FindFile(str);//在str目录下查找
while(bFind)//一旦找到
{
bFind = file.FindNextFile();
if(!file.IsDirectory())//判断是否为目录,不是插入List控件
{
temp = file.GetFileName();
m_List.InsertItem(number, temp);
++number;
}
}
UpdateData(false);//更新控件值
*pResult = 0;
}
void CDialogModalless::OnCancel()
{
// TODO: Add extra cleanup here
CDialog::OnCancel();
}
4>运行检测效果,记得是在多文档的“查看”菜单下运行这个非模态对话框。