基于MFC實現多線程進度條
更新時間:2025年01月22日 11:08:49 作者:秋月的私語
這篇文章主要為大家詳細介紹了如何基于MFC實現多線程進度條效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
先看下效果,MFC對話框中實現多線程進度條,對話框支持拖拽不卡死。

直接上代碼
我這里提供完整的對話框代碼:
// MultiThreadProgressDlg.h: 頭文件
//
#pragma once
// 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 void 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);
}
}
// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動
// 執(zhí)行此操作
SetIcon(m_hIcon, TRUE); // 設置大圖標
SetIcon(m_hIcon, FALSE); // 設置小圖標
// TODO: 在此添加額外的初始化代碼
m_hThread1.SetRange(0, 100000);
m_hThread2.SetRange(0, 100000);
m_hThread3.SetRange(0, 100000);
//創(chuàng)建線程
m_hThreadOne = CreateThread(NULL, 100, ThreadOne, (void*)this, CREATE_SUSPENDED, NULL); // CREATE_SUSPENDED標識創(chuàng)建的線程可以被掛起的
SetThreadPriority(m_hThreadOne, THREAD_PRIORITY_ABOVE_NORMAL); //標識創(chuàng)建的線程具有的優(yōu)先級別
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);
// 使圖標在工作區(qū)矩形中居中
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;
}直接編譯運行,即可看到效果。

為了進一步研究動態(tài)添加進度條,于是我寫了下面這個小程序,可以根據對話框的大小,動態(tài)增減進度條的個數,其中寬度為當前對話框的寬度:

直接上完整代碼:
// 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 支持
//創(chuàng)建一個進度條
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)
{
//創(chuàng)建一個進度條
CProgressCtrl* pProgress = new CProgressCtrl;
// 創(chuàng)建進度條
if (!pProgress->Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, rect, this, IDC_PRG_START))
{
TRACE(_T("創(chuàng)建進度條失??!\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);
}
}
// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動
// 執(zhí)行此操作
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);
// 使圖標在工作區(qū)矩形中居中
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多線程進度條內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

