CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170

    Question MFC:dynamically create a file list in a submenu?

    Hello, I am trying to make a submenu to display at runtime a list of unknown number of files. The files are contained in a directory specified at compile time. I want this to look like the Windows Start>>Documents menu where the user can pick the file off the menu and have it open. How can I do this using MFC?

    Thank you!

    Jim

  2. #2
    Join Date
    Jun 2002
    Posts
    1,417
    That could potentially be a very huge menu!! What happens when there are several hundred or maybe even thousands of files names in the menu?

  3. #3
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    I'll worry about that later, right now I need to see if it can be done and how. We're still in the first phases of the project. But for the sake of argument, lets say I limit them to 20 files.

    thanks!

  4. #4
    Join Date
    Jun 2002
    Posts
    1,417
    start with the CMenu class and work from there. When the user selects the main menu item, for example File, then generate the list of files and dynamically create the new menu with the CMenu object. You'll have to read MSDN about that class and search MSDN downloads or the MSDN CD that came with your compiler for examples. You might also look at www.codeproject.com for examples.

  5. #5
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    I think the difficult part for me is I don't know how to get a directory list. I have tried using the CListBox:ir() and the CComboBox:ir thinking that once I get the directory listing I can access them one at a time and populate a menu. Another thing holding me back is CMenu needs to have a controller ID and I don't know how to create these dynamically. If I simply plug in numbers, what's to stop Class Wizard from creating dialogs with the same number? I am also dealing with the terminology; do I create a sub menu, a child menu or a pop up menu?

    Thanks for pointing me to the codeproject web page. That could be useful.

    Thanks!

    Jim

  6. #6
    Join Date
    Jun 2002
    Posts
    1,417
    I don't know why M$ did not make this part of Win32 API since it is used sooo often, but here is how to create the list of files:

    Code:
    #include <windows.h>
    #include <vector>
    #include <string>
    #include <iostream>
    using namespace std;
    
    
    
    void CreateFileList(string dirname, vector<string>& list)
    {
    	WIN32_FIND_DATA data;
    	HANDLE hFile = FindFirstFile(dirname.c_str(), &data);
    	if(hFile != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			if(!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    			{
    				// This is not a director, so must be a file
    				list.push_back(data.cFileName);
    			}
    		} while( FindNextFile(hFile, &data));
    		FindClose(hFile);
    
    	}
    
    }
    
    int main(int argc, char* argv[])
    {
    	vector<string> fileList;
    	CreateFileList("\\SomeDirectory\\*.*", fileList);
    	return 0;
    }
    Last edited by stober; January 23rd, 2003 at 04:50 PM.

  7. #7
    Join Date
    Jun 2002
    Posts
    1,417
    Originally posted by xucaen
    . Another thing holding me back is CMenu needs to have a controller ID and I don't know how to create these dynamically. If I simply plug in numbers, what's to stop Class Wizard from creating dialogs with the same number? I am also dealing with the terminology; do I create a sub menu, a child menu or a pop up menu?
    If all you want to do is like a RecentFile List in the File menu, then here is another idea:

    // This adds the pathname c:\temp\test.doc to the top of
    // the most recently used (MRU) list in the File menu.
    AfxGetApp()->AddToRecentFileList("c:\\temp\\test.doc");

  8. #8
    Join Date
    Jun 2002
    Posts
    1,417
    More information can be found in Tech Note 20 at MSDN

    http://msdn.microsoft.com/library/de...otes_tn022.asp

  9. #9
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    Thank you so much for the CreateFileList() function. This is exactly waht I need to get my file list.
    I didn't know about the AfxGetApp()->AddToRecentFileList(), this will be useful too as the clients will probably want this.

    I'm attaching a file that show an example of what I hope to do with my menu. Once getting a file list I want to populate a menu.
    Attached Images Attached Images  

  10. #10
    Join Date
    Jun 2002
    Posts
    1,417
    This is not a complete solution but should get you going in the right direction. First create an event handler as shown below because that is what gets called when someone clicks the Transactions menu item. Then you will need to modity the menu to add additional menu items in the "External Lists" popup-menu. I think the id's can be any arbitrary number because they are only for your use and are only good for the menu. No problem if they already duplicate a number in the resource file.

    Code:
    void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) 
    {
    	CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
    	
    	// TODO: Add your message handler code here
    	CString str;
    	int nMenuCount = pPopupMenu->GetMenuItemCount();
    	for(int i = 0; i < nMenuCount; i++)
    	{
    		pPopupMenu->GetMenuString(i, str, MF_BYPOSITION);
    		if(str == "External Lists")
    			break;
    	}	
    }

  11. #11
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    You have been so helpful! Thank you! I am now able to dynamically populate a popup menu with a file list.

    Now all I need to figure out is how to get the item selected. I'm searching thru MSDN for a function or some way of capturing which item is selected from the menu. I'm going to experiment with OnCommand() to see if I can get the item selected.

    Thanks again!!

    Jim
    Last edited by xucaen; January 24th, 2003 at 12:27 PM.

  12. #12
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    I am using the function you showed me to create my file list. It works beautifully! I am noticing, however, that any new files added to the directory while my app is running never show up in the list even though I am calling this function every time the menu is selected. Is there a way to refresh before getting the file list?
    Here is the function I am using;

    #define MAX_FILE_LIST 100
    .
    .
    .

    void CreateFileList(string dirname, vector<string>* list)
    {
    WIN32_FIND_DATA data;
    HANDLE hFile = FindFirstFile(dirname.c_str(), &data);
    if(hFile != INVALID_HANDLE_VALUE)
    {
    do
    {
    if(!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    {
    // This is not a directory, so must be a file
    list->push_back(data.cFileName);
    }
    } while( list->size() < MAX_FILE_LIST && FindNextFile(hFile, &data) );
    FindClose(hFile);

    }

    }


    Thanks!!

    Jim
    Last edited by xucaen; January 27th, 2003 at 04:06 PM.

  13. #13
    Join Date
    Jun 2002
    Posts
    1,417
    I suspect you have something else wrong. I wrote a small test program and did not see that behavior. To run this test you first need to create the directory c:\tmp, unless you already have one. The first time you see "Press any key...", copy some more files into the directory before pressing a key.

    Maybe your list is filling up with file names?
    Code:
    #include "stdafx.h"
    #include <windows.h>
    #include <string>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    #define MAX_FILE_LIST 100
    
    void CreateFileList(string& dirname, vector<string>& list)
    {
    	WIN32_FIND_DATA data;
    	HANDLE hFile = FindFirstFile(dirname.c_str(), &data);
    	if(hFile != INVALID_HANDLE_VALUE)
    	{
    		do
    		{
    			if(!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    			{
    				// This is not a directory, so must be a file
    				list.push_back(data.cFileName);
    			}
    		} while( list.size() < MAX_FILE_LIST && FindNextFile(hFile, &data) );
    		FindClose(hFile);
    	}
    
    }
    
    void ShowList(vector<string>& list)
    {
    	vector<string>::iterator it;
    	for(it = list.begin(); it < list.end(); it++)
    	{
    		cout << *it << endl;
    	}
    }
    
    int main(int argc, char* argv[])
    {
    	vector<string> lst;
    	string name = "c:\\tmp\\*.*";
    	CreateFileList(name, lst);
    	ShowList(lst);
    	cout << "Press any key to continue."; 
    	cin.ignore();
    	cout << endl;
    	CreateFileList(name, lst);
    	ShowList(lst);
    	cout << "Press any key to continue."; 
    	cin.ignore();
    
    	return 0;
    }

  14. #14
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    Your example does work. Interesting... It must have something to do with the menu I'm populating. Maybe something in Windows is keeping it from refreshing, whereas a DOS prompt automatically refreshes or it accesses the directory differently? I'll keep working on it. I'll post what I find.

    Thanks!!

    Jim

  15. #15
    Join Date
    Jan 2003
    Location
    Massachusetts
    Posts
    170
    Well, I found out why my file list isn't being refreshed; OnInitMenuPopup() is only called once, so CreateFileList() only gets called once. So now I need a way to either call OnInitMenuPopup() everytime the menu is accessed or find a different way to populate my menu.

    I'll keep digging and post what I find..

    Thanks!!

    Jim

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured