【啰嗦2句】
现在用C#的人很少了吧?GDI+更少了吧?所以这个问题估计也冷门。没关系,分享给特定需要的人也不错。
【问题现象】
工作中开发了一个报告编辑器,实现图文排版等功能,用着没什么问题,直到有一天发现,文本框粘贴的内容暗藏Tab键(保存为\t字符),比如“银丝鸡蛋面 GB 28050-2011 100克 ”,用DrawString怎么绘制都会忽略中间的间距,变成“银丝鸡蛋面GB 28050-2011100克”。
比较糟糕的是MySQL数据库查看时的值也是“银丝鸡蛋面GB 28050-2011100克”。
【分析历程】
刚开始并不知道是中间包含着Tab键,从MySQL数据库复制到NotePad++后,发现有这个tab分隔才找到原因。还以为是没法保存\t这个符号。
既然有这个键值为什么DrawString没有识别并区分呢?不知道。CSDN的做法比较巧妙,我编辑这篇文章时,看到CSDN把Tab键转换成了8个空格。这个是不错的做法,按理说我的报告编辑器也可以这么做。但是,仍然希望所见所得吧,作为报告,希望保留内容的原始性。
最终在微软在线文档中发现有个StringFormat.SetTabStops()方法,似乎是一个希望。链接看这个:微软文档StringFormat.SetTabStops(Single, Single[]) 方法
【解决案例】
1、微软文档的做法,其实并没有解决问题。
新建一个窗体Form1,双击Paint事件编辑代码。
/// <summary>
/// 直接在Form的Paint演示
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Paint(object sender, PaintEventArgs e)
{
//注意“直接的”前面是换行符
string text = "Hello, 移动中的鸭子!\n直接的\t方法\t来获\t取每\t个字符的精确位置。";
Graphics graphics = e.Graphics;
// 设置文本的布局,制表符将会根据这个对齐方式计算
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Near;
//这个tabStops是重点,但是也很难搞懂
float[] tabStops = { 100.0f,50.0f,20.0f,100.0f,20.0f }; //每个间隔跟上一个的间隔像素
format.SetTabStops(0, tabStops);//设置起始符位置0,其他的按tabStops
graphics.DrawString(text, this.Font, new SolidBrush(Color.Green), 10, 10, format);
}
原文:Hello, 移动中的鸭子!\n直接的\t方法\t来获\t取每\t个字符的精确位置
运行效果如下图:
这里微软官方解释:
tabStops
数组中的每个制表位偏移量(第一个除外)相对于上一个。 第一个制表位偏移量相对于由firstTabOffset
指定的初始偏移位置。 例如,如果初始偏移位置为 8,第一个制表位偏移量为 50,则第一个制表位位于位置 58。 如果初始偏移位置为零,则第一个制表位偏移量相对于位置 0(字符串原点)。
实际我测试了多个tabStops数组值,第一个值比较准,其他表现得莫名其妙。比如:
tabStops = { 100.0f,50.0f,20.0f,50.0f}
由于资料很少,所以这个方案只能作为参考,可能受不同系统语言、地区等影响表现未必符合要求。有兴趣的读者可以再摸索摸索。
2、参照CSDN这种做法,直接把\t替换为4个或8个空格。推荐用这种方法。
label3.Text = text.Replace("\t", " ");