MFC进行界面设计与编程

来源:互联网 发布:单片机pc地址 编辑:程序博客网 时间:2024/06/14 10:21

总体思路

由UI设计界面背景图片、相关按钮图片等,然后在代码中创建关联控件变量。对于无需变化的背景、按钮,可以不设控件变量关联。一般有以下几个步骤:
1.UI设计界面;
2.创建需要变动的控件变量与之关联,并设置透明;
3.加载图片;
4.创建控件相应消息响应函数。

控件开发

系统控件

创建

CStatic ctrl_record_;CRect rt_record_(614, 196, 794, 376);//创建控件ID,后续可以根据此ID找到控件GetDlgItem(IDC_INPUT_ID)->Invalidate(TRUE)//pWnd->GetDlgCtrlID() == IDC_RECORD#define IDC_RECORD        0x10001//SS_NOTIFY--能够接收消息ctrl_record_.Create(NULL, WS_CHILD | SS_CENTER | SS_CENTERIMAGE | WS_VISIBLE | SS_NOTIFY , rt_record_, this, IDC_RECORD);

透明&消息响应

//定义消息响应函数afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);//消息映射BEGIN_MESSAGE_MAP(CRiskEstimateDemoDlg, CDialogEx)    ON_WM_CTLCOLOR()    ON_STN_CLICKED(IDC_RECORD, &CRiskEstimateDemoDlg::OnRecordClicked)END_MESSAGE_MAP()//设置控件透明HBRUSH CRiskEstimateDemoDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor){    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);    // TODO:  在此更改 DC 的任何特性    CFont font;    // TODO:  如果默认的不是所需画笔,则返回另一个画笔    if (nCtlColor == CTLCOLOR_STATIC)    {        if (pWnd->GetDlgCtrlID() == IDC_DISPLAY_FACE             || pWnd->GetDlgCtrlID() == IDC_RECORD            )        {            font.CreatePointFont(150, _T("Microsoft YaHei"));            pDC->SelectObject(&font);            pDC->SetBkMode(TRANSPARENT); //透明            pDC->SetTextColor(0xffffff);            return (HBRUSH)GetStockObject(NULL_BRUSH);        }    }    return hbr;}

图片加载

//resource.h#define IDB_PNG_BACKGROUND              110//*.rcIDB_PNG_BACKGROUND      PNG                     "res\\bg.png"//加载各个控件图片,拖动会重刷BOOL CRiskEstimateDemoDlg::OnEraseBkgnd(CDC* pDC){    CDC *pDc = GetDC();    //加载背景图    LoadImageForCtrl(pDc, IDB_PNG_BACKGROUND, rt_background_.left, rt_background_.top);    if (pDc)        ReleaseDC(pDc);    return TRUE;}

自定义继承控件

自定义控件可以解决频繁刷新整个界面闪烁的问题.

class CMyStatic : public CStatic{    DECLARE_DYNAMIC(CMyStatic)public:    CMyStatic();    virtual ~CMyStatic();    virtual CMyStatic& SetText(const CString& strText);    virtual CMyStatic& SetMyFont(int nSize,const CString& strFont);    virtual CMyStatic& SetTextColor(COLORREF crText);protected:    afx_msg LRESULT OnSetText(WPARAM,LPARAM);    afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/);    afx_msg BOOL OnEraseBkgnd(CDC* pDC);    DECLARE_MESSAGE_MAP()public:    void SetImage(UINT id);private:    BOOL GetImageById(CImage *pImage, UINT nResID, LPCTSTR lpTyp);    BOOL GetImageInfo(CImage *pImage, UINT nResID, LPCTSTR lpTyp);    void SetByteForImage(CImage &image);    void Update();private:    CBitmap     bitmap_;    CFont       font_;    COLORREF    text_color_;    BOOL        bitmap_used_;    static image_id_ stat_image_[IMAGE_NUM];};

ListBox 具有 LBS_OWNERDRAW 样式是没有文字的,除非再添加 LBS_HASSTRINGS 样式,并处理 WM_DRAWITEM 去绘制文字,否则肯定不会显示文字。
参考:让ListBox控件每一行显示不同的颜色

为MFC中的ListBox添加水平滚动条
参考:为MFC中的ListBox添加水平滚动条

双缓冲区解决闪烁

//加载各个控件图片,拖动会重刷BOOL CRiskEstimateDemoDlg::OnEraseBkgnd(CDC* pDC){    // TODO:  在此添加消息处理程序代码和/或调用默认值    CDC *pDc = GetDC();    if (pDc == NULL){        return FALSE;    }    CDC memDC; //首先定义一个显示设备对象    CBitmap memBitMap;//定义一个位图对象    CImage image; //背景图片用来定义位图大小    CBitmap *pOldBmp;    int width = rt_background_.Width();    int height = rt_background_.Height();    memDC.CreateCompatibleDC(pDc);    //ASSERT(memDC.CreateCompatibleDC(pDc) != NULL);//这时还不能绘图,因为没有地方画    //下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小,也可以自己定义    memBitMap.CreateCompatibleBitmap(pDc, width, height);    //ASSERT(memBitMap.CreateCompatibleBitmap(pDc, width, height) != NULL);    pOldBmp = memDC.SelectObject(&memBitMap);//将位图选入到内存显示设备中    //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上    ASSERT(pOldBmp != NULL);    if (pOldBmp == NULL){        return FALSE;    }    //memDC.FillSolidRect(0, 0, image.GetWidth(), image.GetHeight(), RGB(255, 255, 255));    //绘图    DrawCtrl(memDC);    pDc->BitBlt(0, 0, width, height, &memDC, 0, 0, SRCCOPY);    //绘图完成后的清理,把前面的pOldBit选回来.在删除MemBitmap之前要先从设备中移除它    memDC.SelectObject(pOldBmp);    DeleteObject(&memDC);    memBitMap.DeleteObject();    if (pDc)        ReleaseDC(pDc);    return TRUE;}

MFC调用Bat文件

    if (flag_record_)    {        //system("e:\\Workspaces\\Git\\FKDemo\\FKDemo\\record.bat");        WinExec("record.bat 001.flv", SW_HIDE);    }    else    {        WinExec("kill.bat", SW_HIDE);    }

record.bat

@echo offffmpeg -f dshow -rtbufsize 200M -i video="Logitech HD Webcam C310":audio="Âó¿Ë·ç (HD Webcam C310)" -pix_fmt yuv420p -ar 48000 -vcodec libx264 -crf 23 -preset veryslow -x264opts b-adapt=2:bframes=0:aq-strength=1:psy-rd=0.8,0 -vsync vfr -acodec aac -bsf:a aac_adtstoasc -f flv %1pauseexit

kill.bat

@echo offtaskkill /f /im ffmpeg.exe

常见知识点

cstring、string、lpwstr、lpstr、char*之间相互转换;

cstring 转换为 *

/* cstring 转 string */CString cs(_T("cs"));  string s;  s = (LPCSTR)(CStringA)(cs);  /* CString转换成LPCWSTR、LPWSTR、LPCSTR、LPSTR *///VS2005中CString已经改为宽字符型LPWSTR  lpstr = (LPWSTR)(LPCWSTR)str;LPCSTR lpcstr = (LPCSTR)(LPCWSTR)str;LPSTR lpcstr = (LPSTR)(LPCWSTR)str;/* CString转换成char* 、TCHAR* */ char* p = (char*)str.GetBuffer(); //方法1 char* p = (LPSTR)(LPCTSTR)str;    //方法2 TCHAR* pw = str.GetBuffer();

string 转换为 *

/* string 转 cstring *///方法1string s ="Hello World!中国";  CString cs(s.c_str());  //方法2,用c_str()确实比data()要好.CString.format(”%s”, string.c_str());/* string 转 lpcstr */std::string a="abc";LPCSTR str = a.c_str();/* string转换为LPWSTR */wstring widstr;   std:string s("DanTeng");  widstr = std::wstring(s.begin(), s.end());  lvItem.pszText=(LPWSTR)widstr.c_str(); /* string转换为int、float */ //可以使用atoi,atof,atol等函数来完成。

LPCWSTR 转换为 *

/* LPCWSTR转换成CString */LPCWSTR lpcwStr = L"TestWStr"; CString str(lpcwStr);

LPWSTR 转换为 *

/* LPWSTR 转换成LPWSTR  */LPWSTR lpwstr = (LPCSTR)lpstr;lpwstr = (LPWSTR)lpcstr;

LPCSTR 转换为 *

/* LPCSTR 转换成CString */ LPCSTR lpcStr = (LPCSTR)str;/* LPWSTR 转换成LPWSTR  */LPWSTR lpwstr = (LPCSTR)lpstr;

LPSTR 转换为 *

/* LPSTR 转换成CString */ LPSTR lpStr = L"TestStr"; CString str(lpStr);/* LPSTR 转换成LPCSTR、LPWSTR 、LPCWSTR  */  LPCSTR  lpcstr = lpstr; LPWSTR lpwstr = (LPWSTR)lpstr; LPCWSTR lpcwstr = (LPCWSTR)lpstr;

char* 转换为 *

/* char* 转换成CString */ //方法1char* p = "test";CString str = ("%s",p);//方法2CString.format(”%s”, char*);/* char* 转换成string*/ string s(char *);  //只能初始化,在不是初始化的地方最好还是用assign()./* char* 转换成LPSTR、LPCSTR */  char *p; LPSTR lpstr = p; LPCSTR lpcstr = p;/* char* 转换成WCHAR  */ wchar_t  ws[100];swprintf(ws, 100, L"%hs", "ansi string");

/* char* 转换成LPCWSTR */
参考:C++中char*转换为LPCWSTR的解决方案

TCHAR * /WCHAR* 转换为 *

/* TCHAR* 转换成char*  */p = (char*)sex;/* WCHAR* 转换成TCHAR*  */pw = (WCHAR*)name;/* WCHAR* 转换成char*  */char output[256];WCHAR* wc = L"Hellow World" ;sprintf(output, "%ws", wc );

文件夹操作

遍历文件1

BrowseCurrentAllFile(CString strDir){     if(strDir == _T("")){         return;     }     else     {         if(strDir.Right(1) != _T("//"))              strDir += L"//";         strDir =strDir+_T("*.*");     }     CFileFind finder;     CString strPath;     BOOL bWorking = finder.FindFile(strDir);     while(bWorking)     {         bWorking = finder.FindNextFile();         strPath = finder.GetFilePath();         if(finder.IsDirectory() && !finder.IsDots())              BrowseCurrentAllFile(strPath); //递归调用         else if(!finder.IsDirectory() && !finder.IsDots())         {              //strPaht就是所要获取的文件路径         }     }}//调用方式:BrowseCurrentAllFile(_T("D://test"));

遍历文件2

BOOL ProcessImage(cv::Mat& image){    CString strDir(PLOT_DATA_IMG_PATH);    strDir += "*.jpg";    CString fileFullName;    CFileFind finder;    BOOL bWorking = finder.FindFile(strDir);    if (!bWorking)    {        return FALSE;    }    bWorking = finder.FindNextFile();    fileFullName = finder.GetFilePath();    string s;    s = (LPCSTR)(CStringA)(fileFullName);    image = cv::imread(s);    DeleteFile(fileFullName); //删除文件    return TRUE;}

目标文件是否存在

#include <shlwapi.h>#pragma comment(lib,"Shlwapi.lib") //如果没有这行,会出现link错误    if (PathFileExists(strDBPath))    {           //存在    }    else  CreateDirectory(html_path_out1, NULL);  //文件夹不存在//Cstring.Replace('/','\\');    //将地址中的'/'替换为'\\'

浏览文件夹目录

    // 设置过滤器         TCHAR szFilter[] = _T("启动文件(*.avi)|*.avi|所有文件(*.*)|*.*||");    // 构造打开文件对话框         CFileDialog fileDlg(TRUE, _T("exe"), NULL, 0, szFilter, this);    if (IDOK == fileDlg.DoModal())    {        CString str = fileDlg.GetPathName();        replay_video_path_ = (LPCSTR)(CStringA)(str);        ctrl_list_msg_.AddString(str);    }    else {        return;    }

MFC接收命令行参数的三种方法

/* 方法一:将获取到 "C:\test\app.exe  -1 -2" */CString sCmdline = ::GetCommandLine(); AfxMessageBox(sCmdline);   /*方法二:将获取到 将依次得到"C:\test\app.exe""-1""-2"*/char buff[128] = { 0 }for (int i = 0; i < __argc; i++) {     sprintf_s(buff, 128, "%ws", __targv[6]);    g_Config.kBusinessEnd = atoi(buff)} /*方法三:将获取到 将获取到 "-1 -2 "AfxGetApp()->m_lpCmdLine 只包含参数*/CString sCmdline = AfxGetApp()->m_lpCmdLine; 

DEBUG模式测试如何设置:
菜单的: 项目->属性->配置属性->调试->命令行参数

命令行参数里可以直接写你的参数,例如在命令行是:test.exe per1 per2 , 这样在这里就直接写:per1 per2

MFC获取时间的几种方法

参考:MFC获取时间的几种方法

MFC 屏蔽ESC和ENTER键关闭对话框

VC MFC 屏蔽ESC和ENTER键关闭对话框

方法一:窗体头文件中加入:1 protected:2     virtual BOOL PreTranslateMessage(MSG* pMsg);  // PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的3 public:4     virtual void OnOK();在CPP中加入:复制代码 1 BOOL CColorDlgDlg::PreTranslateMessage(MSG* pMsg) 2 { 3     //屏蔽ESC关闭窗体/ 4     if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE ) return TRUE; 5     //屏蔽回车关闭窗体,但会导致回车在窗体上失效. 6     //if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN && pMsg->wParam) return TRUE; 7     else 8         return CDialog::PreTranslateMessage(pMsg); 9 }10 void CColorDlgDlg::OnOK()11 {12     //CDialogEx::OnOK();13 }复制代码方法二:窗体头文件中加入:public:    virtual void OnOK();    virtual void OnCancel();    afx_msg void OnClose(); //响应关闭事件!在CPP中加入:复制代码void CFirstFZDlg::OnOK(){    return;}void CFirstFZDlg::OnCancel(){    return;}void CFirstFZDlg::OnClose(){    // TODO:  在此添加消息处理程序代码和/或调用默认值    CDialogEx::OnCancel();    //CDialogEx::OnClose();}复制代码MSG 结构体定义如下:typedef struct tagMSG {     // msg     HWND hwnd;   // 窗口句柄   UINT message;  // 消息   WPARAM wParam;  // 消息附加信息,根据消息而定   LPARAM lParam;  // 消息附加信息,根据消息而定   DWORD time;  // 消息发送时间   POINT pt;  // 消息发送时指针的位置(屏幕坐标)} MSG;

完全退出线程

UINT thread_testexit( PVOID pParam )  {      while( g_bExtiThread )      {          Sleep(1000);          static int i = 0;          CString str;str.Format( L"%d",i++);          //AfxGetApp()->GetMainWnd()->SetWindowText( str );      }      return 0;  }  void Ctmfc1Dlg::OnBnClickedButton1()  {      // TODO: 在此添加控件通知处理程序代码      pWinThreadtestexit = AfxBeginThread( thread_testexit, 0 );  }  void Ctmfc1Dlg::OnBnClickedButton2()  {      // TODO: 在此添加控件通知处理程序代码       g_bExtiThread = 0;      WaitForSingleObject( pWinThreadtestexit->m_hThread, INFINITE );      SetWindowText( L"线程已经停止" );   }  

参考:MFC 线程的退出方法

常见错误

Error Cxxx

1.Error C1003: error count exceeds 100
A:在自定义源文件中要加入#include “stdafx.h”,且要加在首行。

应用程序无法正常启动0xc000007b解决方法

问题原因
依赖的库文件错误,需要排查更换。

解决方法
使用depends.exe检测错误的依赖库。并更换。

参考

1、(极好)VC++判断文件或文件夹是否存在

原创粉丝点击