本文由BlueCoder编写 转载请说明出处:
http://blog.csdn.net/crocodile__/article/details/14102149
我的邮箱:bluecoder@yeah.net 欢迎大家和我交流编程心得
我的微博:BlueCoder_黎小华 欢迎光临^_^
昨天研究了一下MFC文本编程方面的要领,本来可以昨晚编写此文的,可昨晚发生了一个小事故——不小心把手腕摔着了,虽然现在好多了,但我依然是带伤上阵啊——这一点,是否有些类似科比呢?呵呵——我是科密,必须学习他积极的一面哈
今天用一些简单的文本知识、加上右键菜单来实现一个字符串"撞墙反弹"的简易效果——为下次的游戏做铺垫——接下来进入今天的正题……
一、效果演示
(1). 通过右键菜单来更改字体
(2). "撞墙反弹"效果
二、准备工作
(1). 看看IDE支持的字体
“工具”--> "选项" --> "字体与颜色"
在"字体"中查看支持的字体
(2). 通过IDE创建一个右键菜单
这里仅用了四个字体:
名称 ID号 宋体 ID_SONG 华文彩云 ID_CAIYUN 华文行楷 ID_XINGKAI 微软雅黑 ID_YAHEI
(3). 讲解两个API函数
1). CDC::GetTextExtent
CSize GetTextExtent( const CString& str ) const; 在当前DC中,获取字符串str的size大小
2).CMenu::TrackPopupMenu
BOOL TrackPopupMenu( UINT nFlags, //标记——详情见msdn,上面讲的很详细,这里不再赘述 int x, //x坐标 int y, //y坐标 CWnd* pWnd, //所属窗口 LPCRECT lpRect = 0 //忽略, 没用 );
对于此函数需要注意的是右键菜单的坐标问题:详见代码分析
三、代码剖析
(1). 预先浏览一下头文件中的相关声明
#include<atlimage.h>//使用CImage类所需添加的头文件 //计时器ID定义 #define ID_TIMER 100 class CTextView : public CView { protected: // 仅从序列化创建 CTextView(); DECLARE_DYNCREATE(CTextView) // 属性 public: CTextDoc* GetDocument() const; // 操作 public: // 重写 public: virtual void OnDraw(CDC* pDC); // 重写以绘制该视图 virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: // 实现 public: virtual ~CTextView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif //私有成员变量 private: CMenu m_popupMenu; CImage m_bk;//背景 CSize m_sClient;//客户区大小 CString m_str;//字体动画的内容 CString m_sFont;//字体名称 CPoint m_ptStr;//字符串的左上角点 CSize m_sStr;//字符串的大小 COLORREF m_fontColor;//字符串颜色 CSize m_move;//字符串的移动距离(x, y) bool m_isPause;//是否暂停 //私有成员函数 private: inline void SetStrPoint();//设置字符串的左上角起点 inline void SetMove();//设置字符串的移动距离 inline void MoveString();//移动字符串 protected: // 生成的消息映射函数 protected: DECLARE_MESSAGE_MAP() public: afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); protected: //重写OnCommand函数, 用于相应WM_COMMAND消息——右键菜单消息 virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); };
(2). 设置字符串的左上角起点void CTextView::SetStrPoint() { //设置种子 srand(GetTickCount()); //保证坐标为整十数 m_ptStr.x = rand() % ((m_sClient.cx - m_sStr.cx) / 10); m_ptStr.x *= 10; m_ptStr.y = rand() % ((m_sClient.cy - m_sStr.cy) / 10); m_ptStr.y *= 10; }
(3). 设置字符串的移动距离
void CTextView::SetMove() { //如果x坐标出了边界, 就反向 if(m_ptStr.x < 0 || m_ptStr.x > (m_sClient.cx - m_sStr.cx)) { m_move.cx = -m_move.cx; //变换字体颜色 m_fontColor = RGB(rand()%256, rand()%100, rand()%256); } //如果y坐标出了边界, 就反向 if(m_ptStr.y < 0 || m_ptStr.y > (m_sClient.cy - m_sStr.cy)) { m_move.cy = -m_move.cy; //变换字体颜色 m_fontColor = RGB(rand()%256, rand()%100, rand()%256); } }
(4). 移动字符串
void CTextView::MoveString() { m_ptStr.x += m_move.cx; m_ptStr.y += m_move.cy; }
(5). 鼠标左键控制字符串的启动和暂停
void CTextView::OnLButtonDown(UINT nFlags, CPoint point) { //如果暂停, 就关闭计时器 if(m_isPause) { this->KillTimer(ID_TIMER); //下一次点击时, 就是不暂停 m_isPause = false; } //否则, 重新启动计时器 else { this->SetTimer(ID_TIMER, 40, NULL); //下一次点击时, 就是暂停 m_isPause = true; } CView::OnLButtonDown(nFlags, point); }
(6). 鼠标右键选择字体
void CTextView::OnRButtonDown(UINT nFlags, CPoint point) { /* 因为当前获取的坐标point是客户区坐标,而TrackPopupMenu函数坐标参数 是屏幕坐标,因此应该使用ClientToScreen函数,转换为屏幕坐标 */ this->ClientToScreen(&point); //显示右键菜单 m_popupMenu.TrackPopupMenu( TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, point.x, point.y, this, NULL); CView::OnRButtonDown(nFlags, point); }
(7). 响应WM_COMMAND消息,设置选择的字体
BOOL CTextView::OnCommand(WPARAM wParam, LPARAM lParam) { //修改字体 switch(LOWORD(wParam)) { case ID_SONG: m_sFont = "宋体"; break; case ID_CAIYUN: m_sFont = "华文彩云"; break; case ID_XINGKAI: m_sFont = "华文行楷"; break; case ID_YAHEI: m_sFont = "微软雅黑"; break; } //重绘 InvalidateRect(NULL, FALSE); return CView::OnCommand(wParam, lParam); }
(8). 绘制客户区——响应WM_PAINT消息
void CTextView::OnDraw(CDC* pDC) { CTextDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; //创建内存DC, 以用双缓冲绘图 CDC bufferDC; bufferDC.CreateCompatibleDC(NULL); CBitmap bufferBmp; bufferBmp.CreateCompatibleBitmap(pDC, m_sClient.cx, m_sClient.cy); bufferDC.SelectObject(bufferBmp); //------------------------------------------------------ // 以下都在内存DC中绘图 //------------------------------------------------------ //获取指定的字体 CFont font; font.CreatePointFont(150, (LPCTSTR)m_sFont); bufferDC.SelectObject(font); m_sStr = bufferDC.GetTextExtent(m_str); //贴背景 bufferDC.SetStretchBltMode(COLORONCOLOR); bufferDC.SetTextColor(m_fontColor); m_bk.StretchBlt(bufferDC, 0, 0, m_sClient.cx, m_sClient.cy, SRCCOPY); //贴字符串 bufferDC.SetBkMode(TRANSPARENT); bufferDC.TextOutW(m_ptStr.x, m_ptStr.y, m_str); //------------------------------------------------------ // 将内存DC中的图绘制到窗口客户区DC中 //------------------------------------------------------ pDC->BitBlt(0, 0, m_sClient.cx, m_sClient.cy, &bufferDC, 0, 0, SRCCOPY); //删除字体 font.DeleteObject(); //删除内存bmp bufferBmp.DeleteObject(); //删除DC bufferDC.DeleteDC(); }
四、零积分源码下载
【VC++游戏开发#四】2D篇 —— 物理建模(一) 匀速直线运动:字符串"撞墙反弹"效果
最新推荐文章于 2024-04-23 00:15:00 发布