Creating a Windows explorer like directory tree

纵饮孤独 提交于 2019-12-01 08:03:09

问题


Currently, I am using wxWidgets' wxGenericDirCtrl, which gives me a user interface to the directory tree. It looks like this:

However, I would prefer it to look like this:

Talking with the wxWidgets developers, they suggest that one good way to proceed is to modify the wxGenericDirCtrl class to use the native Windows directory control. I would like to contribute this functionality to wxWidgets myself, but I'm not sure where to start, and could use some suggestions to get me started.

Questions:

  1. What's the correct native way to create such a control in C++. Do I use MFC, .NET, or something else?
  2. Are there any keywords which can help me find this information?
  3. Is there any example code showing how to do this?

回答1:


Creating a Window Explorer like directory tree (known as "shell namespace tree control") has become quite easy since Windows Vista. This control can be created through a COM class called INameSpaceTreeControl. Windows 7 added a newer version of this class called INameSpaceTreeControl2.

The following sample code could be called from the WM_CREATE handler of the parent window. It creates a namespace tree control that has its root set to the desktop folder. Other root folders are possible, even multiple roots can be inserted.

#include <ShlObj.h>   //Shell COM API
#include <atlbase.h>  //CComPtr

static CComPtr<INameSpaceTreeControl> pTree;
if( SUCCEEDED( pTree.CoCreateInstance( CLSID_NamespaceTreeControl ) ) )
{
    RECT rc{ 0, 0, 444, 333 }; // Client coordinates of the tree control
    if( SUCCEEDED( pTree->Initialize( hWndParent, &rc, 
            NSTCS_HASEXPANDOS | NSTCS_AUTOHSCROLL | NSTCS_FADEINOUTEXPANDOS ) ) )
    {
        CComPtr<IShellItem> pItem;
        if( SUCCEEDED( SHCreateItemInKnownFolder( FOLDERID_Desktop, 0, nullptr, 
                                                  IID_PPV_ARGS( &pItem ) ) ) )
        {
            pTree->AppendRoot( pItem, SHCONTF_FOLDERS, NSTCRS_EXPANDED, nullptr );
        }
    }
}

Destroy the namespace tree control by calling the Release() method of the COM object when the parent window gets destroyed, typically in the WM_DESTROY handler of the parent window:

pTree.Release();  // Releases the COM object and sets the pointer to nullptr

Don't forget to CoInitialize(nullptr) once at startup of your program and CoUninitialize() before shutdown.




回答2:


wxWidgets does NOT use MFC, .NET or whatever other high-level library on Windows. Just the basic system API (libs kernel32, winspool, comctl32, etc). Same goes for OSX, using the OS provided API. In Linux there's no such "basic API", and thus wxWidgets uses GTK+.

You already have the keywords to search for: explorer like control.

wxGenericDirCtrl has GetTreeCtrl()member. Then, just add images to nodes, for example by wxTreeCtrl::AssignButtonsImageList(). See wx docs




回答3:


ExplorerApp.h

    #ifndef EXPLORERAPP_H
#define EXPLORERAPP_H

#include <wx/app.h>

class ExplorerApp : public wxApp
{
    public:
        virtual bool OnInit();
};

#endif // EXPLORERAPP_H

ExplorerApp.cpp

#include "ExplorerApp.h"

//(*AppHeaders
#include "ExplorerMain.h"
#include <wx/image.h>
//*)

IMPLEMENT_APP(ExplorerApp);

bool ExplorerApp::OnInit()
{
    //(*AppInitialize
    bool wxsOK = true;
    wxInitAllImageHandlers();
    if ( wxsOK )
    {
        ExplorerFrame* Frame = new ExplorerFrame(0);
        Frame->Show();
        SetTopWindow(Frame);
    }
    //*)
    return wxsOK;

}

ExplorerMain.h

#ifndef EXPLORERMAIN_H
#define EXPLORERMAIN_H

#include<wx/imaglist.h>
#include<wx/artprov.h>
#include<wx/dir.h>
////(*Headers(ExplorerFrame)
  #include <wx/treectrl.h>
  #include <wx/textctrl.h>
  #include <wx/button.h>
  #include <wx/dirdlg.h>
  #include <wx/frame.h>
  //*)

class ExplorerFrame: public wxFrame
{
    public:

        ExplorerFrame(wxWindow* parent,wxWindowID id = -1);
        virtual ~ExplorerFrame();

    private:

        ////(*Handlers(ExplorerFrame)
          void OnQuit(wxCommandEvent& event);
          void OnAbout(wxCommandEvent& event);
          void OnButton1Click(wxCommandEvent& event);
          void findir(wxTreeItemId,wxString);
          //*)

        ////(*Identifiers(ExplorerFrame)
          static const long ID_TEXTCTRL1;
          static const long ID_BUTTON1;
          static const long ID_CUSTOM1;
          //*)

        ////(*Declarations(ExplorerFrame)
          wxButton* Button1;
          wxDirDialog* DirDialog1;
          wxTextCtrl* TextCtrl1;
          wxTreeCtrl* Mytreectrl;
          //*)

        wxImageList* myimageliste;
        wxTreeItemId root;
        wxTreeItemId Child1;
        wxTreeItemId Child2;
        wxTreeItemId Child3;

        DECLARE_EVENT_TABLE()
};

#endif // EXPLORERMAIN_H

ExplorerMain.cpp

#include "ExplorerMain.h"
#include <wx/msgdlg.h>

////(*InternalHeaders(ExplorerFrame)
#include <wx/intl.h>
#include <wx/string.h>
//*)

//helper functions
enum wxbuildinfoformat {
    short_f, long_f };

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

//(*IdInit(ExplorerFrame)
const long ExplorerFrame::ID_TEXTCTRL1 = wxNewId();
const long ExplorerFrame::ID_BUTTON1 = wxNewId();
const long ExplorerFrame::ID_CUSTOM1 = wxNewId();
//*)

BEGIN_EVENT_TABLE(ExplorerFrame,wxFrame)
    //(*EventTable(ExplorerFrame)
    //*)
END_EVENT_TABLE()

ExplorerFrame::ExplorerFrame(wxWindow* parent,wxWindowID id)
{
    ////(*Initialize(ExplorerFrame)
      Create(parent, id, _("wxTreeCtrl"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));
      SetClientSize(wxSize(400,298));
      TextCtrl1 = new wxTextCtrl(this, ID_TEXTCTRL1, _("C:/"), wxPoint(32,16), wxSize(240,22), 0, wxDefaultValidator, _T("ID_TEXTCTRL1"));
      Button1 = new wxButton(this, ID_BUTTON1, _("Browse"), wxPoint(320,16), wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1"));
      Mytreectrl = new wxTreeCtrl(this,ID_CUSTOM1,wxPoint(24,56),wxSize(352,224),wxTR_HAS_BUTTONS,wxDefaultValidator,_T("ID_CUSTOM1"));
      DirDialog1 = new wxDirDialog(this, _("Select directory"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, wxDefaultSize, _T("wxDirDialog"));
      Center();

      Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ExplorerFrame::OnButton1Click);
      //*)

    myimageliste = new wxImageList(16,16);
    myimageliste->Add(wxArtProvider::GetBitmap(wxART_FOLDER,wxART_OTHER,wxSize(16,16)));
    myimageliste->Add(wxArtProvider::GetBitmap(wxART_REPORT_VIEW,wxART_OTHER,wxSize(16,16)));

    Mytreectrl->AssignImageList(myimageliste);

    root = Mytreectrl->AddRoot(_T("Root"),0);
    /*Child1 = Mytreectrl->AppendItem(root,_T("Folder 1"),0);
    Mytreectrl->AppendItem(Child1,_T("My folder 11"),1);
    Mytreectrl->AppendItem(Child1,_T("My folder 12"),1);
    Mytreectrl->AppendItem(Child1,_T("My folder 13"),1);

    Child2 = Mytreectrl->AppendItem(root,_T("Folder 2"),0);
    Mytreectrl->AppendItem(Child2,_T("My folder 21"),1);
    Mytreectrl->AppendItem(Child2,_T("My folder 22"),1);
    Mytreectrl->AppendItem(Child2,_T("My folder 23"),1);

    Child3 = Mytreectrl->AppendItem(root,_T("Folder 3"),0);
    Mytreectrl->ExpandAll();*/
    //findir(root,"C:\\");
}

ExplorerFrame::~ExplorerFrame()
{
    //(*Destroy(ExplorerFrame)
    //*)
}

void ExplorerFrame::OnQuit(wxCommandEvent& event)
{
    Close();
}

void ExplorerFrame::OnAbout(wxCommandEvent& event)
{
    wxString msg = wxbuildinfo(long_f);
    wxMessageBox(msg, _("Welcome to..."));
}

void ExplorerFrame::findir(wxTreeItemId id,wxString path){
    wxDir mydir;
    //DirDialog1->SetPath(_T("C://"));
    bool isopen = false;
    //int dir = DirDialog1->ShowModal();
   // if(dir == wxID_OK){
    //TextCtrl1->SetValue(DirDialog1->GetPath());
    //Mytreectrl->DeleteChildren(root);
    //Mytreectrl->SetItemText(root,DirDialog1->GetPath());
    isopen = mydir.Open(path);
    //}

    wxString filename;
    bool cont = false;
    bool con = false;

    if(isopen){
        con = mydir.GetFirst(&filename,wxEmptyString,wxDIR_DIRS);
    }

    int handleforfiles = 0;
    while(con and isopen){
        wxTreeItemId ids = Mytreectrl->AppendItem(id,filename,0);
        //wxMessageBox(path+filename,path+'\\'+filename);
        if(handleforfiles >= 150){
            //wxMessageBox(_T("The Max File limit reached"),_T("The Max File limit reached"));
            break;
        }
        findir(ids,path+'\\'+filename);
        con = mydir.GetNext(&filename);
        ++handleforfiles;
    }

    if(isopen){
        cont = mydir.GetFirst(&filename,wxEmptyString,wxDIR_FILES);
    }

    handleforfiles = 0;

    while(cont and isopen){
        Mytreectrl->AppendItem(id,filename,1);
        if(handleforfiles >= 150){
            //wxMessageBox(_T("The Max File limit reached"),_T("The Max File limit reached"));
            break;
        }
        cont = mydir.GetNext(&filename);
        ++handleforfiles;
    }
}

void ExplorerFrame::OnButton1Click(wxCommandEvent& event)
{
    //wxDir mydir;
    DirDialog1->SetPath(_T("C://"));
    //bool isopen = false;
    int dir = DirDialog1->ShowModal();
    if(dir == wxID_OK){
        TextCtrl1->SetValue(DirDialog1->GetPath());
        Mytreectrl->DeleteChildren(root);
        Mytreectrl->SetItemText(root,DirDialog1->GetPath());
        //isopen = mydir.Open(DirDialog1->GetPath());
        findir(root,DirDialog1->GetPath());
    }
}


来源:https://stackoverflow.com/questions/48586051/creating-a-windows-explorer-like-directory-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!