基于MFC实现多线程进度条
先看下效果,MFC对话框中实现多线程进度条,对话框支持拖拽不卡死。
直接上代码
我这里提供完整的对话框代码:
// MultiThreadProgressDlg.h: 头文件 // #pragma onandroidce // CMultiThreadProgressDlg 对话框 class CMultiThreadProgressDlg : public CDialogEx { // 构造 public: CMultiThreadProgressDlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_MULTITHREADPROGRESS_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg voiandroidd OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedOk(); CProgressCtrl m_hThread1; CProgressCtrl m_hThread2; CProgressCtrl m_hThread3; static dwORD _stdcall ThreadOne(LPVOID IpParameter); static DWORD _stdcall ThreadTwo(LPVOID IpParameter); static DWORD _stdcall ThreadThree(LPVOID IpParameter); HANDLE m_hThreadOne; HANDLE m_hThreadTwo; HANDLE m_hThreadThree; };
然后是实现文件
// MultiThreadProgressDlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "MultiThreadProgress.h" #include "MultiThreadProgressDlg.h" #include "afxdialogex.h" #ifdef _DEBUG编程客栈 #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CMultiThreadProgressDlg 对话框 CMultiThreadProgressDlg::CMultiThreadProgressDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MULTITHREADPROGRESS_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMultiThreadProgressDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_PROGRESS1, m_hThread1); DDX_Control(pDX, IDC_PROGRESS2, m_hThread2); DDX_Control(pDX, IDC_PROGRESS3, m_hThread3); } BEGIN_MESSAGE_MAP(CMultiThreadProgressDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CMultiThreadProgressDlg::OnBnClickedOk) END_MESSAGE_MAP() // CMultiThreadProgressDlg 消息处理程序 BOOL CMultiThreadProgressDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 m_hThread1.SetRange(0, 100000); m_hThread2.http://www.devze.comSetRange(0, 100000); m_hThread3.SetRange(0, 100000); //创建线程 m_hThreadOne = CreateThread(NULL, 100, ThreadOne, (void*)this, CREATE_SUSPENDED, NULL); // CREATE_SUSPENDED标识创建的线程可以被挂起的 SetThreadPriority(m_hThreajsdOne, THREAD_PRIORITY_ABOVE_NORMAL); //标识创建的线程具有的优先级别 m_hThreadTwo = CreateThread(NULL, 100, ThreadTwo, (void*)this, CREATE_SUSPENDED, NULL); SetThreadPriority(m_hThreadTwo, THREAD_PRIORITY_NORMAL); m_hThreadThree = CreateThread(NULL, 100, ThreadThree, (void*)this, CREATE_SUSPENDED, NULL); SetThreadPriority(m_hThreadThree, THREAD_PRIORITY_BELOW_NORMAL); //启动线程 ResumeThread(m_hThreadOne); ResumeThread(m_hThreadTwo); ResumeThread(m_hThreadThree); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMultiThreadProgressDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMultiThreadProgressDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<wpARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMultiThreadProgressDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CMultiThreadProgressDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); } DWORD _stdcall CMultiThreadProgressDlg::ThreadOne(LPVOID IpParameter) { CMultiThreadProgressDlg* pDlg = (CMultiThreadProgressDlg*)IpParameter; int low, high, pos; pos = pDlg->m_hThread1.GetPos(); pDlg->m_hThread1.GetRange(low, high); while (pos < high) { pos = pDlg->m_hThread1.GetPos(); Sleep(10); pDlg->m_hThread1.SetPos(pos + 1); } pDlg->m_hThread1.SetPos(0); return 0; } DWORD _stdcall CMultiThreadProgressDlg::ThreadTwo(LPVOID IpParameter) { CMultiThreadProgressDlg* pDlg = (CMultiThreadProgressDlg*)IpParameter; int low, high, pos; pos = pDlg->m_hThread2.GetPos(); pDlg->m_hThread2.GetRange(low, high); while (pos < high) { pos = pDlg->m_hThread2.GetPos(); Sleep(10); pDlg->m_hThread2.SetPos(pos + 1); } pDlg->m_hThread2.SetPos(0); return 0; } DWORD _stdcall CMultiThreadProgressDlg::ThreadThree(LPVOID IpParameter) { CMultiThreadProgressDlg* pDlg = (CMultiThreadProgressDlg*)IpParameter; int low, high, pos; pos = pDlg->m_hThread3.GetPos(); pDlg->m_hThread3.GetRange(low, high); while (pos < high) { pos = pDlg->m_hThread3.GetPos(); Sleep(10); pDlg->m_hThread3.SetPos(pos + 1); } pDlg->m_hThread3.SetPos(0); return 0; }
直接编译运行,即可看到效果。
为了进一步研究动态添加进度条,于是我写了下面这个小程序,可以根据对话框的大小,动态增减进度条的个数,其中宽度为当前对话框的宽度:
直接上完整代码:
// DynamicProgressBarsDlg.h: 头文件 // #pragma once #include <vector> // CDynamicProgressBarsDlg 对话框 class CDynamicProgressBarsDlg : public CDialogEx { // 构造 public: CDynamicProgressBarsDlg(CWnd* pParent = nullptr); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_DYNAMICPROGRESSBARS_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 //创建一个进度条 CProgressCtrl* CreateProgressBar(const CRect rect); //进度条指针 std::vector<CProgressCtrl*> m_vpPrgoressCtrl; int m_nShowCount = 0; // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnSize(UINT nType, int cx, int cy); };
实现文件:
// DynamicProgressBarsDlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "DynamicProgressBars.h" #include "DynamicProgressBarsDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif #define IDC_PRG_START 1000 // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CDynamicProgressBarsDlg 对话框 CDynamicProgressBarsDlg::CDynamicProgressBarsDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DYNAMICPROGRESSBARS_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CDynamicProgressBarsDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } CProgressCtrl* CDynamicProgressBarsDlg::CreateProgressBar(const CRect rect) { //创建一个进度条 CProgressCtrl* pProgress = new CProgressCtrl; // 创建进度条 if (!pProgress->Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, rect, this, IDC_PRG_START)) { TRACE(_T("创建进度条失败!\n")); delete pProgress; return NULL; } // 设置进度条范围和初始位置 pProgress->SetRange(0, 100); pProgress->SetPos(60); return pProgress; } BEGIN_MESSAGE_MAP(CDynamicProgressBarsDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_SIZE() END_MESSAGE_MAP() // CDynamicProgressBarsDlg 消息处理程序 BOOL CDynamicProgressBarsDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != nullptr) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CDynamicProgressBarsDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CDynamicProgressBarsDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CDynamicProgressBarsDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CDynamicProgressBarsDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码 CRect rectWindow; GetWindowRect(&rectWindow); int nWidth = rectWindow.Width(); int nHeight = rectWindow.Height(); int nNewCount = nHeight / 60; size_t nProgressBarCount = m_vpPrgoressCtrl.size(); if (nProgressBarCount < nNewCount) { for (size_t i = m_nShowCount; i < nNewCount; ++i) { CRect rect(0, i * 60, nWidth, i * 60 + 55); if (CProgressCtrl* pCtrl = CreateProgressBar(rect)) { m_vpPrgoressCtrl.emplace_back(pCtrl); } } m_nShowCount = nNewCount; } else { for (size_t i = 0; i < m_nShowCount; ++i) { if (CProgressCtrl* pCtrl = m_vpPrgoressCtrl[i]) { pCtrl->ShowWindow(SW_SHOW); } } for (size_t i = nNewCount; i < nProgressBarCount; ++i) { if (CProgressCtrl * pCtrl = m_vpPrgoressCtrl[i]) { pCtrl->ShowWindow(SW_HIDE); } } } }
关键代码在OnSize()函数中。
到此这篇关于基于MFC实现多线程进度条的文章就介绍到这了,更多相关MFC多线程进度条内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论