UDN-企业互联网技术人气社区

板块导航

浏览  : 1764
回复  : 0

[资源] GacUI Demo:模拟Windows7资源管理器

[复制链接]
狂战灬梦舞的头像 楼主
发表于 2015-12-8 11:25:28 | 显示全部楼层 |阅读模式
  GacUI Demo:模拟Windows7资源管理器
  
  GacUI的ListView支持Windows 7资源管理器的六种View,并且在默认的皮肤下表现的跟资源管理器十分类似。这个Demo也使用了一些Shell API来获得资源管理器使用的文件的图标、文件类型的字符串等等。完整的代码可以在http://www.gaclib.net/Demos/Cont ... Switching/Demo.html看到。在这里先上图:
1.jpg
2.jpg
3.jpg
4.jpg
5.jpg
6.jpg


    想必这么一个简单的两个控件的排版大家都已经知道怎么写了。首先创建一个2行1列的表格,其次直接放两个控件进去。代码如下:
  1. #include "..\..\Public\Source\GacUI.h"
  2. #include <ShlObj.h>
  3. using namespace vl::collections;
  4. int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow)
  5. {
  6.     return SetupWindowsDirect2DRenderer();
  7. }
  8. extern void FillData(GuiListView* listView);
  9. /***********************************************************************
  10. ViewSwitchingWindow
  11. ***********************************************************************/
  12. class ViewSwitchingWindow : public GuiWindow
  13. {
  14. private:
  15.     GuiListView*                    listView;
  16.     GuiComboBoxListControl*            comboView;
  17.     void comboView_SelectedIndexChanged(GuiGraphicsComposition* sender, GuiEventArgs& arguments)
  18.     {
  19.         switch(comboView->GetSelectedIndex())
  20.         {
  21.         case 0:
  22.             listView->ChangeItemStyle(new list::ListViewBigIconContentProvider);
  23.             break;
  24.         case 1:
  25.             listView->ChangeItemStyle(new list::ListViewSmallIconContentProvider);
  26.             break;
  27.         case 2:
  28.             listView->ChangeItemStyle(new list::ListViewListContentProvider);
  29.             break;
  30.         case 3:
  31.             listView->ChangeItemStyle(new list::ListViewDetailContentProvider);
  32.             break;
  33.         case 4:
  34.             listView->ChangeItemStyle(new list::ListViewTileContentProvider);
  35.             break;
  36.         case 5:
  37.             listView->ChangeItemStyle(new list::ListViewInformationContentProvider);
  38.             break;
  39.         }
  40.     }
  41. public:
  42.     ViewSwitchingWindow()
  43.         :GuiWindow(GetCurrentTheme()->CreateWindowStyle())
  44.     {
  45.         this->SetText(L"Controls.ListView.ViewSwitching");
  46.         GuiTableComposition* table=new GuiTableComposition;
  47.         table->SetCellPadding(4);
  48.         table->SetAlignmentToParent(Margin(0, 0, 0, 0));
  49.         table->SetRowsAndColumns(2, 1);
  50.         table->SetRowOption(0, GuiCellOption::MinSizeOption());
  51.         table->SetRowOption(1, GuiCellOption::PercentageOption(1.0));
  52.         table->SetColumnOption(0, GuiCellOption::PercentageOption(1.0));
  53.         {
  54.             GuiCellComposition* cell=new GuiCellComposition;
  55.             table->AddChild(cell);
  56.             cell->SetSite(0, 0, 1, 1);
  57.             GuiTextList* comboSource=g::NewTextList();
  58.             comboSource->GetItems().Add(L"Big Icon");
  59.             comboSource->GetItems().Add(L"Small Icon");
  60.             comboSource->GetItems().Add(L"List");
  61.             comboSource->GetItems().Add(L"Detail");
  62.             comboSource->GetItems().Add(L"Tile");
  63.             comboSource->GetItems().Add(L"Information");
  64.             comboSource->SetHorizontalAlwaysVisible(false);
  65.             comboView=g::NewComboBox(comboSource);
  66.             comboView->SetSelectedIndex(0);
  67.             comboView->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, -1, 0));
  68.             comboView->GetBoundsComposition()->SetPreferredMinSize(Size(160, 0));
  69.             comboView->SelectedIndexChanged.AttachMethod(this, &ViewSwitchingWindow::comboView_SelectedIndexChanged);
  70.             cell->AddChild(comboView->GetBoundsComposition());
  71.         }
  72.         {
  73.             GuiCellComposition* cell=new GuiCellComposition;
  74.             table->AddChild(cell);
  75.             cell->SetSite(1, 0, 1, 1);
  76.             listView=g::NewListViewBigIcon();
  77.             listView->GetBoundsComposition()->SetAlignmentToParent(Margin(0, 0, 0, 0));
  78.             listView->SetHorizontalAlwaysVisible(false);
  79.             listView->SetVerticalAlwaysVisible(false);
  80.             listView->SetMultiSelect(true);
  81.             cell->AddChild(listView->GetBoundsComposition());
  82.         }
  83.         this->GetBoundsComposition()->AddChild(table);
  84.         FillData(listView);
  85.         // set the preferred minimum client size
  86.         this->GetBoundsComposition()->SetPreferredMinSize(Size(640, 480));
  87.         // call this to calculate the size immediately if any indirect content in the table changes
  88.         // so that the window can calcaulte its correct size before calling the MoveToScreenCenter()
  89.         this->ForceCalculateSizeImmediately();
  90.         // move to the screen center
  91.         this->MoveToScreenCenter();
  92.     }
  93. };
复制代码

  在非虚拟模式下的ListView控件可以使用listView->ChangeItem(list::ListView*ContentProvider)来切换外观。整个控件的设计是开放的,如果程序员有特别的要求的话,也可以实现一个类似的ContentProvider来控制每一个item的外观。ContentProvider可以控制的地方有列表项的排版、坐标系和每一个列表项的皮肤等等。排版和坐标系都已经有很多预定义的类(实现)可以使用。值得一提的是,在Detail模式下的ColumnHeader是列表项的排版组件放进去的。如果没有特别复杂的要求,单纯要显示数据的话,使用起来很简单。上面的代码有一个关键的FillData函数,用于读取Windows目录(通常是C:\Windows)的文件内容然后显示上去。代码如下:
  1. /***********************************************************************
  2. FillData
  3. ***********************************************************************/
  4. void FillList(GuiListView* listView, const WString& path, List<WString>& files)
  5. {
  6.     // Fill all information about a directory or a file.
  7.     FOREACH(WString, file, files.Wrap())
  8.     {
  9.         Ptr<list::ListViewItem> item=new list::ListViewItem;
  10.         WString fullPath=path+L"\\"+file;
  11.         // Get large icon.
  12.         item->largeImage=GetFileIcon(fullPath, SHGFI_LARGEICON | SHGFI_ICON);
  13.         // Get small icon.
  14.         item->smallImage=GetFileIcon(fullPath, SHGFI_SMALLICON | SHGFI_ICON);
  15.         // Get display name
  16.         item->text=GetFileDisplayName(fullPath);
  17.         // Get type name
  18.         item->subItems.Add(GetFileTypeName(fullPath));
  19.         // Get last write time
  20.         item->subItems.Add(GetFileLastWriteTime(fullPath));
  21.         // Get file size
  22.         item->subItems.Add(GetFileSize(fullPath));
  23.         listView->GetItems().Add(item);
  24.     }
  25. }
  26. void FillData(GuiListView* listView)
  27. {
  28.     // Get the Windows directory, normally L"C:\Windows".
  29.     wchar_t foldeRPAth[MAX_PATH]={0};
  30.     HRESULT hr=SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, 0, folderPath);
  31.     if(FAILED(hr)) return;
  32.     // Enumerate all directories and files in the Windows directory.
  33.     List<WString> directories;
  34.     List<WString> files;
  35.     SearchDirectoriesAndFiles(folderPath, directories, files);
  36.     // Set all columns. The first column is the primary column. All others are sub columns.
  37.     listView->GetItems().GetColumns().Add(new list::ListViewColumn(L"Name", 230));
  38.     listView->GetItems().GetColumns().Add(new list::ListViewColumn(L"Type", 120));
  39.     listView->GetItems().GetColumns().Add(new list::ListViewColumn(L"Date", 120));
  40.     listView->GetItems().GetColumns().Add(new list::ListViewColumn(L"Size", 120));
  41.     // Set all data columns (important sub solumns). The first sub item is 0. The primary column is not counted in.
  42.     listView->GetItems().GetDataColumns().Add(0);    // Type
  43.     listView->GetItems().GetDataColumns().Add(1);    // Data
  44.     // Fill all directories and files into the list view
  45.     FillList(listView, folderPath, directories);
  46.     FillList(listView, folderPath, files);
  47. }
  48. /***********************************************************************
  49. GuiMain
  50. ***********************************************************************/
  51. void GuiMain()
  52. {
  53.     GuiWindow* window=new ViewSwitchingWindow;
  54.     GetApplication()->Run(window);
  55.     delete window;
  56. }
复制代码
   
  跟很多GUI类库类似,为了在ListView上面显示内容,简单的new一下ListViewItem和ListViewColumn,把数据都放进去就可以了。这里的DataColumn主要是为了在Tile和Information模式下面显示附加数据而制作的。剩下的内容就不是重点了,不过有些人可能很关心一些具体的操作,譬如怎样获取文件图标啦,怎样获取文件的各种属性等等。值得一提的是Windows有很多类似GetDateFormatEx这样的函数,用来把几乎所有需要在GUI上显示的数据,转成一个跟用户当前的区域设置(locale)相关的字符串。这种事情就应该让操作系统来做啊。剩下的代码包含了很多操作Windows API获取文件属性的代码:
  1. /***********************************************************************
  2. File System Operations
  3. ***********************************************************************/
  4. void SearchDirectoriesAndFiles(const WString& path, List<WString>& directories, List<WString>& files)
  5. {
  6.     // Use FindFirstFile, FindNextFile and FindClose to enumerate all directories and files
  7.     WIN32_FIND_DATA findData;
  8.     HANDLE findHandle=INVALID_HANDLE_VALUE;
  9.     while(true)
  10.     {
  11.         if(findHandle==INVALID_HANDLE_VALUE)
  12.         {
  13.             WString searchPath=path+L"\\*";
  14.             findHandle=FindFirstFile(searchPath.Buffer(), &findData);
  15.             if(findHandle==INVALID_HANDLE_VALUE)
  16.             {
  17.                 break;
  18.             }
  19.         }
  20.         else
  21.         {
  22.             BOOL result=FindNextFile(findHandle, &findData);
  23.             if(result==0)
  24.             {
  25.                 FindClose(findHandle);
  26.                 break;
  27.             }
  28.         }
  29.         if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  30.         {
  31.             if(wcscmp(findData.cFileName, L".")!=0 && wcscmp(findData.cFileName, L"..")!=0)
  32.             {
  33.                 directories.Add(findData.cFileName);
  34.             }
  35.         }
  36.         else
  37.         {
  38.             files.Add(findData.cFileName);
  39.         }
  40.     }
  41.     Func<vint(WString a, WString b)> comparer=[](WString a, WString b){return _wcsicmp(a.Buffer(), b.Buffer());};
  42.     CopyFrom(directories.Wrap(), directories.Wrap()>>OrderBy(comparer));
  43.     CopyFrom(files.Wrap(), files.Wrap()>>OrderBy(comparer));
  44. }
  45. Ptr<GuiImageData> GetFileIcon(const WString& fullPath, UINT uFlags)
  46. {
  47.     // Use SHGetFileInfo to get the correct icons for the specified directory or file.
  48.     SHFILEINFO info;
  49.     DWORD result=SHGetFileInfo(fullPath.Buffer(), 0, &info, sizeof(SHFILEINFO), uFlags);
  50.     Ptr<GuiImageData> imageData;
  51.     if(result)
  52.     {
  53.         Ptr<INativeImage> image=windows::CreateImageFromHICON(info.hIcon);
  54.         if(image)
  55.         {
  56.             imageData=new GuiImageData(image, 0);
  57.         }
  58.         DestroyIcon(info.hIcon);
  59.     }
  60.     return imageData;
  61. }
  62. WString GetFileDisplayName(const WString& fullPath)
  63. {
  64.     SHFILEINFO info;
  65.     DWORD result=SHGetFileInfo(fullPath.Buffer(), 0, &info, sizeof(SHFILEINFO), SHGFI_DISPLAYNAME);
  66.     return result?info.szDisplayName:L"";
  67. }
  68. WString GetFileTypeName(const WString& fullPath)
  69. {
  70.     SHFILEINFO info;
  71.     DWORD result=SHGetFileInfo(fullPath.Buffer(), 0, &info, sizeof(SHFILEINFO), SHGFI_TYPENAME);
  72.     return result?info.szTypeName:L"";
  73. }
  74. WString GetFileLastWriteTime(const WString& fullPath)
  75. {
  76.     // Get file attributes.
  77.     WIN32_FILE_ATTRIBUTE_DATA info;
  78.     BOOL result=GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
  79.     // Get the localized string for the file last write date.
  80.     FILETIME localFileTime;
  81.     SYSTEMTIME localSystemTime;
  82.     FileTimeToLocalFileTime(&info.ftLastWriteTime, &localFileTime);
  83.     FileTimeToSystemTime(&localFileTime, &localSystemTime);
  84.     // Get the correct locale
  85.     wchar_t localeName[LOCALE_NAME_MAX_LENGTH]={0};
  86.     GetSystemDefaultLocaleName(localeName, sizeof(localeName)/sizeof(*localeName));
  87.     // Get the localized date string
  88.     wchar_t dateString[100]={0};
  89.     GetDateFormatEx(localeName, DATE_SHORTDATE, &localSystemTime, NULL, dateString, sizeof(dateString)/sizeof(*dateString), NULL);
  90.     // Get the localized time string
  91.     wchar_t timeString[100]={0};
  92.     GetTimeFormatEx(localeName, TIME_FORCE24HOURFORMAT | TIME_NOSECONDS, &localSystemTime, NULL, timeString, sizeof(timeString)/sizeof(*timeString));
  93.     return dateString+WString(L" ")+timeString;
  94. }
  95. WString GetFileSize(const WString& fullPath)
  96. {
  97.     // Get file attributes.
  98.     WIN32_FILE_ATTRIBUTE_DATA info;
  99.     BOOL result=GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
  100.     // Get the string for file size
  101.     LARGE_INTEGER li;
  102.     li.HighPart=info.nFileSizeHigh;
  103.     li.LowPart=info.nFileSizeLow;
  104.     WString unit;
  105.     double size=0;
  106.     if(li.QuadPart>=1024*1024*1024)
  107.     {
  108.         unit=L" GB";
  109.         size=(double)li.QuadPart/(1024*1024*1024);
  110.     }
  111.     else if(li.QuadPart>=1024*1024)
  112.     {
  113.         unit=L" MB";
  114.         size=(double)li.QuadPart/(1024*1024);
  115.     }
  116.     else if(li.QuadPart>=1024)
  117.     {
  118.         unit=L" KB";
  119.         size=(double)li.QuadPart/1024;
  120.     }
  121.     else
  122.     {
  123.         unit=L" Bytes";
  124.         size=(double)li.QuadPart;
  125.     }
  126.     WString sizeString=ftow(size);
  127.     const wchar_t* reading=sizeString.Buffer();
  128.     const wchar_t* point=wcschr(sizeString.Buffer(), L'.');
  129.     if(point)
  130.     {
  131.         const wchar_t* max=reading+sizeString.Length();
  132.         point+=4;
  133.         if(point>max) point=max;
  134.         sizeString=sizeString.Left(point-reading);
  135.     }
  136.     return sizeString+unit;
  137. }
复制代码

  在这里需要特别说明一下。这个Demo没有使用GacUIIncludes.h,而是用GacUI.h,是因为GacUI.h包含了一些跟Windows操作系统直接相关的东西,譬如说把一个HICON类型转成INativeImage类型的方法:windows::GetImageFromHICON。类似的操作在开发跟Windows系统本身交互比较密切的函数是很有用的。下一个Demo还没有写,但是基本上会选择一个小场景来描述如何使用ListView的虚拟模式。GacUI里面所有的列表控件都有虚拟模式,包括GuiVirtualTextList、GuiVirtualListView和GuiTreeView(TreeView的虚拟模式和非虚拟模式是同一个类型)等。敬请期待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部