⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 choosedirectory.cpp

📁 VC源代码大全(精华版)
💻 CPP
字号:
// ChooseDirectory.cpp : implementation file
//

#include	"stdafx.h"
#include	"resource.h"
#include	"ChooseDirectory.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CChooseDirectory dialog

//	DirPath will hold the selected path when the dialog is closed.
//	This object is created in the caller function and will not be
//	destructed until it goes out of scope in that function.
//
CChooseDirectory::CData::CData()
{
	m_DirPath = _T("");
	m_OldPath = _T("");

}

// delete the DirPath member
CChooseDirectory::CData::~CData()
{
}

CChooseDirectory::CChooseDirectory(CData& Data, char *Title /*NULL*/, CWnd* pParent /*=NULL*/)
	: CDialog(CChooseDirectory::IDD, pParent), m_Data (Data)
{
	//{{AFX_DATA_INIT(CChooseDirectory)
	m_CurrentSelection = _T("");
	//}}AFX_DATA_INIT
	m_level = 0;
}

CChooseDirectory::~CChooseDirectory()
{
}

void CChooseDirectory::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CChooseDirectory)
	DDX_Control(pDX, IDC_DIRECTORYTREE, m_DirTree);
	DDX_Text(pDX, IDC_CURRENTSELECTION, m_CurrentSelection);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CChooseDirectory, CDialog)
	//{{AFX_MSG_MAP(CChooseDirectory)
	ON_BN_CLICKED(IDHELP, OnHelp)
	ON_NOTIFY(TVN_ITEMEXPANDED, IDC_DIRECTORYTREE, OnItemexpandedDirectoryTree)
	ON_NOTIFY(TVN_SELCHANGED, IDC_DIRECTORYTREE, OnSelchangedDirectoryTree)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChooseDirectory message handlers


BOOL CChooseDirectory::OnInitDialog() 
{
	CDialog::OnInitDialog();

	CWaitCursor cw;
	// TODO: Add extra initialization here

	m_Images.Create (IDB_DRIVEIMAGES, 20, 1, RGB(0x00, 0x80, 0x80));
	m_DirTree.SetImageList (&m_Images, TVSIL_NORMAL);

	LoadTree ();
//	HTREEITEM RootNode = m_DirTree.GetRootItem ();

	if (!m_Data.m_OldPath.IsEmpty())
		SelectStartDir ((char *)(LPCSTR) m_Data.m_OldPath);
	return (true);	// return TRUE unless you set the focus to a control
					// EXCEPTION: OCX Property Pages should return FALSE
}

void CChooseDirectory::OnOK() 
{
char	*s, NewPath[_MAX_PATH];
//
//	Get the results of our dialog
//
	GetDlgItemText (IDC_CURRENTSELECTION, NewPath, _MAX_PATH);
//
//	Remove any trailing backslash
//
	s = NewPath + strlen (NewPath) - 1;
	if (*s == '\\')
		*s = '\0';
	m_Data.m_DirPath = NewPath;
	CDialog::OnOK();
}

void CChooseDirectory::OnHelp() 
{
	// TODO: Add your control notification handler code here
	
}

void CChooseDirectory::SelectStartDir(char * StartDir)
{
TCHAR	*startDir, Drive[32];
char	*s;
HTREEITEM	RootNode, node;

	if (!strlen (StartDir))
		return;
//
//	Make a copy of the directory string.
//
	startDir = new char [strlen (StartDir) + 1];
	strcpy (startDir, (LPCSTR) StartDir);
//
//	Make sure the path contains no forward slashes.
//
	while ((s = strchr (startDir, '/')) != NULL)
		*s = '\\';

	s = strtok (startDir, "\\");
	if (s == NULL)
	{
		s = startDir;
	}
//
//	Make it all upper case. Less confusion that way. Our first node
//	should be the device. Append the trailing backslash, which is the
//	way the node is returned from BuildPath
//
//
	strupr (s);
	sprintf (Drive, "%s\\", s);

//	Get the root node
	RootNode = m_DirTree.GetRootItem ();
//	Get the first child item of the root node
	node = m_DirTree.GetNextItem(RootNode, TVGN_ROOT);
//
//	Loop through the siblings until we find our drive
//
	for (; node; node = m_DirTree.GetNextItem(node, TVGN_NEXT))
	{
		CString ItemText;
		BuildPath (ItemText, node);
//
//	If the root paths match, we've found it
//
		if (!strcmpi (Drive, (LPCSTR) ItemText))
			break;
	}
//
//	Did we find the start for our directory?
//
	if (node == NULL)
	{
		delete [] startDir;
		return;
	}
//
//	Select this item just in case the next strtok is NULL
//
	m_DirTree.Select (node, TVGN_CARET);
	s = strtok (NULL, "\\");			// Get the next part of the path
	if (s == NULL)						// If none, we are finished.
	{
		delete [] startDir;
		return;
	}
//
//	There's more to look for, so expand this item.
//
	m_DirTree.Expand (node, TVE_EXPAND);		// Always expand
	while (s != NULL)
	{
		for (node = m_DirTree.GetNextItem(node, TVGN_CHILD);
			 node;
			 node = m_DirTree.GetNextItem(node, TVGN_NEXT))
		{
			CString ItemText = m_DirTree.GetItemText (node);
			if (!ItemText.CompareNoCase (s))
				break;
		}
//
//	If the node was not found, we can't continue. Leave the current
//	selection as it is.
//
        if (node == NULL)
			break;
//
//	Select the current item.
//
		m_DirTree.Select (node, TVGN_CARET);
		s = strtok (NULL, "\\");
//	If the next token is not null, expand the current item.
		if (s != NULL)
			m_DirTree.Expand (node, TVE_EXPAND);		// Always expand
	}
	delete [] startDir;
}

void CChooseDirectory::OnItemexpandedDirectoryTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	
// get the node that was expanded or contracted
	HTREEITEM node = pNMTreeView->itemNew.hItem;

//	Get the Tree Item for the node. Zero out the new structure. Tree control
//	functions don't like stray data.
	TV_ITEM item;
	memcpy ((char *) &item, (char *) &pNMTreeView->itemNew, sizeof (TV_ITEM));

//	if the node was contracted then set the item data so that
//	later we know not to rebuild the node.
	if (pNMTreeView->action == TVE_COLLAPSE)
	{
		item.mask = TVIF_PARAM;
		item.lParam = CChooseDirectory::tmExpanded;
		m_DirTree.SetItem(&item);
		return;
	}

// If the node was already built once then we don't need to do
// it again. If we do, we'll have duplicate entries
	if (item.lParam == CChooseDirectory::tmExpanded)
		return;

// remove the first child because we're going to add it again
// remember that we have to have already added one child per
// node so that the plus sign gets added to the node
	HTREEITEM child = m_DirTree.GetChildItem(node);
	if (child)
		m_DirTree.DeleteItem(child);

// add this node and all subnodes
	AddNode(0, node, 0, CChooseDirectory::tmDetail);

	*pResult = 0;
}

void CChooseDirectory::OnSelchangedDirectoryTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

//	get the selected node
	HTREEITEM sel = m_DirTree.GetSelectedItem();
	CString s;
//	build the path name based on the selection
	BuildPath(s, sel);
//	set the static control's text to the complete path
	m_CurrentSelection = s;
	UpdateData (FALSE);

	*pResult = 0;
}

//	BuildPath() builds the path name by recursing backward
//	through the tree.
//
void CChooseDirectory::BuildPath(CString& path, HTREEITEM node)
{

// get the parent of the current node
	HTREEITEM parent = m_DirTree.GetParentItem(node);

//	Get the text of the node. We'll use it to build the path
	CString buff = m_DirTree.GetItemText (node);

// add the backslash to the node
	buff += "\\";

//	Add (prepend) the path to the current directory name, the set the
//	path to the new value. This prepends the current directory to the
//	path (we're stepping backwards through the directory tree).
//
	buff += path;
	path = buff;

//	If this node has a parent then we recurse until no parent is found.
//	If there is no parent, then we are finished building the path.
//
	if (parent)
	{
		BuildPath(path, parent);
	}
	else
	{
//	If the parent is found then we need to strip the volume name
//	from the string. It is enclosed in parentheses, so look for the
//	first open paren and pick up the left side, then find the first
//	close paren and pick up the right part.
//
		CString dPath = path;
		int		Length = path.GetLength ();
		int pos = dPath.Find("(");
		if (pos > 0)
			path = dPath.Left (pos - 1);
		pos = dPath.Find (")");
		if (pos > 0)
			path += dPath.Right (Length - pos - 1);
	}
}

void CChooseDirectory::LoadTree()
{
char			drives [_MAX_PATH];
char *aDrive, *s;	//	= drives;
HTREEITEM		RootNode = m_DirTree.GetRootItem ();

//	Get the drive string. This is a double null terminated list, with
//	each item terminated with a null.
//
	if (::GetLogicalDriveStrings(_MAX_PATH, drives))
	{
	char	CurDrive[64];		//	We need the copy because we are going to
								//	remove any trailing backslash, which would
								//	screw up our double null terminated list.
		aDrive = drives;
//	Parse the drives
		do
		{
		UINT	type;
//	Get a drive
			strcpy (CurDrive, aDrive);
			type = ::GetDriveType(CurDrive);

			if ((s = strchr (CurDrive, '\\')) != NULL)
				*s = '\0';
//	Make sure the drive letter is caps and add the node for the drive.
			strupr (CurDrive);
			AddNode(CurDrive, RootNode, type, CChooseDirectory::tmShort);
				aDrive += strlen (aDrive) + 1;
		} while(strlen (aDrive));
	}
}

//	AddNode(). This function adds the nodes to the tree. The first
//	time we display a node we don't want to add each and every
//	sub-directory to the tree. We only want to add nodes when
//	necessary or it will take forever for the dialog box to come
//	up initially. But, we have to add at least one node so that
//	the + sign shows up indicating that sub-directories exist.

void CChooseDirectory::AddNode (const char * path, HTREEITEM node, int type, int mode)
{
WIN32_FIND_DATA fd;
HANDLE					hFind;
char					buff [_MAX_PATH];	//	temporary storage
HTREEITEM				newNode = node;		//	May be used to build pathname without
											//	adding any new nodes.

//	Image 0 is the unselected folder image and Image 1 is the
//	selected node image.
	int image1 = 0, image2 = 1;

//	We need a string object to build the directory path
	CString dirPath;

//	If a node name was passed to us then we will add the node.
//	Otherwise, we need to get a directory name first and then recurse.
//
	if (path)
	{

//	if the mode indicates that we are adding a drive node
//	then we need to:
//		add the drive label in parens.
//		set the image to correspond to the type of drive...
//		reset the mode to tmShort (actually, on fast machines this
//			doesn't really speed things up).
		if (type >= CChooseDirectory::dtRemovable)
		{
		char	VolName[24];
		char	RootName[10];
		DWORD	dwCompLen, dwFlags;

			sprintf (RootName, "%s\\", path);
			memset (VolName, '\0', sizeof (VolName));
			GetVolumeInformation (RootName, VolName, 24, NULL, &dwCompLen, &dwFlags, NULL, 0);
			if (strlen (VolName))
			{
				wsprintf(buff, "%s (%s)", path, VolName);
			}
			else
				wsprintf (buff, "%s", path);
			if ((type == CChooseDirectory::dtCDRom)
				&& !strcmp (VolName, "Audio CD"))
				type = CChooseDirectory::dtRamDisk;
			image1 = image2 = type;
			newNode = InsertChild (node, buff, image1, image2, TVI_LAST);
			mode = CChooseDirectory::tmShort;
		}
//	Otherwise just use the node name passed
		else
		{
			strcpy(buff, path);

//	Add the node as a child to the current node using the folder images.
//	Use the sort flag to sort the tree as we go.so the list is sorted
//	as we go.
			newNode = InsertChild (node, buff, image1, image2, TVI_SORT);
		}
	}

//	Build a path name based on the node.
	BuildPath(dirPath, newNode);
//	Add wildcards
	dirPath += "*.*";
//
//	Look for the first match. Return if none.
	if ((hFind = FindFirstFile(dirPath, &fd)) == INVALID_HANDLE_VALUE)
	{
		return;
	}
// add one to the level we are on
	m_level++;
	do
	{
		if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				&& (!(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
		{
			if (!strcmp (fd.cFileName, "."))
			{
				;		// Current directory. Do nothing.
			}
			else if (!strcmp (fd.cFileName, ".."))
			{
				;		// Parent directory. Do nothing.
			}
			else
			{

//	If the are building the intial tree structure (tmShort) or we are
//	expanding a level (tmDetail), add the node by recursion.
				if (((mode == CChooseDirectory::tmShort)
						&& (m_level < 2))
						|| (mode == CChooseDirectory::tmDetail))
					AddNode(fd.cFileName, newNode, 0, mode);	// type, 0);	// mode);

//	If we're building the initial structure, we want to add only one
//	subnode to make the plus symbold appear.
				if (mode == CChooseDirectory::tmShort)
					break;

//	In the detail mode we need to fill this branch completely
//	but only one sub-node per node under this branch. Again,
//	we have to do this so the + sign shows up next to the node.
				if (mode == CChooseDirectory::tmDetail && m_level > 1)
				{
					break;
				}
			}
		}
	} while (::FindNextFile (hFind, &fd));		// Look for the next match
	FindClose (hFind);

// decrement the level counter
	m_level--;
}

//
//	InsertChild() inserts a new node in the tree as a child of the node
//	passed as the parent.Images default to 0 and SortType default to TVI_SORT
//
HTREEITEM CChooseDirectory::InsertChild (HTREEITEM parent, char *label, int image, int selimage, HTREEITEM SortType)
{
TV_INSERTSTRUCT	TreeItem;

//
//	Zero out the new structure. CTreeCtrl doesn't like stray data.
//
	memset ((char *) &TreeItem, '\0', sizeof (TV_INSERTSTRUCT));
	TreeItem.hParent = parent == NULL ? TVI_ROOT : parent;
	TreeItem.hInsertAfter = SortType;
	TreeItem.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
	TreeItem.item.pszText = label;
	TreeItem.item.cchTextMax = strlen (label) + 1;
	TreeItem.item.lParam = 0;
	TreeItem.item.iImage = image;
	TreeItem.item.iSelectedImage = selimage;
	return (m_DirTree.InsertItem(&TreeItem));
}

int CChooseDirectory::DoModal(LPCSTR BeginDir) 
{
	if (BeginDir)
		m_Data.m_OldPath = (char *) BeginDir;
	return CDialog::DoModal();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -