提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|使用教程|编辑:鲍佳佳|2021-07-08 09:41:23.733|阅读 391 次
概述:在上一节中讲了CFont字体类,本节主要讲解文本输出的方法和实例。在文本输出到设备以前,我们需要确定字体、字体颜色和输出的文本内容等信息。Windows窗口的客户区由应用程序管理,所以我们还要在应用程序中控制输出文本的格式,例如后续字符的位置、换行等格式。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
相关链接:
在上一节中讲了CFont字体类,本节主要讲解文本输出的方法和实例。
文本输出过程
在文本输出到设备以前,我们需要确定字体、字体颜色和输出的文本内容等信息。Windows窗口的客户区由应用程序管理,所以我们还要在应用程序中控制输出文本的格式,例如后续字符的位置、换行等格式。
由此,文本的输出过程大致包括确定字体信息、格式化文本和执行输出操作三个步骤。下面分别讲解。
1、确定字体信息
文本在输出以前应该先确定字体信息,或者是当前正在使用的字体,或者是自定义的字体,之后就可以根据确定的字体来显示文本或者利用字体信息来设定文本的格式了,例如,我们可以根据当前字体的字符高度来确定下一行字符在什么位置输出。
自定义字体可以通过CFont类的创建字体的几个成员函数完成。获取当前选择字体的信息可以使用API函数GetTextMetrics实现,此函数的原型如下:
BOOL GetTextMetrics(__in HDC hdc,__out LPTEXTMETRIC lptm);
参数hdc为设备上下文的句柄;参数lptm是指向TEXTMETRIC结构体变量的指针,此结构体变量用于接收字体信息。TEXTMETRIC结构体的定义如下:
C++代码
typedef struct tagTEXTMETRIC { LONG tmHeight; // 字符高度 LONG tmAscent; // 字符基线以上的高度 LONG tmDescent; // 字符基线以下的高度 LONG tmInternalLeading; // 由tmHeight成员指定的字符高度顶部的空间 LONG tmExternalLeading; // 行间距 LONG tmAveCharWidth; // 字符的平均宽度 LONG tmMaxCharWidth; // 字符的最大宽度 LONG tmWeight; // 字符的粗度 LONG tmOverhang; // 合成字体间附加的宽度 LONG tmDigitizedAspectX; // 为输出设备设计的x轴尺寸 LONG tmDigitizedAspectY; // 为输出设备设计的y轴尺寸 TCHAR tmFirstChar; // 字体中第一个字符值 TCHAR tmLastChar; // 字体中最后一个字符值 TCHAR tmDefaultChar; // 替换字体中没有的字符 TCHAR tmBreakChar; // 作为分隔符的字符 BYTE tmItalic; // 非0则表示字体为斜体 BYTE tmUnderlined; // 非0则表示字体有下划线 BYTE tmStruckOut; // 非0则表示字符带有删除线 BYTE tmPitchAndFamily;// 字体间距和字体族 BYTE tmCharSet; // 字符集 } TEXTMETRIC, *PTEXTMETRIC;
2、格式化文本
格式化文本一般包括两种,一种是确定文本行中后续文本的位置,另一种是确定换行时下一行文本的位置。
确定后续文本的位置
一般我们可以先获取当前字符串的宽度,根据此宽度确定文本行中后续文本的位置。当前字符串的宽度可以通过API函数GetTextExtentPoint32获得。GetTextExtentPoint32函数的原型如下:
BOOL GetTextExtentPoint32(__in HDC hdc,__in LPCTSTR lpString,__in int c,__out LPSIZE lpSize);
参数hdc为设备上下文的句柄;参数lpString为指向文本字符串缓存的指针,此字符串不是必须以结束符结尾的,因为参数c指定了长度;参数c为lpString指向的字符串的长度;参数lpSize为指向SIZE结构体变量的指针,此SIZE结构体变量用于接收字符串的宽度和高度信息。SIZE结构体定义如下:
C++代码
typedef struct tagSIZE { LONG cx; // 宽度 LONG cy; // 高度 } SIZE, *PSIZE;
已知本字符串的起始水平坐标和宽度,两者相加即是后续文本的起始坐标。
确定换行时下一行文本的位置
由GetTextMetrics函数获取了当前字体的信息并存入TEXTMETRIC结构体后,通过计算当前文本行的垂直坐标、当前字体的高度和行间距之和,就可以得到换行时下一行的垂直坐标。
3、执行文本输出操作
最后,通过API函数TextOut执行文本输出操作。TextOut函数的原型如下:
BOOL TextOut(__in HDC hdc,__in int nXStart,__in int nYStart,__in LPCTSTR lpString,__in int cbString);
参数hdc为设备上下文的句柄;参数nXStart为起始点x坐标;参数nYStart为起始点y坐标;参数lpString为要输出的文本字符串;参数cbString为字符串中要输出的字符的数量。
当然也可以使用设备上下文类CDC的成员函数TextOut来输出,CDC::TextOut函数的两种重载形式如下:
virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);
BOOL TextOut(int x,int y,const CString& str);
参数x指定文本起始点的x坐标;参数y指定文本起始点的y坐标;参数lpszString为要输出的文本字符串;参数nCount指定字符串中的字节个数;参数str为包含要输出的字符的CString对象。
字体和文本输出的应用实例
鸡啄米下面给大家演示一个简单的关于字体和文本输出的实例。功能就是实现两个字符串分别在水平方向和垂直方向上定时滚动。实现步骤如下:
1、创建一个基于对话框的MFC工程,名字设置为“Example48”。
2、在自动生成的对话框模板IDD_EXAMPLE48_DIALOG中,删除“TODO: Place dialog controls here.”静态文本框。
3、在Example48Dlg.h文件中为CExample48类添加成员变量:
C++代码
int m_nTextX; // 水平滚动文本的起始点的x坐标 int m_nTextY; // 垂直滚动文本的起始点的y坐标 CFont m_newFont; // 新字体 CFont *m_pOldFont; // 选择新字体之前的字体
4、在CExample48Dlg类的构造函数中,初始化新添加的成员变量:
C++代码
CExample48Dlg::CExample48Dlg(CWnd* pParent /*=NULL*/) : CDialogEx(CExample48Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_nTextX = 260; m_nTextY = 10; m_pOldFont = NULL; }
5、在CExample48Dlg对话框初始化函数中,创建新的字体,并开启定时器:
C++代码
BOOL CExample48Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. 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); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here // 创建一种新的字体(18点,隶书) m_newFont.CreatePointFont(180, _T("隶书")); // 设置定时器,定时时间为200ms SetTimer(1,200,NULL); return TRUE; // return TRUE unless you set the focus to a control }
6、修改CExample48Dlg::OnPaint()函数,如果窗口没有最小化就在指定的位置输出文本,即在OnPaint函数中if(IsIconic())对应的else大括号内添加相应代码。CExample48Dlg::OnPaint()函数修改如下:
C++代码
void CExample48Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // Center icon in client rectangle 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; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CPaintDC dc(this); // device context for painting // 设置m_newFont对象的字体为当前字体,并将之前的字体指针保存到m_pOldFont m_pOldFont = (CFont*)dc.SelectObject(&m_newFont); // 设置 dc.SetBkMode(TRANSPARENT); //设置背景为透明! // 设置文本颜色为红色 dc.SetTextColor(RGB(255,0,0)); // 在指定位置输出文本 dc.TextOut(m_nTextX,10,_T("欢迎来到鸡啄米!")); // 设置文本颜色为绿色 dc.SetTextColor(RGB(0,255,0)); // 在指定位置输出文本 dc.TextOut(10,m_nTextY,_T("谢谢关注www.jizhuomi.com")); // 恢复以前的字体 dc.SelectObject(m_pOldFont); CDialogEx::OnPaint(); } }
7、在Class View类视图中找到CExample48Dlg,右键点Properties,显示出其属性页,在属性页工具栏上点击Messages按钮,找到WM_TIMER消息,添加消息响应函数CExample48Dlg::OnTimer(UINT_PTR nIDEvent),并在此函数中修改两个文本输出的坐标位置。
C++代码
void CExample48Dlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default LOGFONT logFont; // 获取m_newFont字体的LOGFONT结构 m_newFont.GetLogFont(&logFont); // 将m_nTextX的值减5 m_nTextX -= 5; // 如果m_nTextX小于10,则文本“欢迎来到鸡啄米”回到起始位置 if (m_nTextX < 10) m_nTextX = 260; // 将m_nTextY的值加一个字符高度 m_nTextY += abs(logFont.lfHeight); // 如果m_nTextY大于260,则文本“谢谢关注www.jizhuomi.com”回到起始位置 if (m_nTextY >260) m_nTextY = 10; // 使窗口客户区无效,之后就会重绘 Invalidate(); CDialogEx::OnTimer(nIDEvent); }
到这一步,两个文本就可以分别在水平和垂直方向滚动了。鸡啄米再简单解释下这个过程:程序刚启动时,会调用OnPaint函数,在初始位置绘出两个文本,然后每次到了定时器的定时时间后,会执行OnTimer函数,修改两个文本的坐标值,并通过Invalidate使窗口重绘,又会重新调用OnPaint函数绘制两个文本。这样通过定时修改坐标值就实现了两个文本的滚动效果。
8、运行程序,最终的效果如下图:
好了,本节就讲到这里了,最后的实例大家可以自己丰富下它的功能,看看效果。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@capbkgr.cn
文章转载自:本文将演示如何使用DevExpress WPF Grid控件实现列和带的固定,欢迎下载最新版组件体验!
在本文中,我们将探讨如何通过使用 JxBrowser 和 Quill.js 将现代富文本编辑器嵌入到 Java 桌面应用程序中,来克服 Swing、JavaFX 和 SWT 中内置编辑器的局限性。
Word 文档中的批注通常用于协作审阅和反馈。这些批注可能包含文本和图片,它们为文档改进提供了重要的参考信息。本文将演示如何使用 Spire.Doc for Java 在 Java 中提取 Word 文档中的批注文本和图片。
本文主要介绍如何使用DevExpress WinForms Data Grid组件实现列重新排序,欢迎下载最新版组件体验!
专为Windows平台开发人员提供最全面的Visual C++界面开发组件
BCGControlBar Pro for MFC用于构建类似微软Office、Visual Studio等MFC用户界面高级套包。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@capbkgr.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢