MFC通过多线程实现拷贝文件并显示进度条

1.实现目标

通过在主窗口获取文件原路径和目标路径,主窗口点击开始传输后进行传输文件,同时子窗口显示文件传输进度以及百分比,子窗口传输文件完成后,子窗口实现自动关闭。主窗口点击挂起时候,文件暂停传输,点击唤醒文件继续传输,点击终止,直接退出。

2.实现效果

2.1主窗口

 2.2子窗口:

 3.实现代码

项目名称:MFCDay71

子窗口实现文件:


// MFCday71Dlg.cpp : 实现文件
//

#include "stdafx.h"
#include "MFCday71.h"
#include "MFCday71Dlg.h"
#include "afxdialogex.h"
#include "TipDlg.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)
{
        CTipDlg m_pTipDlg = NULL;
        
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CMFCday71Dlg 对话框


CMFCday71Dlg::CMFCday71Dlg(CWnd* pParent /*=NULL*/)
        : CDialogEx(IDD_MFCDAY71_DIALOG, pParent)
        , m_MainDlg(0)
{
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCday71Dlg::DoDataExchange(CDataExchange* pDX)
{
        CDialogEx::DoDataExchange(pDX);
        //两个编辑框的变量
        DDX_Control(pDX, IDC_EDIT1, m_Edit1);
        DDX_Control(pDX, IDC_EDIT2, m_Edit2);
        
}

BEGIN_MESSAGE_MAP(CMFCday71Dlg, CDialogEx)
        ON_WM_SYSCOMMAND()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()
        ON_BN_CLICKED(IDC_BUTTON1, &CMFCday71Dlg::OnBnClickedButton1)
        ON_BN_CLICKED(IDC_BUTTON2, &CMFCday71Dlg::OnBnClickedButton2)
        ON_BN_CLICKED(IDC_BUTTON3, &CMFCday71Dlg::OnBnClickedButton3)
        ON_BN_CLICKED(IDC_BUTTON4, &CMFCday71Dlg::OnBnClickedButton4)
        ON_BN_CLICKED(IDC_BUTTON5, &CMFCday71Dlg::OnBnClickedButton5)
        ON_BN_CLICKED(IDC_BUTTON6, &CMFCday71Dlg::OnBnClickedButton6)
        ON_WM_TIMER()
END_MESSAGE_MAP()


// CMFCday71Dlg 消息处理程序

BOOL CMFCday71Dlg::OnInitDialog()
{
        CDialogEx::OnInitDialog();

        // 将“关于...”菜单项添加到系统菜单中。

        // IDM_ABOUTBOX 必须在系统命令范围内。
        ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
        ASSERT(IDM_ABOUTBOX < 0xF000);

        CMenu* pSysMenu = GetSystemMenu(FALSE);
        if (pSysMenu != NULL)
        {
                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 CMFCday71Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
        if ((nID & 0xFFF0) == IDM_ABOUTBOX)
        {
                CAboutDlg dlgAbout;
                dlgAbout.DoModal();
        }
        else
        {
                CDialogEx::OnSysCommand(nID, lParam);
        }
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMFCday71Dlg::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 CMFCday71Dlg::OnQueryDragIcon()
{
        return static_cast<HCURSOR>(m_hIcon);
}


//打开:按钮1点击事件 IDC_BUTTON1
void CMFCday71Dlg::OnBnClickedButton1()
{
        // TODO: Add your control notification handler code here
        CString FileName;

        TCHAR szFilter[] = _T("文本文件(*.txt)||DAT文件(*.dat)||所有文件(*.*)||");

        CFileDialog fileDlg(TRUE, _T("txt"), NULL, 0, szFilter, this);
        if (IDOK == fileDlg.DoModal()) {
                FileName = fileDlg.GetPathName();
        }
        m_Edit1.SetWindowText(FileName);
}


//保存到:按钮2点击事件 IDC_BUTTON2
void CMFCday71Dlg::OnBnClickedButton2()
{
        // TODO: Add your control notification handler code here
        CString FileName;
        CFileDialog dlgFile(FALSE, _T("*.txt"), NULL, OFN_HIDEREADONLY, _T("Describe File(*.txt)|*.txt|*.dat|All Files(*.*)|*.*||"), NULL);
        if (IDOK == dlgFile.DoModal())
        {
                FileName = dlgFile.GetPathName();
        }
        else
        {
                return;
        }
        m_Edit2.SetWindowText(FileName);
}


//按钮3的点击事件:点击后跳转弹窗
void CMFCday71Dlg::OnBnClickedButton3()
{
        
        // TODO: Add your control notification handler code here
        //创建子窗口指针
        m_pTipDlg = new CTipDlg();
        //弹窗
        m_pTipDlg->Create(IDD_DIALOG1, this);
        m_pTipDlg->ShowWindow(SW_SHOW);
        UpdateData(TRUE);
        
        //创建子对话框指针,存储路径 用来传递参数
        CString a, b;
        GetDlgItemText(IDC_EDIT1, a);
        GetDlgItemText(IDC_EDIT2, b);
        //子窗口指针存储两个路径
        //m_pTipDlg = new CTipDlg();
        m_pTipDlg->m_strSrcPath = a;
        m_pTipDlg->m_strDestPath = b;
        
        //拷贝文件的时候开启进度条线程
        hThread = CreateThread(NULL, 0, ThreadSpeed, m_pTipDlg, 0, NULL);

        //点击事件完成后,禁止点击
        GetDlgItem(IDC_BUTTON3)->EnableWindow(FALSE);

}


//线程函数的实现
DWORD CMFCday71Dlg::ThreadSpeed(LPVOID lpParameter)
{
        DOUBLE nFileSize = 0;
        DOUBLE nTotalBytesRead = 0;
        DWORD dwBytesRead = 0;
        BYTE buffer[1024];

        // 解析传入的参数,获取源文件和目标文件路径
        CTipDlg *m_pTipDlg = (CTipDlg*)lpParameter;

        //两个文件路径:m_pTipDlg->m_strSrcPath, m_pTipDlg->m_strDestPath
        //BOOL m = CopyFile(m_pTipDlg->m_strSrcPath, m_pTipDlg->m_strDestPath, FALSE);

        // 打开源文件和目标文件
        CFile sourceFile(m_pTipDlg->m_strSrcPath, CFile::modeRead | CFile::shareDenyWrite);
        CFile targetFile(m_pTipDlg->m_strDestPath, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);

        // 获取源文件大小
        nFileSize = sourceFile.GetLength();

        //将原路径和目标路径写在静态文本中
        //m_pTipDlg->GetDlgItem(IDC_STATIC3)->SetWindowText(m_pTipDlg->m_strSrcPath);
        //m_pTipDlg->GetDlgItem(IDC_STATIC4)->SetWindowText(m_pTipDlg->m_strSrcPath);

        // 拷贝文件:读1024个字节进入缓存区
        while (dwBytesRead = sourceFile.Read(buffer, sizeof(buffer)))
        {
                //从缓冲区 写字节
                targetFile.Write(buffer, dwBytesRead);
                //累计加入字节
                nTotalBytesRead += dwBytesRead;

                // 更新进度条
                int nProgress = (int)((nTotalBytesRead / nFileSize) * 100);
                //PBM_DELTAPOS 在当前位置上加上一个值,绘制进度条的新位置(返回值是原位置的值)
                Sleep(500);
                //子窗口指针指向进度条(设置进度栏控件的当前位置,并重绘进度栏以反映新位置)
                m_pTipDlg->m_progress1.SetPos(nProgress);

                //将进度写进静态文本框
                CString strPercent;
                strPercent.Format(_T("%d"), nProgress);
                m_pTipDlg->GetDlgItem(IDC_STATIC)->SetWindowText(strPercent + "%");

                if (nProgress == 100) {
                        //发送消息给主线程  用来关闭进度条对话框
                        m_pTipDlg->PostMessage(WM_DESTROY, 0, 0);
                }

        }

        // 关闭文件
        sourceFile.Close();
        targetFile.Close();
        
        return TRUE;
}



//按钮4 线程挂起
void CMFCday71Dlg::OnBnClickedButton4()
{
        // TODO: Add your control notification handler code here
        SuspendThread(hThread);  //挂起线程函数,参数为线程句柄
}

//按钮5 线程唤醒
void CMFCday71Dlg::OnBnClickedButton5()
{
        // TODO: Add your control notification handler code here
        ResumeThread(hThread); //唤醒挂起的线程
}

//按钮6 线程终止
void CMFCday71Dlg::OnBnClickedButton6()
{
        // TODO: Add your control notification handler code here
        //TerminateThread(m_ThreadSpeed, 0);
        //发送WM_CLOSE消息关闭窗口,退出全部程序
        //SendMessage(WM_CLOSE); 
}

//对话框实现的WM_TIMER消息,与定时器有关
//当我们按钮设置了定时器.则这个消息回来.每100毫秒一次
void CMFCday71Dlg::OnTimer(UINT_PTR nIDEvent)
{
        // TODO: Add your message handler code here and/or call default

        CDialogEx::OnTimer(nIDEvent);
}

子窗口实现文件:

// TipDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MFCday71.h"
#include "TipDlg.h"
#include "afxdialogex.h"
#include "MFCday71Dlg.h"

// CTipDlg dialog

IMPLEMENT_DYNAMIC(CTipDlg, CDialogEx)

CTipDlg::CTipDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_DIALOG1, pParent)
{

}

CTipDlg::~CTipDlg()
{
}

void CTipDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	//进度条的变量
	DDX_Control(pDX, IDC_PROGRESS1, m_progress1);

	DDX_Control(pDX, IDC_STATIC3, m_Static3);
	DDX_Control(pDX, IDC_STATIC4, m_Static4);
}


BEGIN_MESSAGE_MAP(CTipDlg, CDialogEx)
	ON_WM_DESTROY()
END_MESSAGE_MAP()


// CTipDlg message handlers


void CTipDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: Add your message handler code here
	//MessageBox(_T("wee"));
	// 关闭进度条(模式)对话框
	EndDialog(0);
}

4.注意

以上支持VS-2015,只是个小练习,其中有很多不足。同时文章省略了各种消息函数的添加,但是注释都有,可根据其他文档进行自行学习添加。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MFC拷贝文件夹并显示进度条可以通过以下步骤实现。首先,我们需要使用CFileFind类来获取文件夹中的所有文件和子文件夹。然后,我们可以使用SHFileOperation函数来拷贝文件夹,这个函数可以在后台进行拷贝操作,我们可以通过设置FOF_SIMPLEPROGRESS标志来显示一个简单的进度条。另外,我们还可以通过CProgressCtrl类来创建一个更加自定义的进度条,并在拷贝过程中不断更新进度条的进度。在文件拷贝完成后,我们需要关闭进度条显示拷贝结果给用户。 以下是代码示例: // 使用CFileFind类获取文件夹中的所有文件和子文件夹 CFileFind finder; BOOL bWorking = finder.FindFile(_T("C:\\SourceFolder\\*.*")); // 使用SHFileOperation函数进行文件拷贝,并显示进度条 SHFILEOPSTRUCT fileOp; memset(&fileOp, 0, sizeof(SHFILEOPSTRUCT)); fileOp.hwnd = NULL; fileOp.wFunc = FO_COPY; fileOp.pFrom = _T("C:\\SourceFolder"); fileOp.pTo = _T("C:\\DestinationFolder"); fileOp.fFlags = FOF_SIMPLEPROGRESS; int nResult = SHFileOperation(&fileOp); // 创建进度条并在拷贝过程中不断更新进度条的进度 CProgressCtrl progressBar; progressBar.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, CRect(10, 10, 200, 30), this, 1); int nFileCount = 100; // 总文件数量 for (int i = 0; i < nFileCount; i++) { progressBar.SetPos(i * 100 / nFileCount); // 拷贝文件操作...... } // 关闭进度条显示拷贝结果给用户 progressBar.DestroyWindow(); AfxMessageBox(_T("文件拷贝完成"));

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值