C# WinForm RichTextBox 如何自定义下划线样式颜色?
为什么要自定义?
「添雨跟打器」中的核心功能之一——「词库管理」。这是一个大类。包含有词库添加、删除、自动提示,智能学习,理论码长等功能。用户在跟打过程中,如何以方便,快捷的方式提示给用户?这是一个产品体验上的问题。
早在「老版添雨跟打器」之中,@hwj 帮忙制作了「提词器」。使用的技术很简单,就是在 RichTextBox 上显示 Label ,用来划出不同的线条,颜色。但是缺点很明显。
- 渲染效率问题
- 显示样式单一
这两个问题都很好解决。但是「效率」和显示的「感观」上的问题仍然有一种,无法让人忍受的问题。例如,在拖动滚动条时,整个显示错位。如果让它们随之滚动,则会存在效率上的问题。两者,似乎存在一种不可兼得的情况。
寻找
为了解决问题。利用搜索引擎,去寻找解决方案。MSDN 是首先的选择。正好,在其上便找到如下一篇 《how to change the underline style》 。里面含有大量的 VB 代码。
手动翻译成 C# 代码如下文。
代码
新建类:
public class Underline
{
public RichTextBox R { get; private set; }
public Underline(RichTextBox richText)
{
this.R = richText;
}
}
创建结构体:
[StructLayout(LayoutKind.Sequential)]
private struct CHARFORMAT
{
public int cbSize;
public uint dwMask;
public uint dwEffects;
public int yHeight;
public int yOffset;
public int crTextColor;
public byte bCharSet;
public byte bPitchAndFamily;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szFaceName;
public short wWeight;
public short sSpacing;
public int crBackColor;
public int LCID;
public uint dwReserved;
public short sStyle;
public short wKerning;
public byte bUnderlineType;
public byte bAnimation;
public byte bRevAuthor;
}
引入 Win32 API:
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref CHARFORMAT lp);
创建属性:
public UnderlineStyle SelectionUnderlineStyle
{
set
{
//Ensure we don't alter the color by accident.
var color = SelectionUnderlineColor;
//Ensure we don't show it if it shouldn't be shown.
if (value == UnderlineStyle.None)
{
color = UnderlineColor.Black;
}
var fmt = new CHARFORMAT
{
yOffset = 100
};
fmt.cbSize = Marshal.SizeOf(fmt);
fmt.dwMask = CFM_UNDERLINETYPE;
fmt.bUnderlineType = (byte)((byte)value | (byte)color);
fmt.bAnimation = 1;
//Set the underline type.
SendMessage(this.R.Handle, EM_SETCHARFORMAT, SCF_SELECTION, ref fmt);
}
get
{
var fmt = new CHARFORMAT
{
yOffset = 4
};
fmt.cbSize = Marshal.SizeOf(fmt);
//Get the underline style.
SendMessage(this.R.Handle, EM_GETCHARFORMAT, SCF_SELECTION, ref fmt);
// Default to no underline.
if ((fmt.dwMask & CFM_UNDERLINETYPE) == 0)
{
return UnderlineStyle.None;
}
var style = (byte)fmt.bUnderlineType & 0xF;
return (UnderlineStyle)style;
}
}
public UnderlineColor SelectionUnderlineColor
{
get
{
var fmt = new CHARFORMAT();
fmt.cbSize = Marshal.SizeOf(fmt);
//Get the underline color.
SendMessage(this.R.Handle, EM_GETCHARFORMAT, SCF_SELECTION, ref fmt);
// Default to black.
if ((fmt.dwMask & CFM_UNDERLINETYPE) == 0)
{
return UnderlineColor.Black;
}
var style = fmt.bUnderlineType & 0xF;
return (UnderlineColor)style;
}
set
{
//Ensure we don't alter the style.
var style = SelectionUnderlineStyle;
//Ensure we don't show it if it shouldn't be shown.
if (style == UnderlineStyle.None)
{
value = UnderlineColor.Black;
}
var fmt = new CHARFORMAT();
fmt.cbSize = Marshal.SizeOf(fmt);
fmt.dwMask = CFM_UNDERLINETYPE;
fmt.bUnderlineType = (byte)((byte)style | (byte)value);
//Set the underline color.
SendMessage(this.R.Handle, EM_SETCHARFORMAT, SCF_SELECTION, ref fmt);
}
}
使用:
var line = new Underline(this.richTextBoxEx1);
this.richTextBoxEx1.SelectionStart = 0;
this.richTextBoxEx1.SelectionLength = 1;
line.SelectionUnderlineStyle = UnderlineStyle.Dash;
line.SelectionUnderlineColor = UnderlineColor.Blue;
其它问题
- 下划线样式好像并不是每个都有效,像 wave 样式
- 颜色方面还没有找到是否可以完全自定义颜色的方式
如果有读者读至此处,了解相关内容,欢迎留言。