DuiLib : 使用CListUI显示海量数据
2015-08-24 16:47
411 查看
最近遇到要在一个DuiLib::CListUI中显示动态数据的子任务.
在使用我改版的DuiLib中发现如下问题, 真杯具.
* 如果反复添加删除CListContainerElementUI, 会引起CListUI所在的Dialog退出时挂掉的问题.
e.g. 在CListUI中增加2000条数据, 在CListUI中删掉2000条数据, 如此反复20次. 再退出该CListUI所在的Dialog, UI就挂掉了.
现象是WM_PAINT陷入了一个循环(这个正常), 但是UI显示不出来了.
这个问题我回避了, 搞不定. 采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行), 根据要显示的内容计算List的UI可见部分应该写什么数据.
这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在退出时UI挂掉的问题.
* 当CListUI一次添加太多数据时(e.g. 一次添加2000行), 当滚动时, List反应特别的迟钝, 有时还会导致UI卡死.
这个问题我同样回避了, 搞不定. 采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行), 根据要显示的内容计算List的UI可见部分应该写什么数据.
这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在滚动List自带竖向滚动条时, 引起的机率性UI卡死.
这个问题让我做了5天实验, 才想到折中的解决方法.
我采用的方法是:
* 隐藏CListUI实例自带的竖向滚动条控件, 每次只显示一页的数据
* 在CListUI实例右边的Container中自己摆一个 CScrollBarUI, 用户点击滚动条时, 记录点击的位置, 发送自定义消息, 去刷新CListUI中的显示.
实验过了, 准备20W条数据, 在CListUI中显示, 也是蛮快的, 和数据多少无关, 花费的操作和显示时间都是常量.
这个折中的方法, 让我感到很欣慰.
备注:
数据的容器使用std::vector, 而不能是std::deque, 防止数据释放时, 时间太长. 20W条数据时, std::deque释放的不是一般的慢, 和构造数据的速度比较, 慢了100倍.
使用std::vector时, 构造数据和释放数据的时间是基本相同的. 在20W条数据的条件下做过实验了.
运行效果图:
工程下载点 : srcbk_2015_0824_1711_prj_dlg_show_list_ui_use_massive_amounts_of_data.zip
工程预览:
xml文件:
在使用我改版的DuiLib中发现如下问题, 真杯具.
* 如果反复添加删除CListContainerElementUI, 会引起CListUI所在的Dialog退出时挂掉的问题.
e.g. 在CListUI中增加2000条数据, 在CListUI中删掉2000条数据, 如此反复20次. 再退出该CListUI所在的Dialog, UI就挂掉了.
现象是WM_PAINT陷入了一个循环(这个正常), 但是UI显示不出来了.
这个问题我回避了, 搞不定. 采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行), 根据要显示的内容计算List的UI可见部分应该写什么数据.
这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在退出时UI挂掉的问题.
* 当CListUI一次添加太多数据时(e.g. 一次添加2000行), 当滚动时, List反应特别的迟钝, 有时还会导致UI卡死.
这个问题我同样回避了, 搞不定. 采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行), 根据要显示的内容计算List的UI可见部分应该写什么数据.
这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在滚动List自带竖向滚动条时, 引起的机率性UI卡死.
这个问题让我做了5天实验, 才想到折中的解决方法.
我采用的方法是:
* 隐藏CListUI实例自带的竖向滚动条控件, 每次只显示一页的数据
* 在CListUI实例右边的Container中自己摆一个 CScrollBarUI, 用户点击滚动条时, 记录点击的位置, 发送自定义消息, 去刷新CListUI中的显示.
实验过了, 准备20W条数据, 在CListUI中显示, 也是蛮快的, 和数据多少无关, 花费的操作和显示时间都是常量.
这个折中的方法, 让我感到很欣慰.
备注:
数据的容器使用std::vector, 而不能是std::deque, 防止数据释放时, 时间太长. 20W条数据时, std::deque释放的不是一般的慢, 和构造数据的速度比较, 慢了100倍.
使用std::vector时, 构造数据和释放数据的时间是基本相同的. 在20W条数据的条件下做过实验了.
运行效果图:
工程下载点 : srcbk_2015_0824_1711_prj_dlg_show_list_ui_use_massive_amounts_of_data.zip
工程预览:
/// @file MainDlg.h /// @brief 主对话框的定义, 基类为CXmlWnd #ifndef __MAIN_DLG_H__ #define __MAIN_DLG_H__ #include "stdafx.h" #include<sstream> #include <iomanip> #include <iostream> #include <map> #include <deque> #include "XmlWnd.h" /// 扩展DuiLib控件 #include "controls_ex.h" extern HWND g_hHwndMain; extern TAG_HOOK_DATA g_KbHookData; extern TAG_HOOK_DATA g_MouseHookData; LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam // mouse coordinates ); enum e_view_index { e_view_index_unknown = 0, e_view_index_start_prog, }; typedef struct _INFO_LIST_ITEM_DATA { _INFO_LIST_ITEM_DATA() { ::ZeroMemory(cFileType, sizeof(cFileType)); ::ZeroMemory(cCreationTime, sizeof(cCreationTime)); ::ZeroMemory(cLastWriteTime, sizeof(cLastWriteTime)); ::ZeroMemory(cFilePath, sizeof(cFilePath)); ::ZeroMemory(cFileSize, sizeof(cFileSize)); } char cFileType[MAX_PATH]; ///< type_dir 目录, 其它 文件 char cCreationTime[MAX_PATH]; char cLastWriteTime[MAX_PATH]; char cFilePath[MAX_PATH + 1]; char cFileSize[MAX_PATH]; }INFO_LIST_ITEM_DATA, *PINFO_LIST_ITEM_DATA; typedef enum _eDispWParam { DISP_REFRESH_CUR_TREE_NODE_FILES_INFO_REMOVE_ALL, ///< 移除List的当前页面内容 DISP_REFRESH_CUR_TREE_NODE_FILES_INFO, ///< 刷新当前用户选择节点的文件信息 DISP_MSG, ///< 显示消息 }eDispWParam; class CMainDlg : public CXmlWnd { public: CMainDlg(WCHAR * pcXmlFileName, WCHAR * pcWndClassName); virtual ~CMainDlg(void); /// 安装相关 DWORD m_dwMainTID; public: void ThreadProcStart(); BOOL ThreadProcEnd(BOOL bStopNow); static UINT WINAPI ThreadProc(void* pParam); UINT WINAPI ThreadProc(); DUI_DECLARE_MESSAGE_MAP() public: virtual void InitWindow(); virtual LONG GetStyle(); virtual LONG GetExStyle(); virtual CControlUI* CreateUiControlByMySelf(LPCTSTR pstrClass); virtual LRESULT WndMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT WndMessageProc_WM_DISP_REFRESH(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual LRESULT SysMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled); virtual void OnFinalMessage(HWND hWnd); virtual void Notify(TNotifyUI & msg); virtual void OnClick(TNotifyUI& msg); virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); private: void UiInit(); void UiInit_List(); void clearFindData(); void PrepareData(); void ShowMsg(const WCHAR* pcMsg); void InsertRow2FileList_RemoveAll(); void ClearRow2FileList(CListContainerElementUI* pListItem); void fn_ShowCurTreeNodeFilesInfo(); void InsertRow2FileList(std::vector<INFO_LIST_ITEM_DATA*>& deqFindData); void InsertRow2FileList(INFO_LIST_ITEM_DATA*& FindData, CListContainerElementUI*& pListItem); void MoveMyWindowToDesktopRightBottom(); void DataInit(); void DataUnInit(); void RunObjProg(); void switch_view(e_view_index PageIndex); private: DuiLib::CTabLayoutUI* m_pTabView; DuiLib::CContainerUI* m_pPage_StartProg; CListUI* m_pListFiles; ///< 显示文件信息集合的List CScrollBarUI* m_pVScrollBarForFilesList; ///< List右边的竖向滚动条 CContainerUI* m_pContainerForVScrollBarForFilesList; ///< List右边竖向滚动条的容器 DuiLib::CLabelUI* m_pStatusMsg; std::wstring m_strTipMsg; ///< 提示消息 std::wstring m_strTipMsgPerv; ///< 提示消息(最后一次), 为了提高效率 ns_shaoyuan::CCriticalSection m_Locker_MainUI; int m_iCntFilesListRowMax; ///< List一页最多显示几行 int m_iDataSoruceRecordCnt; ///< 要操作的数据集合总条目数量, 暂定为20W条数据 std::vector<INFO_LIST_ITEM_DATA*> m_deqFindData; ///< 要显示的数据, 假设有6W条数据 ns_shaoyuan::CCriticalSection m_Locker_DispInfo; ns_base::CThreadManager m_ThreadManager; BOOL m_bRunObjProgNow; BOOL m_bMsgProcessOver_RefreshFilesInfo_RemoveAll; BOOL m_bMsgProcessOver_RefreshFilesInfo; }; #endif // #ifndef __MAIN_DLG_H__
/// @file MainDlg.cpp #include "stdafx.h" #include "resource.h" #include "resource.h" #include <comutil.h> #include <commdlg.h> #include <mshtml.h> #include <wininet.h> #include <sys/stat.h> #include "MainDlg.h" /// Hook键盘产生的数据, 动机 : 当焦点在Edit中时, DuiLib不传递 WM_KEYxx + VT_TAB /// 下全局钩子, 不采用DLL注入方式, 只监控本程序的键盘输入 /// 当有Tab键按下时, PostMessage 到主程序中处理, /// 当此时, 登录框出现时, 就切换用户名和密码的Edit焦点 TAG_HOOK_DATA g_KbHookData; TAG_HOOK_DATA g_MouseHookData; HWND g_hHwndMain = NULL; LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam) { if (nCode==0) { MOUSEHOOKSTRUCT* pMouseHook= (MOUSEHOOKSTRUCT*)lParam; if ( pMouseHook->hwnd == NULL ) { } } return CallNextHookEx(g_MouseHookData.hHook, nCode, wParam, lParam); } LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { static LONG_PTR lVkCodePrev_Tab = 0; static LONG_PTR lVkCode_Tab = 0; static LONG_PTR lVkCode_Enter = 0; static LONG_PTR lVkCode_Cancel = 0; LONG_PTR lTemp = 0; /** when tab key press down and up KeyboardProc : nCode = 0x0, wParam = 0x9, lParam = 0xF0001 KeyboardProc : nCode = 0x0, wParam = 0x9, lParam = 0xC00F0001 */ if (0 == nCode) { switch (wParam) { case VK_TAB: { lVkCode_Tab = (LONG_PTR)lParam; lTemp = lVkCode_Tab & 0xFFF00000; if (0 == lTemp) { // tab key press down lVkCodePrev_Tab = lVkCode_Tab; } else { // tab key press up if (lVkCode_Tab != lVkCodePrev_Tab) { lVkCodePrev_Tab = lVkCode_Tab; if (NULL != g_hHwndMain) { ::PostMessageW(g_hHwndMain, WM_TAB_KEY_PRESS, 0, 0); } } } } break; case VK_RETURN: { lVkCode_Enter = (LONG_PTR)lParam; lTemp = lVkCode_Enter & 0xFFF00000; if (lTemp > 0) { // key press up if (NULL != g_hHwndMain) { ::PostMessageW(g_hHwndMain, WM_ENTER_KEY_PRESS, 0, 0); } } } break; case VK_UP: { lVkCode_Enter = (LONG_PTR)lParam; lTemp = lVkCode_Enter & 0xFFF00000; if (lTemp>0) { POINT pt; GetCursorPos(&pt); ::PostMessageW(g_hHwndMain,WM_UP_KEY_PRESS,pt.x,pt.y); } } break; case VK_DOWN: { lVkCode_Enter = (LONG_PTR)lParam; lTemp = lVkCode_Enter & 0xFFF00000; if (lTemp>0) { ::PostMessageW(g_hHwndMain,WM_DOWN_KEY_PRESS,0,0); } } break; case VK_ESCAPE: { lVkCode_Cancel = (LONG_PTR)lParam; lTemp = lVkCode_Cancel & 0xFFF00000; if (0 == lTemp) { // key press down if (NULL != g_hHwndMain) { ::PostMessageW(g_hHwndMain, WM_CANCEL_KEY_PRESS, 0, 0); } } } break; default: break; } } return CallNextHookEx(g_KbHookData.hHook, nCode, wParam, lParam); } CMainDlg::CMainDlg(WCHAR * pcXmlFileName, WCHAR * pcWndClassName) : CXmlWnd(pcXmlFileName, pcWndClassName), m_iCntFilesListRowMax(4), m_iDataSoruceRecordCnt(200000) { DataInit(); } CMainDlg::~CMainDlg(void) { DataUnInit(); } DUI_BEGIN_MESSAGE_MAP(CMainDlg, CXmlWnd) DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick) DUI_END_MESSAGE_MAP() void CMainDlg::UiInit() { do { m_dwMainTID = ::GetCurrentThreadId(); WriteLogEx(L"m_dwMainTID = 0x%x or %d", m_dwMainTID, m_dwMainTID); m_pTabView = (DuiLib::CTabLayoutUI*)m_PaintManager.FindControl(L"TabLayout_setup_now"); if (NULL == m_pTabView) break; m_pPage_StartProg = (DuiLib::CContainerUI*)m_pTabView->FindSubControl(L"Container_page_install_over"); if (NULL == m_pPage_StartProg) break; UiInit_List(); switch_view(e_view_index_start_prog); /// 将窗体放到桌面右下角 MoveMyWindowToDesktopRightBottom(); ThreadProcStart(); } while (0); } void CMainDlg::UiInit_List() { int iWidth = 0; LPCTSTR pcDefaultAttributes = NULL; do { if (NULL == m_pListFiles) { m_pStatusMsg = (CLabelUI*)m_PaintManager.FindControl(L"Label_UI_MSG"); _ASSERT(NULL != m_pStatusMsg); m_pContainerForVScrollBarForFilesList = (CContainerUI*)m_PaintManager.FindControl(L"container_for_v_scrollbar_for_list"); _ASSERT(NULL != m_pContainerForVScrollBarForFilesList); m_pVScrollBarForFilesList = (CScrollBarUI*)m_PaintManager.FindControl(L"scrollbar_for_files_list"); _ASSERT(NULL != m_pVScrollBarForFilesList); m_pVScrollBarForFilesList->SetOwner(NULL); m_pVScrollBarForFilesList->SetManager(&m_PaintManager, NULL, false); pcDefaultAttributes = m_PaintManager.GetDefaultAttributeList(_T("VScrollBar")); if (NULL != pcDefaultAttributes) { m_pVScrollBarForFilesList->ApplyAttributeList(pcDefaultAttributes); /// 为了让滚动时,List中的内容可以衔接的观看 m_pVScrollBarForFilesList->SetLineSize((m_iCntFilesListRowMax > 3) ? (m_iCntFilesListRowMax - 1) : 1); /// 重新安装滚动条配置, 设置合适的滚动条宽度 iWidth = m_pVScrollBarForFilesList->GetFixedWidth(); m_pContainerForVScrollBarForFilesList->SetFixedWidth(iWidth); } m_pListFiles = (CListUI*)m_PaintManager.FindControl(L"list_files"); _ASSERT(NULL != m_pListFiles); m_pListFiles->SetAttribute(L"bkcolor", L"#FFFFFFFF"); m_pListFiles->SetAttribute(_T("itemaltbk"),_T("true")); m_pListFiles->SetAttribute(_T("itembkcolor"),_T("#fff8f8f8")); m_pListFiles->SetAttribute(_T("itemhotbkcolor"), _T("#FFE4E4E4")); m_pListFiles->SetAttribute(_T("itemselectedbkcolor"), _T("#FFD9E1EE")); m_pListFiles->EnableScrollBar(false, true); m_pListFiles->GetHeader()->SetMinWidth(100); } } while (0); } void CMainDlg::clearFindData() { int iIndex = 0; float fProcessPercent = 0; float fProcessPercentPerv = 0; DWORD dwTickBegin = 0; DWORD dwTickEnd = 0; std::wstring strTmp = L""; INFO_LIST_ITEM_DATA* pData = NULL; std::vector<INFO_LIST_ITEM_DATA*>::iterator it; dwTickBegin = GetTickCount(); while (1) { Sleep(0); it = m_deqFindData.begin(); if (it == m_deqFindData.end()) break; if (NULL != *it) { pData = m_deqFindData.front(); if (NULL != pData) SAFE_DELETE(pData); m_deqFindData.erase(m_deqFindData.begin()); iIndex++; } dwTickEnd = GetTickCount(); if ((dwTickEnd - dwTickBegin) > 500) { fProcessPercent = (1.0f * iIndex / m_iDataSoruceRecordCnt) * 100; if ((fProcessPercentPerv != fProcessPercent) && ((fProcessPercent - 0.001f) > fProcessPercentPerv)) { fProcessPercentPerv = fProcessPercent; dwTickBegin = GetTickCount(); strTmp = ns_base::StringFormatV( L"程序正在退出, 资源释放进度%.2f%%, 请稍候...", fProcessPercent); ShowMsg(strTmp.c_str()); } } } m_deqFindData.resize(0); } void CMainDlg::MoveMyWindowToDesktopRightBottom() { ASSERT(::IsWindow(m_hWnd)); ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==0); RECT rcDlg = { 0 }; ::GetWindowRect(m_hWnd, &rcDlg); RECT rcArea = { 0 }; RECT rcCenter = { 0 }; HWND hWnd=*this; HWND hWndParent = ::GetParent(m_hWnd); HWND hWndCenter = ::GetWindowOwner(m_hWnd); if (hWndCenter!=NULL) hWnd=hWndCenter; // 处理多显示器模式下屏幕居中 MONITORINFO oMonitor = {}; oMonitor.cbSize = sizeof(oMonitor); ::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor); rcArea = oMonitor.rcWork; if( hWndCenter == NULL ) rcCenter = rcArea; else ::GetWindowRect(hWndCenter, &rcCenter); int DlgWidth = rcDlg.right - rcDlg.left; int DlgHeight = rcDlg.bottom - rcDlg.top; // Find dialog's upper left based on rcCenter int xLeft = rcCenter.right - DlgWidth; int yTop = rcCenter.bottom - DlgHeight; // The dialog is outside the screen, move it inside if( xLeft < rcArea.left ) xLeft = rcArea.left; else if( xLeft + DlgWidth > rcArea.right ) xLeft = rcArea.right - DlgWidth; if( yTop < rcArea.top ) yTop = rcArea.top; else if( yTop + DlgHeight > rcArea.bottom ) yTop = rcArea.bottom - DlgHeight; ::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } void CMainDlg::DataInit() { m_strTipMsg = L""; m_strTipMsgPerv = L""; m_bMsgProcessOver_RefreshFilesInfo_RemoveAll = FALSE; m_bMsgProcessOver_RefreshFilesInfo = FALSE; m_pStatusMsg = NULL; m_pListFiles = NULL; m_pVScrollBarForFilesList = NULL; m_pContainerForVScrollBarForFilesList = NULL; m_bRunObjProgNow = FALSE; m_dwMainTID = 0; m_pTabView = NULL; m_pPage_StartProg = NULL; } void CMainDlg::DataUnInit() { } LONG CMainDlg::GetStyle() { long dwStyle = __super::GetStyle(); dwStyle &= ~WS_MAXIMIZEBOX; return dwStyle; } /// CMainDlg::GetExStyle 是虚函数, 在WindowImplBase::OnCreate中被调用, 用来设置扩展窗口风格 LONG CMainDlg::GetExStyle() { long dwStyle = __super::GetExStyle(); /// 禁止接受文件拖拽 dwStyle &= ~WS_EX_ACCEPTFILES; /// 禁止产生任务栏图标 dwStyle |= WS_EX_TOOLWINDOW; dwStyle &= ~(WS_EX_APPWINDOW); return dwStyle; } void CMainDlg::InsertRow2FileList_RemoveAll() { int iCnt = 0; int iIndex = 0; CControlUI* pCtrl = NULL; CListContainerElementUI* pListItem = NULL; do { /// 填充之前, 都是重新填充, 将旧的丢掉 /// 反复删除再插入会导致UI挂死, 这里临时做的处理为, 将行内容全部清除和隐藏 iCnt = m_pListFiles->GetCount(); for (iIndex = 0; iIndex < iCnt; iIndex++) { pListItem = (CListContainerElementUI*)m_pListFiles->GetItemAt(iIndex); ClearRow2FileList(pListItem); } } while (0); } void CMainDlg::ClearRow2FileList(CListContainerElementUI* pListItem) { CButtonUI* pCtrlIcon = NULL; CLabelUI* pCtrlFileName = NULL; CLabelUI* pCtrlFileSize = NULL; CLabelUI* pCtrlFileTime = NULL; CLabelUI* pCtrlFileType = NULL; do { if (NULL == pListItem) break; pCtrlIcon = (CButtonUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_FILE_ICON); if (NULL != pCtrlIcon) pCtrlIcon->SetNormalImage(L""); pCtrlFileName = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_FILE_NAME); if (NULL != pCtrlFileName) pCtrlFileName->SetText(L""); pCtrlFileSize = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_SIZE); if (NULL != pCtrlFileSize) pCtrlFileSize->SetText(L""); pCtrlFileTime = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_TIME); if (NULL != pCtrlFileTime) pCtrlFileTime->SetText(L""); pCtrlFileType = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_TYPE); if (NULL != pCtrlFileType) pCtrlFileType->SetText(L""); } while (0); } void CMainDlg::fn_ShowCurTreeNodeFilesInfo() { InsertRow2FileList(m_deqFindData); } void CMainDlg::InsertRow2FileList(std::vector<INFO_LIST_ITEM_DATA*>& deqFindData) { std::deque<INFO_LIST_ITEM_DATA*>::iterator it; int iCnt = 0; int iIndex = 0; int iScrollPos = 0; int iLastScrollPos = 0; int iScrollRange = 0; int iDataIndex = 0; int iDataBeginIndex = 0; int iDataEndIndex = 0; CListContainerElementUI* pListItem = NULL; do { iCnt = deqFindData.size(); if (iCnt <= m_iCntFilesListRowMax) { iDataBeginIndex = 0; iDataEndIndex = (iCnt > 0) ? (iCnt - 1) : 0; } else { iScrollPos = m_pVScrollBarForFilesList->GetScrollPos(); iLastScrollPos = m_pVScrollBarForFilesList->GetLastScrollPos(); iScrollRange = m_pVScrollBarForFilesList->GetScrollRange(); iDataBeginIndex = (int)((1.0f * iScrollPos / iScrollRange) * iCnt); /// @todo 从最下面开始向上移动的一次, 不会显示新的内容 // if (iScrollPos >= iLastScrollPos) { if (iLastScrollPos == (iCnt - 1)) { OutputDebugStringW(L""); } /// 向下移动 if ((iDataBeginIndex + m_iCntFilesListRowMax) >= iCnt) { iDataEndIndex = iCnt - 1; iDataBeginIndex = iDataEndIndex - (m_iCntFilesListRowMax - 1); } else { iDataEndIndex = iDataBeginIndex + (m_iCntFilesListRowMax - 1); } } // else // { // /// 向上移动 // if ((iDataBeginIndex + m_iCntFilesListRowMax) >= iCnt) // { // iDataEndIndex = iDataBeginIndex; // iDataBeginIndex = iDataEndIndex - (m_iCntFilesListRowMax - 1); // } // else // { // iDataBeginIndex = 0; // iDataEndIndex = m_iCntFilesListRowMax - 1; // } // } } iCnt = m_pListFiles->GetCount(); for (iDataIndex = iDataBeginIndex, iIndex = 0; iDataIndex <= iDataEndIndex; iDataIndex++, iIndex++) { if (iIndex < iCnt) { pListItem = (CListContainerElementUI*)m_pListFiles->GetItemAt(iIndex); } else { pListItem = NULL; } if (deqFindData.size() > 0) { /// 插入或更新行 InsertRow2FileList(deqFindData.at(iDataIndex), pListItem); } else { /// 清除行 ClearRow2FileList(pListItem); } } m_pListFiles->Invalidate(); } while (0); } void CMainDlg::InsertRow2FileList(INFO_LIST_ITEM_DATA*& FindData, CListContainerElementUI*& pListItem) { _ASSERT(NULL != FindData); int iTmp = 0; LONGLONG llTime = 0; std::wstring strPicFileType = L""; std::wstring strFileType = L""; BOOL bObjIsDir = FALSE; std::wstring::size_type nPos = std::wstring::npos; std::wstring strFileName = ns_base::A2Wex(ns_base::UTF8ToMB(FindData->cFilePath).c_str()).c_str(); std::wstring strFileSize = ns_base::Size2SizeString(atol(FindData->cFileSize), FALSE).c_str(); std::wstring strFileTime = L""; SYSTEMTIME st; CButtonUI* pCtrlIcon = NULL; CLabelUI* pCtrlFileName = NULL; CLabelUI* pCtrlFileSize = NULL; CLabelUI* pCtrlFileTime = NULL; CLabelUI* pCtrlFileType = NULL; do { if (NULL == m_pListFiles) break; iTmp = m_pListFiles->GetCount(); /// @todo ls 快了8个小时, 要转成本地时间 llTime = ns_base::string2longlong(FindData->cLastWriteTime); if (ns_base::php_time_2_systemtime((long)llTime, &st)) { strFileTime = ns_base::StringFormatV(L"%d-%d-%d %d:%d:%d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } if (0 == stricmp(FindData->cFileType, "type_dir")) { strPicFileType = L"dir.png"; strFileType = L"目录"; bObjIsDir = TRUE; } else { strPicFileType = L"file.png"; strFileType = L"文件"; bObjIsDir = FALSE; } /// 如果(NULL != pListItem), 就是更新了 if (NULL == pListItem) { /// 插入一个文件夹或者文件 CreateListContainerElementUI( &m_PaintManager, pListItem, L"ListItem_File.xml", this); /// 将目录排前面, 文件放后面 m_pListFiles->AddAt( pListItem, 0 /*bObjIsDir ? 0 : m_pListFiles->GetCount()*/); } pCtrlIcon = (CButtonUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_FILE_ICON); if (NULL != pCtrlIcon) pCtrlIcon->SetNormalImage(strPicFileType.c_str()); pCtrlFileName = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_FILE_NAME); if (NULL != pCtrlFileName) { nPos = strFileName.rfind(L'/'); if (std::wstring::npos != nPos) { strFileName = strFileName.substr(nPos + 1, -1); } pCtrlFileName->SetText(strFileName.c_str()); } pCtrlFileSize = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_SIZE); if (NULL != pCtrlFileSize) pCtrlFileSize->SetText(strFileSize.c_str()); pCtrlFileTime = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_TIME); if (NULL != pCtrlFileTime) pCtrlFileTime->SetText(strFileTime.c_str()); pCtrlFileType = (CLabelUI*)pListItem->FindSubControl(LIST_ROW_ELEMENT_NAME_TYPE); if (NULL != pCtrlFileType) pCtrlFileType->SetText(strFileType.c_str()); } while (0); } LRESULT CMainDlg::WndMessageProc_WM_DISP_REFRESH(UINT uMsg, WPARAM wParam, LPARAM lParam) { if (WM_DISP_REFRESH == uMsg) { switch (wParam) { case DISP_REFRESH_CUR_TREE_NODE_FILES_INFO_REMOVE_ALL: InsertRow2FileList_RemoveAll(); m_bMsgProcessOver_RefreshFilesInfo_RemoveAll = TRUE; break; case DISP_REFRESH_CUR_TREE_NODE_FILES_INFO: fn_ShowCurTreeNodeFilesInfo(); m_bMsgProcessOver_RefreshFilesInfo = TRUE; break; case DISP_MSG: ShowMsg(m_strTipMsg.c_str()); break; default: break; } } return S_OK; } void CMainDlg::ShowMsg(const WCHAR* pcMsg) { do { /// 防止显示重复数据时, 由于要加锁判断, 使显示效率降低 if (0 == m_strTipMsgPerv.compare((NULL != pcMsg) ? pcMsg : L"")) break; m_Locker_MainUI.enter(); m_strTipMsg = (NULL != pcMsg) ? pcMsg : L""; m_Locker_MainUI.leave(); if (GetCurrentThreadId() != m_dwMainTID) { ::PostMessageW(this->GetHWND(), WM_DISP_REFRESH, DISP_MSG, 0); } else { m_Locker_MainUI.enter(); m_pStatusMsg->SetText(m_strTipMsg.c_str()); m_Locker_MainUI.leave(); } } while (0); } LRESULT CMainDlg::WndMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL bNeedDefaultProcess = FALSE; do { switch (uMsg) { case WM_DISP_REFRESH: WndMessageProc_WM_DISP_REFRESH(uMsg, wParam, lParam); break; /// 如果窗口的扩展风格 WS_EX_ACCEPTFILES 被禁止, 是接受不到 WM_DROPFILES 消息的 /// 同时, 拖动文件到CMainDlg时, 图标是禁止样式的图标 case WM_DROPFILES: OutputDebugStringW(L""); break; case WM_CREATE: bNeedDefaultProcess = TRUE; break; case WM_SWITCH_VIEW: switch_view((e_view_index)wParam); break; case WM_CLOSE: EntryUiDestory(TRUE); bNeedDefaultProcess = ThreadProcEnd(FALSE); break; default: bNeedDefaultProcess = TRUE; break; } if (bNeedDefaultProcess) return __super::WndMessageProc(uMsg, wParam, lParam); } while (0); return S_OK; } void CMainDlg::InitWindow() { BOOL bRc = FALSE; DWORD dwStyle = 0; UiInit(); } CControlUI* CMainDlg::CreateUiControlByMySelf(LPCTSTR pstrClass) { if (0 == _tcscmp(pstrClass,_T("ButtonGif"))) return new CButtonGifUI; return NULL; } LRESULT CMainDlg::SysMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled) { return __super::SysMessageProc(uMsg, wParam, lParam, bHandled); } void CMainDlg::OnFinalMessage(HWND hWnd) { m_PaintManager.FreeResourceZip(); ///< ! __super::OnFinalMessage(hWnd); } void CMainDlg::Notify(TNotifyUI & msg) { std::wstring strName = L""; do { if (NULL == msg.pSender) { break; } strName = msg.pSender->GetName().GetData(); if (msg.sType == DUI_MSGTYPE_SCROLL) { if (msg.pSender == m_pVScrollBarForFilesList) { ::PostMessage(this->GetHWND(), WM_DISP_REFRESH, DISP_REFRESH_CUR_TREE_NODE_FILES_INFO, 0); } } } while (0); return __super::Notify(msg); } void CMainDlg::OnClick(TNotifyUI& msg) { BOOL bNeedDefaultProcess = FALSE; std::wstring strName = L""; if (NULL != msg.pSender) { strName = msg.pSender->GetName().GetData(); } if (strName == L"btn_close_ui5") { ::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0); } else if (strName == L"btn_run_now") { m_bRunObjProgNow = TRUE; } else { bNeedDefaultProcess = TRUE; } if (bNeedDefaultProcess) __super::OnClick(msg); } LRESULT CMainDlg::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return __super::OnNcHitTest(uMsg, wParam, lParam, bHandled); } void CMainDlg::switch_view(e_view_index PageIndex) { static int iWidth = 0; static int iHeight = 0; do { if (::GetCurrentThreadId() != m_dwMainTID) { ::PostMessageW(this->GetHWND(), WM_SWITCH_VIEW, PageIndex, 0); break; } if (NULL == m_pTabView) break; iWidth = m_pTabView->GetFixedWidth(); iHeight = m_pTabView->GetFixedHeight(); switch (PageIndex) { case e_view_index_start_prog: { if (NULL != m_pPage_StartProg) { m_pTabView->SelectItem(m_pPage_StartProg); } } break; default: break; } } while (0); } void CMainDlg::ThreadProcStart() { if (!m_ThreadManager.IsNeedQuitThread() && !m_ThreadManager.IsThreadRunning()) { m_ThreadManager.SetThreadHandle((HANDLE)_beginthreadex(NULL, 0, &CMainDlg::ThreadProc, (void*)this, 0, NULL)); } } BOOL CMainDlg::ThreadProcEnd(BOOL bStopNow) { BOOL bThreadWasStop = FALSE; do { m_ThreadManager.StopThread(bStopNow, L"m_ThreadManager"); bThreadWasStop = !m_ThreadManager.IsThreadRunning(); } while (0); return bThreadWasStop; } UINT WINAPI CMainDlg::ThreadProc(void* pParam) { UINT uRc = S_FALSE; do { if (NULL == pParam) break; uRc = ((CMainDlg*)pParam)->ThreadProc(); } while (0); return uRc; } UINT WINAPI CMainDlg::ThreadProc() { BOOL bScrollBarEnable = FALSE; int iCntData = 0; std::wstring strMsg = L""; // int iTest = 0; // int iTestPrev = 0x7fffffff; // // // while (++iTest > 0) // // { // // iTestPrev = iTest; // // } // // // iTestPrev 2147483647 int // // iTestPrev 0x7fffffff int // // iTestPrev /= 1000000; ///< 百万级 // // iTestPrev = 2147 ShowMsg(L"正在准备数据, 请稍后..."); PrepareData(); /// 现在采用只填充一个7行的List, 具体填充的内容由ScorllBar来决定 iCntData = m_deqFindData.size(); bScrollBarEnable = iCntData > m_iCntFilesListRowMax; m_pVScrollBarForFilesList->SetVisible(TRUE == bScrollBarEnable); m_pVScrollBarForFilesList->SetEnabled(TRUE == bScrollBarEnable); if (bScrollBarEnable) { m_pVScrollBarForFilesList->SetScrollPos(0); m_pVScrollBarForFilesList->SetScrollRange((iCntData > 0) ? iCntData : 1); } m_pContainerForVScrollBarForFilesList->SetFixedWidth(bScrollBarEnable ? m_pVScrollBarForFilesList->GetFixedWidth() : 1); m_pContainerForVScrollBarForFilesList->Invalidate(); ShowMsg(L"数据准备完成"); /// 进行首次UI刷新, 让List显示数据 do { /// 移除files m_bMsgProcessOver_RefreshFilesInfo_RemoveAll = FALSE; ::PostMessage(this->GetHWND(), WM_DISP_REFRESH, DISP_REFRESH_CUR_TREE_NODE_FILES_INFO_REMOVE_ALL, 0); while (!m_bMsgProcessOver_RefreshFilesInfo_RemoveAll) { if (IsEntryUiDestory()) break; ::Sleep(10); } if (IsEntryUiDestory()) break; /// 刷新files m_bMsgProcessOver_RefreshFilesInfo = FALSE; ::PostMessage(this->GetHWND(), WM_DISP_REFRESH, DISP_REFRESH_CUR_TREE_NODE_FILES_INFO, 0); while (!m_bMsgProcessOver_RefreshFilesInfo) { if (IsEntryUiDestory()) break; ::Sleep(10); } } while (0); do { ::Sleep(20); if (IsEntryUiDestory()) break; if (m_ThreadManager.IsNeedQuitThread()) break; if (ns_base::IsMutextExist(PE_INSTANCE_NAME_CMD_LET_DLG_NOTIFY_QUIT)) { ::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0); break; } if (m_bRunObjProgNow) { m_bRunObjProgNow = FALSE; RunObjProg(); ::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0); break; } } while (1); clearFindData(); ::PostMessageW(this->GetHWND(), WM_CLOSE, 0, 0); return S_OK; } void CMainDlg::PrepareData() { int iTmp = 0; DWORD dwTickBegin = 0; DWORD dwTickEnd = 0; std::wstring strTmp = L""; int iIndex = 0; INFO_LIST_ITEM_DATA* pData = NULL; UINT uTimeVal = 0; srand((UINT)time(NULL)); dwTickBegin = GetTickCount(); for (iIndex = 0; iIndex < m_iDataSoruceRecordCnt; iIndex++) { dwTickEnd = GetTickCount(); if ((dwTickEnd - dwTickBegin) > 500) { dwTickBegin = GetTickCount(); strTmp = ns_base::StringFormatV(L"数据准备进度%.2f%%", (1.0f * iIndex / m_iDataSoruceRecordCnt) * 100); ShowMsg(strTmp.c_str()); } pData = new INFO_LIST_ITEM_DATA; _ASSERT(NULL != pData); ::ZeroMemory(pData, sizeof(INFO_LIST_ITEM_DATA)); uTimeVal = (UINT)time(NULL); uTimeVal += ns_base::RandRange(-10, 10); strcpy_s(pData->cCreationTime, ns_base::StringFormatVA("%u", uTimeVal).c_str()); strcpy_s(pData->cFileSize, ns_base::StringFormatVA("%d", ns_base::RandRange(100, 1000)).c_str()); iTmp = ns_base::RandRange(1, 2); strcpy_s(pData->cFileType, ns_base::StringFormatVA("type_%s", (1 == iTmp) ? "dir" : "file").c_str()); if (1 == iTmp) { strcpy_s(pData->cFilePath, ns_base::StringFormatVA("TestDir_%d", iIndex).c_str()); } else { strcpy_s(pData->cFilePath, ns_base::StringFormatVA("TestFile_%d.txt", iIndex).c_str()); } strcpy_s(pData->cLastWriteTime, ns_base::StringFormatVA("%u", uTimeVal + ns_base::RandRange(1, 10)).c_str()); m_deqFindData.push_back(pData); } } void CMainDlg::RunObjProg() { ns_base::CreateProcessEx(L"C:\\Windows\\System32\\notepad.exe", L"", FALSE, TRUE); }
xml文件:
<!-- dlgNotify_MainDlg.xml --> <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <Window size="595,412"> <Font name="微软雅黑" size="11" bold="false" italic="false" /> <Font name="微软雅黑" size="12" bold="false" italic="false" /> <Font name="微软雅黑" size="13" bold="false" italic="false" /> <Font name="微软雅黑" size="14" bold="false" italic="false" /> <Font name="微软雅黑" size="15" bold="false" italic="false" /> <Font name="微软雅黑" size="16" bold="false" italic="false" /> <Font name="微软雅黑" size="14" bold="true" italic="false" /> <Default name="VScrollBar" value="button1normalimage="file='scrollbar.bmp' source='0,90,16,106' mask='#FFFF00FF'" button1hotimage="file='scrollbar.bmp' source='18,90,34,106' mask='#FFFF00FF'" button1pushedimage="file='scrollbar.bmp' source='36,90,52,106' mask='#FFFF00FF'" button1disabledimage="file='scrollbar.bmp' source='54,90,70,106' mask='#FFFF00FF'" button2normalimage="file='scrollbar.bmp' source='0,108,16,124' mask='#FFFF00FF'" button2hotimage="file='scrollbar.bmp' source='18,108,34,124' mask='#FFFF00FF'" button2pushedimage="file='scrollbar.bmp' source='36,108,52,124' mask='#FFFF00FF'" button2disabledimage="file='scrollbar.bmp' source='54,108,70,124' mask='#FFFF00FF'" thumbnormalimage="file='scrollbar.bmp' source='0,126,16,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbhotimage="file='scrollbar.bmp' source='18,126,34,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbpushedimage="file='scrollbar.bmp' source='36,126,52,142' corner='2,2,2,2' mask='#FFFF00FF'" thumbdisabledimage="file='scrollbar.bmp' source='54,126,70,142' corner='2,2,2,2' mask='#FFFF00FF'" railnormalimage="file='scrollbar.bmp' source='0,144,16,160' corner='2,2,2,2' mask='#FFFF00FF'" railhotimage="file='scrollbar.bmp' source='18,144,34,160' corner='2,2,2,2' mask='#FFFF00FF'" railpushedimage="file='scrollbar.bmp' source='36,144,52,160' corner='2,2,2,2' mask='#FFFF00FF'" raildisabledimage="file='scrollbar.bmp' source='54,144,70,160' corner='2,2,2,2' mask='#FFFF00FF'" bknormalimage="file='scrollbar.bmp' source='0,162,16,178' corner='2,2,2,2' mask='#FFFF00FF'" bkhotimage="file='scrollbar.bmp' source='18,162,34,178' corner='2,2,2,2' mask='#FFFF00FF'" bkpushedimage="file='scrollbar.bmp' source='36,162,52,178' corner='2,2,2,2' mask='#FFFF00FF'" bkdisabledimage="file='scrollbar.bmp' source='54,162,70,178' corner='2,2,2,2' mask='#FFFF00FF'" " /> <Default name="HScrollBar" value="button1normalimage="file='scrollbar.bmp' source='0,0,16,16' mask='#FFFF00FF'" button1hotimage="file='scrollbar.bmp' source='18,0,34,16' mask='#FFFF00FF'" button1pushedimage="file='scrollbar.bmp' source='36,0,52,16' mask='#FFFF00FF'" button1disabledimage="file='scrollbar.bmp' source='54,0,70,16' mask='#FFFF00FF'" button2normalimage="file='scrollbar.bmp' source='0,18,16,34' mask='#FFFF00FF'" button2hotimage="file='scrollbar.bmp' source='18,18,34,34' mask='#FFFF00FF'" button2pushedimage="file='scrollbar.bmp' source='36,18,52,34' mask='#FFFF00FF'" button2disabledimage="file='scrollbar.bmp' source='54,18,70,34' mask='#FFFF00FF'" thumbnormalimage="file='scrollbar.bmp' source='0,36,16,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbhotimage="file='scrollbar.bmp' source='18,36,34,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbpushedimage="file='scrollbar.bmp' source='36,36,52,52' corner='2,2,2,2' mask='#FFFF00FF'" thumbdisabledimage="file='scrollbar.bmp' source='54,36,70,52' corner='2,2,2,2' mask='#FFFF00FF'" railnormalimage="file='scrollbar.bmp' source='0,54,16,70' corner='2,2,2,2' mask='#FFFF00FF'" railhotimage="file='scrollbar.bmp' source='18,54,34,70' corner='2,2,2,2' mask='#FFFF00FF'" railpushedimage="file='scrollbar.bmp' source='36,54,52,70' corner='2,2,2,2' mask='#FFFF00FF'" raildisabledimage="file='scrollbar.bmp' source='54,54,70,70' corner='2,2,2,2' mask='#FFFF00FF'" bknormalimage="file='scrollbar.bmp' source='0,72,16,88' corner='2,2,2,2' mask='#FFFF00FF'" bkhotimage="file='scrollbar.bmp' source='18,72,34,88' corner='2,2,2,2' mask='#FFFF00FF'" bkpushedimage="file='scrollbar.bmp' source='36,72,52,88' corner='2,2,2,2' mask='#FFFF00FF'" bkdisabledimage="file='scrollbar.bmp' source='54,72,70,88' corner='2,2,2,2' mask='#FFFF00FF'" " /> <Container float="true" pos="0,0,0,0" width="595" height="412"> <TabLayout name="TabLayout_setup_now" width="581" height="380"> <Container name="Container_page_install_over" bkimage="bg_setup_now.png"> <VerticalLayout> <Container width="595" height="40"> <Button name="btn_close_ui5" float="true" pos="554,0,0,0" width="40" height="39" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" align="center" normalimage="btn_close_n.png" hotimage="btn_close_h.png" pushedimage="btn_close_d.png" /> </Container> <Container> <HorizontalLayout> <Container width="10" /> <Container> <HorizontalLayout> <Container name="Container_UI_for_tree_view" > <List name="list_files" width="660" height="527" bordersize="1" bkcolor="#FFC0C0C0" itemtextcolor="#FF000000" itemselectedtextcolor="#FF000000" itemselectedbkcolor="#FFC1E3FF" itemhottextcolor="#FF000000" itemhotbkcolor="#FFE9F5FF" itemdisabledtextcolor="#FFCCCCCC" itemdisabledbkcolor="#FFFFFFFF" vscrollbar="true" hscrollbar="true"> <ListHeader> <ListHeaderItem name="HeadItem_file_name" text="名称" width="258" height="31" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_normal.png" hotimage="headerctrl_hot.png" pushedimage="headerctrl_down.png" sepimage="header_Item_boundary.png" sepwidth="1" > <Container> <HorizontalLayout sepwidth="1" > <Container /> <Container width="1" bkimage="header_Item_boundary.png" /> </HorizontalLayout> </Container> </ListHeaderItem> <ListHeaderItem name="HeadItem_file_size" text="大小" width="73" height="31" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_normal.png" hotimage="headerctrl_hot.png" pushedimage="headerctrl_down.png" sepimage="header_Item_boundary.png" sepwidth="1" > <Container> <HorizontalLayout sepwidth="1" > <Container /> <Container width="1" bkimage="header_Item_boundary.png" /> </HorizontalLayout> </Container> </ListHeaderItem> <ListHeaderItem name="HeadItem_file_type" text="类型" width="73" height="31" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_normal.png" hotimage="headerctrl_hot.png" pushedimage="headerctrl_down.png" sepimage="header_Item_boundary.png" sepwidth="1" > <Container> <HorizontalLayout sepwidth="1" > <Container /> <Container width="1" bkimage="header_Item_boundary.png" /> </HorizontalLayout> </Container> </ListHeaderItem> <ListHeaderItem name="HeadItem_file_time" text="时间" width="170" height="31" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_normal.png" hotimage="headerctrl_hot.png" pushedimage="headerctrl_down.png" sepimage="header_Item_boundary.png" sepwidth="1" > <Container> <HorizontalLayout sepwidth="1" > <Container /> <Container width="1" bkimage="header_Item_boundary.png" /> </HorizontalLayout> </Container> </ListHeaderItem> <ListHeaderItem name="HeadItemhave5" text="" width="660" height="31" textcolor="#FF6c6c6c" disabledtextcolor="#FFA7A6AA" align="center" font="1" normalimage="headerctrl_normal.png" hotimage="headerctrl_hot.png" pushedimage="headerctrl_down.png" /> </ListHeader> </List> </Container> <Container name="container_for_v_scrollbar_for_list" width="20"> <!-- 这里不用设置准确的滚动条宽度,程序里会自动设置 --> <ScrollBar name="scrollbar_for_files_list" /> </Container> </HorizontalLayout> </Container> <Container width="10" /> </HorizontalLayout> </Container> <Container height="80"> <Button name="btn_run_now" float="true" pos="390,11,0,0" width="197" height="59" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" align="center" normalimage="btn_run_now_n.png" hotimage="btn_run_now_h.png" pushedimage="btn_run_now_d.png" /> <Label name="Label_UI_MSG" float="true" pos="6,11,0,0" width="374" height="59" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" /> </Container> </VerticalLayout> </Container> </TabLayout> </Container> </Window>
<!-- ListItem_Files.xml --> <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <Window size="666,61" > <Font name="微软雅黑" size="10" bold="false" italic="false" /> <Font name="微软雅黑" size="11" bold="false" italic="false" /> <Font name="微软雅黑" size="12" bold="false" italic="false" /> <Font name="微软雅黑" size="13" bold="false" italic="false" /> <Font name="微软雅黑" size="14" bold="false" italic="false" /> <Font name="微软雅黑" size="15" bold="false" italic="false" /> <Font name="微软雅黑" size="16" bold="false" italic="false" /> <Font name="微软雅黑" size="17" bold="false" italic="false" /> <Font name="微软雅黑" size="18" bold="false" italic="false" /> <Font name="微软雅黑" size="19" bold="false" italic="false" /> <ListContainerElement name="Container_file_list_item" width="660" height="61"> <Container name="Container_1" width="258"> <HorizontalLayout> <Container> <Button name="btn_row_file_icon" float="true" pos="11,6,0,0" width="48" height="48" textcolor="#FF000000" disabledtextcolor="#FFA7A6AA" align="center" normalimage="" hotimage="" pushedimage="" /> <Label name="label_row_file_name" float="true" endellipsis="false" text="名称" textpadding="0,0,0,18" pos="66,0,0,0" width="600" height="61" textcolor="#FF2C2C2C" disabledtextcolor="#FFA7A6AA" font="1" align="wrap" /> </Container> </HorizontalLayout> </Container> <Container name="Container_2" width="73"> <HorizontalLayout> <Container> <Label name="label_row_size" endellipsis="false" text="大小" float="true" pos="0,0,0,0" width="73" height="61" textcolor="#FF656565" disabledtextcolor="#FFA7A6AA" font="1" align="center" /> </Container> </HorizontalLayout> </Container> <Container name="Container_3" width="73"> <HorizontalLayout> <Container> <Label name="label_row_type" endellipsis="false" text="类型" float="true" pos="0,0,0,0" width="73" height="61" textcolor="#FF656565" disabledtextcolor="#FFA7A6AA" font="1" align="center" /> </Container> </HorizontalLayout> </Container> <Container name="Container_4" width="170" > <HorizontalLayout> <Container> <Label name="label_row_time" endellipsis="false" text="时间" float="true" pos="0,0,0,0" width="170" height="61" textcolor="#FF656565" disabledtextcolor="#FFA7A6AA" font="1" align="center" /> </Container> </HorizontalLayout> </Container> </ListContainerElement> </Window>
相关文章推荐
- JAVA UUID 生成
- easyiui textbox 光标 聚焦
- 程序检测系统是bios引导还是uefi引导
- UITabbarViewController+Navigation框架下的子视图的跳转示例之一
- UIActionSheet的常见用法
- poj 2051 priority_queue应用
- CF_313B_IlyaAndQueries
- 08-排序3. Talent and Virtue (25)
- 调用[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad判断设备
- UE4 WorldPositionOffset
- 【已解决】Request exceeded the limit of 10 internal redirects due to probable configuration error.
- 关于UIView的autoresizingMask属性的研究
- UE3 供游戏性程序员的使用的性能最优化方法
- Codeforces 313B : Ilya and Queries
- UE4 Light Propagation Volumes
- poj--2778DNA Sequence+AC自动机+矩阵快速幂
- A Flexible New Technique for Camera Calibration
- IOS生成UUID
- [LeedCode OJ]#232 Implement Queue using Stacks
- [LeedCode OJ]#225 Implement Stack using Queues