c++暑假实习笔记
编辑"消息"的方法:
a)在资源视图中依次点击展开 MFCcal -> MFCcal.rc -> Dialog,选择不含 ABOUT 的文件得到如图界面: 得到预览图 |
b)右击右边预览图,选择“类向导” 类向导 |
c)将类名选为CMFCcalDlg,选择"消息" -> 选择要编辑的消息 -> 点击"添加处理程序" -> 点击"编辑代码" 类向导 |
d)编辑即可 |
编辑"命令" "消息" "虚函数" "方法"的方法类似。
例如编辑消息WM_CREATE,以后将以上步骤简称为:编辑消息OnCreate
因为相应函数是MFCcalDlg.cpp中的OnCreate()
Day1
day1-1 c++回顾
day1-2 Windows程序介绍
day1-3 MFC介绍,+-*/计算器
Day2
day2-1 mfc 笔刷
day2-2 mfc 时钟
day2-3 mfc 导入图片
mfc 更改背景颜色
假设项目名称MFCcal
step1.
在MFCcalDlg.h中在类的最后添加:public: CBrush m_brush;
step2.
在MFCcalDlg.cpp中BOOL CMFCcalDlg::OnInitDialog()
函数的第一句话CDialogEx::OnInitDialog();
下面添加m_brush.CreateSolidBrush(RGB(想填的颜色));
step3.
在 IDD_MFCCAL_DIALOG 界面,点击类向导,将类名选为CMFCcalDlg,然后选择"消息"(本来是"命令"),找到WM_CTLCOLOR,点击"编辑代码"(如果不能点,就先点击"添加处理程序")。
step4.
回到 MFCcalDlg.cpp 中,在代码最后,有HBRUSH CMFCcalDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
函数,将里面的第一句话HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
注释掉,将返回值改成m_brush
。
step5.
生成,运行即完成。
mfc 添加时钟
会动的时钟
上下左右各与边缘相差5px
假设项目名称 "MFCcal"
step1.
在类向导中编辑“消息”的WM_PAINT,在CMFcalDlg.cpp中找到OnPaint()函数,在 if else 结束后加上下面的代码:
CDC* pDC = this->GetDC(); CPen pen; pen.CreatePen(PS_SOLID, 1, RGB(128, 128, 128)); CPen* pOldPen = pDC->SelectObject(&pen); CRect rc; GetClientRect(&rc); int xStart = rc.right / 2; int yStart = rc.bottom / 2; CTime time = CTime::GetCurrentTime(); CString strDigits; int i, x, y; CSize size; CPen Pen(PS_SOLID, 2, RGB(0, 0, 0)); pOldPen = pDC->SelectObject(&Pen); pDC->Ellipse(5, 5, rc.right - 5, rc.bottom - 5); double Radians; pDC->SetTextColor(RGB(0, 0, 0)); CFont font; font.CreatePointFont(100, _T("宋体"), pDC); pDC->SelectObject(&font); for (i = 1; i <= 12; i++) { strDigits.Format(_T("%d"), i); size = pDC->GetTextExtent(strDigits, strDigits.GetLength()); Radians = (double)i * 6.28 / 12.0; x = xStart - (size.cx / 2) + \ (int)((double)(xStart - 20) * sin(Radians)); y = yStart - (size.cy / 2) - \ (int)((double)(yStart - 20) * cos(Radians)); pDC->TextOut(x, y, strDigits); } font.DeleteObject(); Radians = (double)time.GetHour() + (double)time.GetMinute() / 60.0\ +(double)time.GetSecond() / 3600.0; Radians *= 6.28 / 12.0; CPen HourPen(PS_SOLID, 5, RGB(0, 0, 0));//时针 pDC->SelectObject(&HourPen); pDC->MoveTo(xStart, yStart); pDC->LineTo(xStart + (int)((double)(xStart / 3) * sin(Radians)), \ yStart - (int)((double)(yStart / 3) * cos(Radians))); Radians = (double)time.GetMinute() + (double)time.GetSecond() / 60.0; Radians *= 6.28 / 60.0; CPen MinutePen(PS_SOLID, 3, RGB(0, 0, 0));//分针 pDC->SelectObject(&MinutePen); pDC->MoveTo(xStart, yStart); pDC->LineTo(xStart + (int)((double)(xStart * 2 / 3) * sin(Radians)), \ yStart - (int)((double)(yStart * 2 / 3) * cos(Radians))); Radians = (double)time.GetSecond(); Radians *= 6.28 / 60.0; CPen SecondPen(PS_SOLID, 1, RGB(0, 0, 0));//秒针 pDC->SelectObject(&SecondPen); pDC->MoveTo(xStart, yStart); pDC->LineTo(xStart + (int)((double)(xStart * 4 / 5) * sin(Radians)), \ yStart - (int)((double)(yStart * 4 / 5) * cos(Radians))); pDC->SelectObject(pOldPen);
这结束后,你有了一个不会动的时钟。
step2.
编辑“消息”OnCreate,相应的函数改为
int CMFCcalDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialogEx::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here ///////////////////////////////////// SetTimer(20, 1000, NULL); ///////////////////////////////////// return 0; }
step3.
编辑“消息”OnTimer,相应的函数改为:
void CMFCcalDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default Invalidate(TRUE);//刷新功能 //UpdateData(true); CDialogEx::OnTimer(nIDEvent); }
step4.
运行,完成。
mfc 导入图片
如图,点击导入图片可导入.bmp位图
假设项目名称为MFCtest
step1.
在资源视图的Dialog页面将工具箱中的"Picture Control"拖到页面中,查看它的属性,复制它的ID,假设其为“IDC_STATIC”。
step2.
将工具箱中的Button拖到页面中,将其Caption重命名为“导入图片”。假设它的ID为“IDC_BUTTON1”。
step3.
在类向导的"命令"里找到IDC_BUTTON1,点击"BN_CLICKED",点击"添加处理程序",点击"编辑代码"。将相应函数改为:
void CMFCtestDlg::OnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 CString filename; CFileDialog fDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,\ _T("位图文件(*.bmp)|*.bmp|文本文件(*.txt)|*.txt||"),this); if (fDlg.DoModal() != IDOK) return; filename = fDlg.GetPathName(); HANDLE hBmp = LoadImage(::AfxGetApp()->m_hInstance, lename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);//加载位图 CBitmap bmp;//位图类对象 bmp.Attach(hBmp);//关联位图句柄 //获取位图信息 BITMAP bmpInfo; bmp.GetBitmap(&bmpInfo); //获取显示区域 CRect rect; CWnd* pWnd = GetDlgItem(IDC_STATIC); ///小小的标记 pWnd->GetWindowRect(rect);//获取窗口的绝对坐标区域 //ScreenToClient(rest);//将绝对坐标转换为客户区坐标(相对于当前窗口的左上角) CDC* pDC = pWnd->GetDC();//当前窗口的绘图环境 CDC dc; dc.CreateCompatibleDC(pDC);//与当前窗口兼容的绘图环境 dc.SelectObject(&bmp); //原大小 pDC->BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &dc, 0, 0, SRCCOPY); //伸缩 //pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY); ReleaseDC(pDC); bmp.DeleteObject();//删除位图对象 }
注:上面代码中“小小的标记”处的IDC_STATIC是"Picture Control"的ID名。
Day3
d3-1 mfc发牌
d3-2 mfc调查问卷
发牌
发牌
牌
假设项目名称为“MFCtest”
step1.
左击资源视图中的Dialog,选择“插入Dialog”,在新界面中摆好四个Picture Control,分别改ID为IDC_PK1、IDC_PK2、IDC_PK3、IDC_PK4,和一个Buttom,改名为“发牌”。
对应四个图片控件添加变量,名字分别是m_pk1~m_pk4,类型CStatic。
step2.
左击树状图添加类,命名为Card。
编辑Button“发牌”的BN_CLICKED,如下:
void Card::OnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 int row; srand(time(NULL)); row = rand() % 14; LoadImage(&m_pk1, _T("pk.bmp"), 4, 14, 0, row); row = rand() % 14; LoadImage(&m_pk2, _T("pk.bmp"), 4, 14, 1, row); row = rand() % 14; LoadImage(&m_pk3, _T("pk.bmp"), 4, 14, 2, row); row = rand() % 14; LoadImage(&m_pk4, _T("pk.bmp"), 4, 14, 3, row); }
step3.
在Card类中添加方法LoadImage(),如下:
void Card::LoadImage(CWnd* pWnd, _In_ LPCWSTR lpFilename, int rows, int cols, int row, int col) { HANDLE hImg = ::LoadImage(theApp.m_hInstance, lpFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); CBitmap bmp; bmp.Attach(hImg); //将位图的句柄与位图对象关联 BITMAP bmpInfo; bmp.GetBitmap(&bmpInfo); //获取位图信息 //确定绘图的位置 CRect rect; pWnd->GetClientRect(rect); //准备一个内存DC CDC memDC; CDC* pDC = pWnd->GetDC(); //获取当前绘图设备 memDC.CreateCompatibleDC(pDC); //创建内存DC memDC.SelectObject(bmp); //选择位图 int width, height; //计算单张扑克大小 width = (bmpInfo.bmWidth + 10) / cols; height = bmpInfo.bmHeight / rows; int left, top; //计算扑克位置 left = col * width; top = row * height; //贴图 pDC->StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, left, top, width, height, SRCCOPY); bmp.DeleteObject(); //释放位图 memDC.DeleteDC(); //释放内存DC pWnd->ReleaseDC(pDC); //释放目标DC }
step4.
在MFCtestDlg中添加一个Button,命名为“发牌”,目的是点击此按钮后出现上面我们设计的对话框。
编辑该按钮消息的BN_CLICKED,如下:
void CMFCtestDlg::OnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 Card dlg; //dlg.ShowWindow(true); dlg.DoModal(); }
step5.
主要步骤已经完成,运行调试即可。
调查问卷
step1.
新建mfc,基于对话框,取名为Inves
step2.
将对话框添加成如下模样:
如图
其中用了radio button,check box,list box,combo box,static text,button。
添加成员变量,如下:
如图
step3.
修改CInvesDlg::OnInitDialog()
函数,添加如下代码:
m_combct.AddString(_T("早上")); m_combct.AddString(_T("中午")); m_combct.AddString(_T("下午")); m_combct.AddString(_T("晚上")); m_listct1.AddString(_T("一天内")); m_listct1.AddString(_T("一月内")); m_listct1.AddString(_T("一年内")); m_listct1.AddString(_T("今生内")); m_listct1.AddString(_T("未有过"));
step4.
在CInvesDlg类中添加public: CString radio;
在窗口界面分别双击第一个问题的四个radio控件,改写如下:
void CInvesDlg::OnBnClickedRadio4() { // TODO: 在此添加控件通知处理程序代码 radio = _T("不知道"); } void CInvesDlg::OnBnClickedRadio1() { // TODO: 在此添加控件通知处理程序代码 radio = _T("简直完美"); } void CInvesDlg::OnBnClickedRadio2() { // TODO: 在此添加控件通知处理程序代码 radio = _T("还可以"); } void CInvesDlg::OnBnClickedRadio3() { // TODO: 在此添加控件通知处理程序代码 radio = _T("嫌弃"); }
step5.
给“提交”按钮添加点击函数,如下:
void CInvesDlg::OnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 m_listct2.ResetContent(); m_listct2.AddString(_T("第1个问题:") + radio); CString selectStr; int index; if (m_ckct1.GetState()) selectStr += _T("爱情 "); if (m_ckct2.GetState()) selectStr += _T("动作 "); if (m_ckct3.GetState()) selectStr += _T("爱情动作 "); if (m_ckct4.GetState()) selectStr += _T("喜剧 "); if (m_ckct5.GetState()) selectStr += _T("悬疑 "); m_listct2.AddString(_T("第2个问题:") + selectStr); index = m_listct1.GetCurSel(); m_listct1.GetText(index, selectStr); m_listct2.AddString(_T("第3个问题:") + selectStr); index = m_combct.GetCurSel(); m_combct.GetLBText(index, selectStr); m_listct2.AddString(_T("第4个问题:") + selectStr); }
step6.
运行调试
Day4
马踏棋盘
马踏棋盘,在右边行列选择框了选择起始位置,图中是C5
“马踏棋盘”是在国际象棋的棋盘上任意一个位置放置一个马,然后按照“马走日”的规则不重不漏地走完所有8x8个格子。
这个项目主要考验算法能力。本题采用Warnsdorff法则,由于项目说明中要用非递归程序,因此我用栈模拟dfs。
程序简单解释我已经标在代码中。
step1.
首先解决算法问题。
添加类Data。
Data.h如下:
#pragma once #include "StdAfx.h" using namespace std; //8个移动方案 const int dx[] = { 1,1,2,2,-1,-1,-2,-2 }; const int dy[] = { 2,-2,1,-1,2,-2,1,-1 }; //三元组 struct Tri { int a, b, c; Tri(int a=0, int b=0, int c=0):a(a),b(b),c(c){} bool operator<(const Tri& t)const { return c < t.c; } }; //两元组 struct Pair { int a, b; Pair(int a = 0, int b = 0) :a(a), b(b) {} bool operator<(const Pair& t)const { return a < t.a; } }; //每一步棋盘 class Data { private: int m[8][8], x, y, n;//分别表示 棋盘每一格是第几步 最后一步的两个坐标和步数 queue<int> d;//Warnsdorff法则下的移动顺序 public: Data(); Data(const Data& t); void add(int x, int y, int n);//添加新移动 bool check(int x, int y);//判断该位置是否合法 bool ck();//检查该棋盘是否可行 void print();//打印棋盘 int getson(int cx, int cy);//计算可移动位置数 void getd();//计算移动顺序 int getx() { return x; } int gety() { return y; } int getn() { return n; } int d_front() { return d.front(); } void d_pop() { return d.pop(); } bool d_empty() { return d.empty(); } int getm(int x, int y) { return m[x][y]; } }; Data dfs(int, int);//按照Warnsdorff法则dfs
Data.cpp书写如下:
#include "pch.h" #include "Data.h" using namespace std; Data::Data() { for (int i = 0; i < 8; ++i) for (int j = 0; j < 8; ++j) m[i][j] = 0; n = 0; } Data::Data(const Data& t) { for (int i = 0; i < 8; ++i) for (int j = 0; j < 8; ++j) m[i][j] = t.m[i][j]; x = t.x; y = t.y; n = t.n; d = t.d; } void Data::add(int x, int y, int n) { m[x][y] = n; this->n = n; this->x = x; this->y = y; } bool Data::check(int x, int y) { return x >= 0 && x < 8 && y >= 0 && y < 8 && m[x][y] == 0; } bool Data::ck()//主要是检查四个角 { m[x][y] = 0; int t1 = 2, t2 = 2, t3 = 2, t4 = 2; if (m[0][0] == 0) t1 = (m[1][2] == 0) + (m[2][1] == 0); if (m[0][7] == 0) t2 = (m[1][5] == 0) + (m[2][6] == 0); if (m[7][0] == 0) t3 = (m[5][1] == 0) + (m[6][2] == 0); if (m[7][7] == 0) t4 = (m[5][6] == 0) + (m[6][5] == 0); m[x][y] = n; if (t1 == 0 || t2 == 0 || t3 == 0 || t4 == 0) return false; int num = (t1 == 1) + (t2 == 1) + (t3 == 1) + (t4 == 1); if (num > 2) return false; return true; } void Data::print() { for (int i = 0; i < 8; ++i) { for (int j = 0; j < 8; ++j) { printf("%3d%c", m[i][j], " \n"[j == 7]); } } puts(""); } int Data::getson(int cx, int cy) { int res = 0; for (int i = 0; i < 8; ++i) if (check(cx + dx[i], cy + dy[i])) res++; return res; } void Data::getd() { while (!d.empty()) d.pop(); vector<Pair> p; for (int i = 0; i < 8; ++i) { if (check(x + dx[i], y + dy[i])) { p.push_back(Pair(getson(x + dx[i], y + dy[i]), i)); } } sort(p.begin(), p.end()); for (int i = 0; i < p.size(); ++i) { //printf("(%d,%d) ", p[i].a,p[i].b); d.push(p[i].b); } } stack<Data> S; Data dfs(int x, int y) { while (!S.empty()) S.pop(); Data s; s.add(x, y, 1); s.getd(); S.push(s); do { Data tmp = S.top(); S.pop(); if (tmp.d_empty()) continue; int i = tmp.d_front(); tmp.d_pop(); S.push(tmp); Data nex(tmp); nex.add(tmp.getx() + dx[i], tmp.gety() + dy[i], tmp.getn() + 1); if (nex.getn() == 64) return nex; if (!nex.ck()) continue; nex.getd(); S.push(nex); } while (!S.empty());//用do-while代替递归,真是麻烦 return s; }
其中 StaAfx.h 是这样写的:
#pragma once #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<stack> #include<vector>
step2.
设计窗口界面如下:
成员变量明明如下:
step3.
给Check类添加两个变量:
public: int Wid = 60, NUM = 9;
编辑消息OnPaint,添加代码如下:
//先画出8x8网格 CDC* pDC = this->GetDC(); CPen pen; pen.CreatePen(PS_SOLID, 1, RGB(128, 128, 128)); CPen* pOldPen = pDC->SelectObject(&pen); for (int i = 1; i <= NUM; ++i) { pDC->MoveTo(Wid, Wid * i); pDC->LineTo(Wid * NUM, Wid * i); } for (int i = 1; i <= NUM; ++i) { pDC->MoveTo(Wid * i, Wid); pDC->LineTo(Wid * i, Wid * NUM); } //为网格添加颜色 pen.DeleteObject(); CBrush bru; bru.CreateSolidBrush(RGB(255, 255, 255)); pDC->SelectObject(&bru); for (int i = 1; i < NUM; ++i) { for (int j = 1; j < NUM; ++j) { if ((i + j) % 2) continue; pDC->Rectangle(i * Wid+1, j * Wid+1, (i + 1) * Wid-1, (j + 1) * Wid-1); } } bru.DeleteObject(); bru.CreateSolidBrush(RGB(0, 0, 0)); pDC->SelectObject(&bru); for (int i = 1; i < NUM; ++i) { for (int j = 1; j < NUM; ++j) { if ((i + j)%2==0) continue; pDC->Rectangle(i * Wid+1, j * Wid+1, (i + 1) * Wid-1, (j + 1) * Wid-1); } } bru.DeleteObject(); //添加坐标 CFont font; font.CreatePointFont(150, _T("宋体"), pDC); pDC->SelectObject(&font); pDC->SetBkMode(TRANSPARENT); CString str; for (int i = 1; i < NUM; ++i) { str.Format(_T("%c"), 'A' - 1 + i); pDC->TextOut(i * Wid + Wid / 2-5, Wid / 2-5, str); pDC->TextOut(i * Wid + Wid / 2 - 5, 9*Wid + 5, str); str.Format(_T("%d"), i); pDC->TextOut(Wid / 2+10, (i + 0.5) * Wid-15, str); pDC->TextOut(9.5*Wid-20, (i + 0.5) * Wid - 15, str); } font.DeleteObject();
给OnInitDialog()添加如下代码:
m_listct1.AddString(_T("A")); m_listct1.AddString(_T("B")); m_listct1.AddString(_T("C")); m_listct1.AddString(_T("D")); m_listct1.AddString(_T("E")); m_listct1.AddString(_T("F")); m_listct1.AddString(_T("G")); m_listct1.AddString(_T("H")); m_listct2.AddString(_T("1")); m_listct2.AddString(_T("2")); m_listct2.AddString(_T("3")); m_listct2.AddString(_T("4")); m_listct2.AddString(_T("5")); m_listct2.AddString(_T("6")); m_listct2.AddString(_T("7")); m_listct2.AddString(_T("8"));
为确定按钮添加点击的函数,如下:
void CChessDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); Invalidate(TRUE);//刷新功能 UpdateWindow(); //获得选中坐标及最终棋盘 int x, y; x = m_listct1.GetCurSel(); y = m_listct2.GetCurSel(); if (x == -1 || y == -1) return; Data res = dfs(x, y); //将坐标按步数顺序排列 vector<Tri> tri; for (int i = 0; i < NUM - 1; ++i) { for (int j = 0; j < NUM - 1; ++j) { tri.push_back(Tri(i, j, res.getm(i,j))); } } sort(tri.begin(), tri.end()); //按顺序画 CDC* pDC = this->GetDC(); CFont font; font.CreatePointFont(150, _T("宋体"), pDC); //pDC->SelectObject(&font); //pDC->SetBkMode(TRANSPARENT); CString str; CPen pen1, pen2; pen1.CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); pen2.CreatePen(PS_SOLID, 2, RGB(255, 255, 255)); for (int i = 0; i < 64; ++i) { pDC->SelectObject(&font); pDC->SetBkMode(TRANSPARENT); str.Format(_T("%d"), i+1); int tx = tri[i].a+1, ty = tri[i].b+1; if ((tx + ty) % 2) pDC->SetTextColor(RGB(255, 255, 255)); pDC->TextOutW((tx + 0.5) * Wid - 10, (ty + 0.5) * Wid - 10, str); if ((tx + ty) % 2) pDC->SetTextColor(RGB(0, 0, 0)); pDC->SelectObject(&pen1); pDC->SelectStockObject(NULL_BRUSH); pDC->Rectangle(tx * Wid, ty * Wid, (tx + 1) * Wid, (ty + 1) * Wid); Sleep(500); pDC->SelectObject(&pen2); pDC->SelectStockObject(NULL_BRUSH); pDC->Rectangle(tx * Wid, ty * Wid, (tx + 1) * Wid, (ty + 1) * Wid); } font.DeleteObject(); //UpdateData(0); }
step4.
调式运行。