65.9K
CodeProject 正在变化。 阅读更多。
Home

XHTMLStatic - 一个极其精简的自定义控件,用于显示 HTML

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (39投票s)

2002 年 9 月 16 日

CPOL

9分钟阅读

viewsIcon

279714

downloadIcon

4275

一个基于 CStatic 的自定义控件,它可以解释并显示常见的 HTML 文本格式化元素,如粗体、斜体、颜色、字体和大小,但只会为您的应用程序增加 16 KB 的体积。

引言

在应用程序中有许多地方,漂亮的文本格式都能让您的软件看起来更精致——例如在关于框、启动屏幕,甚至注册对话框中。当我想办法实现这一点时,我发现了以下几种选择:

  1. 富文本控件 - 这是最难使用的一种,因为它涉及非常复杂的 API 和自定义代码——除非您愿意学习 RTF。 (我不知道您是否和我一样,但那些反斜杠让我头晕。) CodeProject 在这里有许多关于富文本控件的文章:这里
  2. CHtmlCtrl - 这是 Paul DiLascia 编写的一个不错的基于 CHtmlView 的控件。您可以在 2000 年 1 月的 MSJ 中找到它。好吧,显然我没有走这条路。为什么没有?这里是 DiLascia 在他的文章中的最后一句话,它解释了如何在 About 对话框中使用 CHtmlCtrl:
    "...一句忠告:加载所有这些 Internet Explorer DLL 需要一些时间。如果运行 About 对话框需要 10 秒钟和沙漏光标,用户可能会认为您的应用程序是由一个笨蛋编写的。"
  3. QHTM - 这是一个共享软件产品,还有一个“精简版”的免费软件版本,可以在这里找到。最初看起来不错,但后来我发现“精简版”DLL 的大小是 248 KB。当您只需要简单的文本格式化时,引入这么多代码太浪费了。而且,即使是共享软件版本,您也无法获得源代码——您必须额外付费才能获得源代码。

因此,在这些选择之间,您必须在复杂性和/或代码臃肿之间做出选择。这让我很失望,但也促使我思考如何显示简单的文本格式。

首先,基于什么来创建新的控件?为了保持尽可能简单,我选择了 CStatic。其次,使用什么格式?这是一个容易的决定,因为显然 HTML 正在成为首选的格式标准。下一个决定是支持哪些 HTML 元素。这里在实现简单紧凑的功能和实现 CHtmlCtrl 所做的事情之间没有明确的界限。例如,目前我不需要显示表格,这就消除了很多复杂性。如果我将来需要表格,我可能会直接使用 CHtmlCtrl——毕竟,如果您真的需要这个功能,为什么不直接从微软那里获取呢?最后的决定也很容易:新控件将不支持任何交互元素,除了一个:超链接。

CXHTMLStatic 功能

CXHTMLStatic 支持以下 HTML 标签:

Tag 语法 属性
A - 锚点 <A>...</A> HREF="https://codeproject.org.cn"
HREF="mailto:hdietrich@gmail.com"
HREF="app:MY_COMMAND_MESSAGE"
BIG - 大号文本 <BIG>...</BIG> Screenshot - blank2.png
B - 粗体文本 <B>...</B> Screenshot - blank1.png
BR - 换行 <BR> Screenshot - blank2.png
CENTER - 文本居中 <CENTER>...</CENTER> Screenshot - blank1.png
CODE - 软件代码文本 <CODE>...</CODE> Screenshot - blank2.png
FONT - 字体更改 <FONT>...</FONT> COLOR="颜色字符串"
BGCOLOR="颜色字符串"
SIZE="大小调整"
FACE="字体名称"
HR - 水平线 <HR> SIZE=线条粗细
I - 斜体文本 <I>...</I> Screenshot - blank1.png
SMALL - 小号文本 <SMALL>...</SMALL> Screenshot - blank2.png
STRIKE - 删除线文本 <STRIKE>...</STRIKE> Screenshot - blank1.png
SUB - 下标文本 <SUB>...</SUB> Screenshot - blank2.png
SUP - 上标文本 <SUP>...</SUP> Screenshot - blank1.png
U - 下划线文本 <U>...</U> Screenshot - blank2.png

除了 FONTBGCOLOR 属性和 Aapp: 说明符之外,所有这些标签都是标准的 HTML。

使用 FONT 标签

FONT 的 COLOR BGCOLOR 属性都接受一个 color string value,它是一个有三种形式的字符串:

  • "颜色名称" - 示例:"red"。
  • "十六进制值" - 示例:"#FF0000"。
  • "RGB 值" - 示例:"255,0,0"。

FONTSIZE 属性目前只接受相对大小的调整——加或减。例如,SIZE="+4"SIZE="-2"

使用 APP: 超链接

XHTMLStatic 控件中使用 APP: 超链接需要三个步骤:

  1. 定义 APP: 结构 - 这是一个示例表:
    ///////////////////////////////////////////////////////////////////
    //
    // define app command message used by <a href=\"app:WM_APP_COMMAND\">
    //
    #define WM_APP_COMMAND_1 (WM_APP+100)
    
    XHTMLSTATIC_APP_COMMAND CXHTMLStaticTestDlg::m_AppCommands[] = 
    {
        { m_hWnd, WM_APP_COMMAND_1, 1, _T("WM_APP_COMMAND") }
    };

    这个表只有一个条目,但您可以添加任意多的条目。每个条目有四个元素:第一个是要接收消息的窗口的 HWND;第二个是通过 SendMessage() 发送到窗口的数字消息编号;第三个是用户定义的数据,将在 wParam 成员中返回;第四个是用于将表条目与 HTML 代码关联的字符串。当用户单击链接时,XHTMLStatic 将扫描该表,尝试找到与 "app:" 后面的字符串匹配的条目。然后,它将从表中提取消息编号并发送消息。

  2. 将表地址传递给 XHTMLStatic 控件:
        m_static1.SetAppCommands(m_AppCommands, 1);

    此函数传递表地址和表中的条目数。XHTMLStatic 控件会自己复制一份表,因此父窗口无需确保其持久性。

  3. 在 HTML 中插入超链接 — 在 XHTMLStaticTestDlg.cpp 中,APP: 超链接的 HTML(此处未显示字体标签)的写法如下:
        _T("<a href=\"app:WM_APP_COMMAND1\">Moby Dick</a>")

    app: 后面的字符串 "WM_APP_COMMAND" 是将超链接与步骤 1 中的应用程序命令表关联起来的。请注意,此字符串可以是您想要的任何内容;为了提高可读性,您可以使用实际消息命令常量的“字符串形式”。

使用字符实体

对字符实体的支持是上一个版本中最受欢迎的功能之一。我希望支持所有常用的字符实体,但又不想有一个巨大的表,包含大多数人永远不会使用的字符。折衷方案是:一个驱动的实体查找表,该表可以轻松添加新条目。

它是如何工作的:

  1. 实体表在 XHTMLStatic.h 中定义为:
    static XHTMLSTATIC_CHAR_ENTITIES    m_aCharEntities[];
    表中的每个条目定义为:
    struct XHTMLSTATIC_CHAR_ENTITIES
    {
        TCHAR * pszName;    // string entered in HTML - e.g., " "
        TCHAR   cCode;      // code generated by XHTMLStatic
        TCHAR   cSymbol;    // character symbol displayed
    };
  2. 表在 XHTMLStatic.cpp 中指定:
    XHTMLSTATIC_CHAR_ENTITIES CXHTMLStatic::m_aCharEntities[] = 
    {
        { _T("&"),     0,  _T('&') },     // ampersand
        { _T("&bull;"),    0,  _T('\x95') },  // bullet      NOT IN MS SANS
                                              //             SERIF
        { _T("&cent;"),    0,  _T('\xA2') },  // cent sign
        { _T("&copy;"),    0,  _T('\xA9') },  // copyright
        { _T("&deg;"),     0,  _T('\xB0') },  // degree sign
        { _T("&euro;"),    0,  _T('\x80') },  // euro sign
        { _T("&frac12;"),  0,  _T('\xBD') },  // fraction one half
        { _T("&frac14;"),  0,  _T('\xBC') },  // fraction one quarter
        { _T("&gt;"),      0,  _T('>') },     // greater than
        { _T("&iquest;"),  0,  _T('\xBF') },  // inverted question mark
        { _T("&lt;"),      0,  _T('<') },     // less than
        { _T("&micro;"),   0,  _T('\xB5') },  // micro sign
        { _T("&middot;"),  0,  _T('\xB7') },  // middle dot = Georgian comma
        { _T(" "),    0,  _T(' ') },     // nonbreaking space
        { _T("&para;"),    0,  _T('\xB6') },  // pilcrow sign = paragraph sign
        { _T("&plusmn;"),  0,  _T('\xB1') },  // plus-minus sign
        { _T("&pound;"),   0,  _T('\xA3') },  // pound sign
        { _T("&quot;"),    0,  _T('"') },     // quotation mark
        { _T("&reg;"),     0,  _T('\xAE') },  // registered trademark
        { _T("&sect;"),    0,  _T('\xA7') },  // section sign
        { _T("&sup1;"),    0,  _T('\xB9') },  // superscript one
        { _T("&sup2;"),    0,  _T('\xB2') },  // superscript two
        { _T("&times;"),   0,  _T('\xD7') },  // multiplication sign
        { _T("&trade;"),   0,  _T('\x99') },  // trademark   NOT IN MS SANS
                                              //             SERIF
        { NULL,            0,  0 }            // MUST BE LAST

    要添加一个条目,只需按照与其他条目相同的格式操作即可。您可以使用 Microsoft 的字符映射表实用程序 charmap.exe 来获取十六进制显示代码。

  3. 就是这样!当 XHTMLStatic 控件看到实体名称时,它将用显示代码进行替换。
使用字符实体时需要注意一点:有些字体,如 MS Sans Serif,其可用字形非常有限。所以您应该验证它们是否显示正常,或者在显示它们之前选择另一种字体。

下表显示了字符实体将如何显示:

实体 显示符号 描述
& & ampersand
&bull; 圆点 (MS SANS SERIF 中没有)
&cent; ¢ 美分符号
&copy; © 版权
&deg; ° 度符号
&euro; 欧元符号
&frac12; ½ 分数 一半
&frac14; ¼ 分数 四分之一
&gt; > greater than
&iquest; ¿ 反问号
&lt; < less than
&micro; µ 微符号
&middot; · 中间点 = 格鲁吉亚逗号
&nbsp; Screenshot - blank2.png 不间断空格
&para; 段落符号 = 段落符号
&plusmn; ± 加减号
&pound; £ 英镑符号
&quot; " 引号 = 双引号
&reg; ® 注册商标
&sect; § 节符号
&sup1; ¹ 上标一
&sup2; ² 上标二
&times; × 乘号
&trade; 商标 (MS SANS SERIF 中没有)

CXHTMLStatic 演示

演示项目提供了一个示例应用程序,展示了 XHTMLStatic 控件的外观。

screenshot

演示展示了大多数 XHTMLStatic 功能,包括下标和上标、字体以及 http: 和 app: 超链接。

按“点击此处查看 HTML”按钮,HTML 将在单独的对话框中显示。

screenshot

当您单击标题时,您将看到父对话框捕获到 APP: 消息。

screenshot

当前限制

  1. 支持的 HTML 标签仅限于上面列出的那些。
  2. 目前,更改同一行上字体的尺寸不会产生预期的结果。对于任何希望这样做的人来说,这可以通过跟踪基线并调整绘图文本的矩形来修复。
  3. 在解析 HTML 时做了一些简化假设——例如,假设在 < 和标签的开始之间没有空格。另一个假设是,序列 "<a href=" 在 "a" 和 "href" 之间只有一个空格,并且 "href" 和 "=" 之间没有空格。

如何使用

要将此 CXHTMLStatic 集成到您自己的应用程序中,您首先需要将以下文件添加到您的项目中:

  • XHTMLStatic.cpp
  • XHTMLStatic.h
  • XNamedColors.cpp
  • XNamedColors.h

接下来,在您的对话框中创建一些静态控件,您想要放置新的 XHTMLStatic 控件。还请使用 ClassWizard 为这些控件指定变量名。然后,在对话框的头文件中包含 XHTMLStatic.h 头文件,并将 CStatic 变量替换为 CXHTMLStatic。这显示了演示中的 XHTMLStaticTestDlg.h 头文件。

#include "XHTMLStatic.h"

//////////////////////////////////////////////////////////////////////
// CXHTMLStaticTestDlg dialog

class CXHTMLStaticTestDlg : public CDialog
{
// Construction
public:
    CXHTMLStaticTestDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
    //{{AFX_DATA(CXHTMLStaticTestDlg)
    enum { IDD = IDD_XHTMLSTATICTEST_DIALOG };
    CXHTMLStatic    m_static1;
    CXHTMLStatic    m_static2;
    //}}AFX_DATA
    .
    .
    .

最后一步是在 XHTMLStatic 控件中放入一些文本。使用您通过 ClassWizard 添加的变量,您可以说:

    m_static1.SetWindowText(_T("<b><font size=\"+8\">Moby Dick</font></b>"));

有关如何使用 CXHTMLStatic 的示例,请参阅 XHTMLStaticTestDlg.cpp

修订历史

版本 1.4 - 2007 年 10 月 19 日

  • 修复了文本可能写在控件客户区外面的错误,该错误由 David Pritchard 报告(并附带修复)。
  • 扩展了字符实体的表格。
  • 添加了 VS2005 项目。
  • 实现了内存 DC 以提高性能,由 conan.ks 建议。
  • 从 WM_TIMER 切换到 WM_MOUSEMOVE 来显示手形光标,由 rm2 和 RichardC 建议。这可以防止手形光标出现在重叠的窗口上。

版本 1.3 - 2006 年 8 月 15 日

  • 添加了透明度支持,由 Anna 建议。
  • 添加了对 WM_PRINT 的支持,由 beaus07 建议。
  • 添加了对 <center> 的支持,这是由几位读者请求的。
  • 为超链接添加了工具提示支持。
  • IDC_HAND 加载手形光标,由 kamnas 建议。
  • 修复了字体对象泄露问题,由 furbo 报告。
  • 修复了 SetWindowText() 的问题,由 Andro67 报告;调用 SetWindowText() 时背景和文本颜色不再被重置。
  • 修复了控件隐藏时的错误,由 RichardC 报告。

版本 1.2 - 2004 年 6 月 12 日

  • 将 APP: 超链接从使用 GetParent 改为使用 HWND。
  • XHTMLSTATIC_APP_COMMAND 结构添加了 wParam。
  • 添加了函数 SetTextColor(LPCTSTR lpszColor)
  • 添加了函数 SetLogFont(const LOGFONT * pLogFont)
  • 添加了函数 SetWindowText() 以调用 Init 和 RedrawWindow
  • 修复了 XNamedColors 在处理“255,0,0”样式时的错误。
  • SetColorFromString() 中。
  • 修复了大型衬线字体的下伸部问题。

版本 1.1 - 2004 年 5 月 20 日

  • 实现了 SUB 标签。
  • 实现了 SUP 标签。
  • 实现了 BIG 标签。
  • 实现了 SMALL 标签。
  • 实现了 CODE 标签。
  • 实现了 HR 标签。
  • 实现了 APP: 超链接。
  • 实现了常见的字符实体。
  • 提高了解析性能。
  • 错误修复。

版本 1.0 - 2002 年 9 月 16 日

  • 首次公开发布。

用法

本软件已进入公共领域。您可以自由地以任何方式使用它,但不得出售此源代码。如果您修改或扩展它,请考虑将新代码发布到此处供大家分享。本软件按“原样”提供,不附带任何明示或暗示的保证。对于本软件可能造成的任何损害或业务损失,本人概不负责。

© . All rights reserved.