最终效果:
方法概述:
1:先新建一个普通对话框工程,使用CRgn,CBrush对象等在对话框中画出需要的字符串显示的边框,如上图中的紫色边框就是由一个矩形CRgn和一个圆角矩形CRgn组合而成,然后截取下来,保存为位图,如需该图片,可在附件res目录下找到
2:新建Marquee工程,将上个工程里制作的位图导入到资源中当做背景图,接下来就是如下代码
3:在代码中会使用内存画布,将位图和文字全部先写到内存DC中,再输出到屏幕
过程:
一:新建一个基于对话框的MFC程序,在对话框头文件中加入以下变量,并且添加一个析构函数
class CMarqueeDlg : public CDialog
{
// Construction
public:
CString m_str; //跑马灯文字
CSize m_size; //跑马灯字符串的高宽
CRgn m_RoundRectRgn; //字符串显示位置的圆角矩形边框
CRgn m_RectangleRgn; //字符串显示位置的矩形边框,与圆角圆角语句进行组合
CRgn m_RdRtCombineRgn; //圆角矩形与矩形的组合区域
CRgn m_StRdRtCbCombineRgn; //m_RdRtCombineRgn区域与文字矩形区域的相交区域
CRgn m_StRtCombineRgn; //m_RectangleRgn区域与文字矩形区域的组合区域(组合方式看代码)
CRect m_rtClient; //窗口客户区
CRect m_rtStatic; //跑马灯文字的矩形区域
CRect m_rtRoundRect; //圆角矩形边框的矩形
CRect m_rtRectangle; //矩形边框
public:
CMarqueeDlg(CWnd* pParent = NULL); // standard constructor
~CMarqueeDlg();
// Dialog Data
//{{AFX_DATA(CMarqueeDlg)
enum { IDD = IDD_MARQUEE_DIALOG };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMarqueeDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMarqueeDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
二:修改对话框的OnPaint(..)函数
void CMarqueeDlg::OnPaint()
{
CPaintDC dc(this);
m_str=TEXT("这是要在跑马灯上显示的字符串");
SetTimer(1,200,NULL);
m_size=dc.GetTextExtent(m_str);//获取字符串的高宽
GetClientRect(&m_rtClient);
//设置圆角矩形边框
m_rtRoundRect.left=m_rtClient.left+70;
m_rtRoundRect.right=m_rtClient.right-70;
m_rtRoundRect.top=m_rtClient.top+(m_rtClient.Height()-m_size.cy)/2-10;
m_rtRoundRect.bottom=m_rtRoundRect.top+45;
//设置矩形边框
m_rtRectangle.left=m_rtRoundRect.left-20;
m_rtRectangle.right=m_rtRoundRect.right+20;
m_rtRectangle.top=m_rtRoundRect.top-5;
m_rtRectangle.bottom=m_rtRoundRect.bottom+5;
//创建圆角矩形边框CRgn
m_RoundRectRgn.CreateRoundRectRgn(m_rtRoundRect.left,m_rtRoundRect.top,m_rtRoundRect.right,m_rtRoundRect.bottom,10,10);
//创建矩形边框CRgn
m_RectangleRgn.CreateRectRgn(m_rtRectangle.left,m_rtRectangle.top,m_rtRectangle.right,m_rtRectangle.bottom);
//创建圆角矩形边框和矩形边框的组合区域CRgn
m_RdRtCombineRgn.CreateRectRgn(0,0,0,0);
m_RdRtCombineRgn.CombineRgn(&m_RoundRectRgn,&m_RectangleRgn,RGN_XOR);
//设置显示字符串的矩形边界
m_rtStatic.left=m_rtClient.left+(m_rtClient.Width()-m_size.cx)/2;
m_rtStatic.right=m_rtStatic.left+m_size.cx;
//不清楚什么原因,如果不稍微加大矩形的的高度,用背景色覆盖文字的时候还是会露一点点出来,所以这里+(-)2;
m_rtStatic.top=m_rtClient.top+(m_rtClient.Height()-m_size.cy)/2-2;//
m_rtStatic.bottom=m_rtStatic.top+m_size.cy+2;
}
三:为对话框添加定时器消息函数OnTimer(..)
void CMarqueeDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
//创建创建兼容DC,并从资源中加载位图,选进兼容DC中
CClientDC dc(this);//这个函数中只能用CClientDC而不能用CPaintDC
CBitmap bmp;
if(!bmp.LoadBitmap(IDB_BITMAP1))
return;
CDC mdc; //客户区的兼容内存DC
mdc.CreateCompatibleDC(&dc);
CBitmap* pOldBmp=(CBitmap*)mdc.SelectObject(&bmp);
//在兼容内存DC中写上文字
mdc.SetBkMode(TRANSPARENT);
mdc.SetTextColor(RGB(0,0,0));
// m_mdc.DrawText(m_str,-1,&m_rtStatic,DT_CENTER);
mdc.DrawText(m_str,m_str.GetLength(),&m_rtStatic,DT_CENTER);
//创建m_StRtCombineRgn,即文本框超出矩形边框的部分,当文字区域滑动到边框外面时,用背景色覆盖掉超出边框的这一部分,不让文字显示
//需要先把文字矩形框转换为CRgn类,才能与矩形边框进行组合,方便在这一部分填充背景色
CRgn StaticRgn;
StaticRgn.CreateRoundRectRgn(m_rtStatic.left,m_rtStatic.top,
m_rtStatic.right,m_rtStatic.bottom,10,10);
//真正创建m_StRtCombineRgn
if(m_StRtCombineRgn.GetSafeHandle())
m_StRtCombineRgn.DeleteObject();
m_StRtCombineRgn.CreateRectRgn(0,0,0,0);
//注意第三个参数,决定组合方式,这里组合得到的区域是只属于文本区域而不属于矩形边框区域
m_StRtCombineRgn.CombineRgn(&StaticRgn,&m_RectangleRgn,RGN_DIFF);
//给这一部分上色,颜色与背景色相同,用来覆盖掉这一部分的文字
//本意:使用加载的位图即背景来覆盖掉这一部分,但使用出错,只能自己指定背景颜色即白色来填充,有知道如何改进的网友
//如果能指点我一下怎么修改这 使用背景位图来覆盖一部分文本区域 这一部分,感激不尽!*/
/*CBrush brTrans;
LOGBRUSH lb={1};
brTrans.CreateBrushIndirect(&lb);
m_mdc.FillRgn(&m_StRtCombineRgn,&brTrans);*/
CBrush brtmp1(RGB(255,255,255));
mdc.FillRgn(&m_StRtCombineRgn,&brtmp1);
/*创建m_StRdRtCbCombineRgn,即文本区域与自绘的边框的区域的组合,当文字区域滑动到这一部分的时候,
使用边框的颜色覆盖点与边框重合的这一部分文字区域,使文字无法显示出来
本意:边框是以位图的形式载入的,本意是无论是文字区域滑动到边框区域还是边框外部区域,都统一使用用载入的背景位图来覆盖掉与边框重合
和超出边框的两部分文字区域,在边框内部的区域仍然显示文字,但不知道如何统一使用背景位图覆盖这两部分,只能自己根据载入的位图
的颜色来选择这两部分的颜色,然后分别用这两个颜色填充两个区域
如果有网友知道如何使用背景位图来覆盖掉不要的那部分文字区域,如果能指导我一下,感激不尽!*/
if(m_StRdRtCbCombineRgn.GetSafeHandle())
m_StRdRtCbCombineRgn.DeleteObject();
m_StRdRtCbCombineRgn.CreateRectRgn(0,0,0,0);
m_StRdRtCbCombineRgn.CombineRgn(&m_RdRtCombineRgn,&StaticRgn,RGN_AND);
CBrush brtmp2(RGB(0,0,255));//原本这是边框区域的颜色,现在也用来填充与边框区域重合部分的文字区域
mdc.FillRgn(&m_StRdRtCbCombineRgn,&brtmp2);
//删除GDI对象
brtmp1.DeleteObject();
brtmp2.DeleteObject();
//最重要的部分,将内存画布里的东西全部滑到屏幕上
dc.BitBlt(0,0,m_rtClient.Width(),m_rtClient.Height(),&mdc,0,0,SRCCOPY);
//控制文本区域的移动
if(m_rtStatic.right<=m_rtRoundRect.left)
{
m_rtStatic.left=m_rtRoundRect.right;
m_rtStatic.right=m_rtStatic.left+m_size.cx;
}
else
{
m_rtStatic.left-=5;
m_rtStatic.right-=5;
}
CDialog::OnTimer(nIDEvent);
}
四:程序遗留问题
因为本人也是初学者,在处理文字的移动时,想要使用位图背景来覆盖掉 已超出边框的文字部分 以及 文字部分和边框部分重合的部分 ,但不知道怎么使用位图背景来覆盖掉超出文字,所以只是手动的根据位图的颜色,自己创建了两个区域(文字区域超出边框的部分,文字区域与边框重合的部分),然后手动使用了两种对应这两个区域的颜色来覆盖掉这两部分,感觉是很大的缺陷,如果能够统一地使用位图背景来统一覆盖掉这两部分,就会少很多问题,如果有网友知道怎么使用位图背景来覆盖掉这两部分,希望能在评论里或写信指导本人一下,感激不尽!!