如何在Windows窗体TextBox控件中设置TAB宽度?

24

如果给定一个具有 MultiLine = trueAcceptsTab == true 的 WinForms 文本框控件,我该如何设置显示的制表符宽度?

我希望将其作为插件的快速脚本输入框,而不需要过多地进行美化,但是如果制表符显示为8个字符宽度就会很糟糕...


1
你应该释放图形资源,最好将其放在using语句中。 - Miha Markic
6个回答

15

我认为向文本框发送EM_SETTABSTOPS消息会起作用。

// set tab stops to a width of 4
private const int EM_SETTABSTOPS = 0x00CB;

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam);

public static void SetTabWidth(TextBox textbox, int tabWidth)
{
    Graphics graphics = textbox.CreateGraphics();
    var characterWidth = (int)graphics.MeasureString("M", textbox.Font).Width;
    SendMessage
        ( textbox.Handle
        , EM_SETTABSTOPS
        , 1
        , new int[] { tabWidth * characterWidth }
        );
}

这可以在你的Form的构造函数中调用,但要注意:确保先运行InitializeComponents


MSDN链接是针对Windows CE的;我已经更改了它。 - SLaks
3
我认为 EM_SETTABSTOPS 使用“对话框模板单位”(有时称为“对话框逻辑单位”或“DLU”)来测量文本。你可以直接说“numChars * 4”(因为每个字符有4个水平 DLUs)。 - Flydog57

12

我知道你当前正在使用一个TextBox,但是如果你可以使用RichTextBox代替,那么你就可以使用SelectedTabs属性来设置所需的制表符宽度:

richTextBox.SelectionTabs = new int[] { 15, 30, 45, 60, 75};

请注意这些偏移量是以像素为单位,而不是字符。


9

谢谢,Loris,我之前不知道这个。 - Daren Thomas

6

通过使用扩展方法,您可以向TextBox控件类添加新方法。以下是我从上面的贡献者那里收集到的实现(包括一个额外的扩展方法,为您提供插入符号当前位置的坐标):

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Extensions
{
    public static class TextBoxExtension
    {
        private const int EM_SETTABSTOPS = 0x00CB;

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam);

        public static Point GetCaretPosition(this TextBox textBox)
        {
            Point point = new Point(0, 0);

            if (textBox.Focused)
            {
                point.X = textBox.SelectionStart - textBox.GetFirstCharIndexOfCurrentLine() + 1;
                point.Y = textBox.GetLineFromCharIndex(textBox.SelectionStart) + 1;
            }

            return point;
        }

        public static void SetTabStopWidth(this TextBox textbox, int width)
        {
            SendMessage(textbox.Handle, EM_SETTABSTOPS, 1, new int[] { width * 4 });
        }
    }
}

不客气!实际上,我在自己的代码中添加了进一步的改进,以确保文本框是多行的,并启用了 AcceptsTab。 - Brien Halstead
谢谢,Brien,这是一种非常好的封装功能的方式! - BillW

4

对于希望使用不同制表位的人,我采取了以下方法:

using System.Runtime.InteropServices;

[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, uint[] lParam);
private const int EM_SETTABSTOPS = 0x00CB;

private void InitialiseTabStops()
{
    // Declare relative tab stops in character widths
    var tabs = new uint[] { 2, 2, 4, 8, 2, 32 };

    // Convert from character width to 1/4 character width
    for (int position = 0; position < tabs.Length; position++)
        tabs[position] *= 4;

    // Convert from relative to absolute positions
    for (int position = 1; position < tabs.Length; position++)
        tabs[position] += tabs[position - 1];

    SendMessage(textBox.Handle, EM_SETTABSTOPS, tabs.Length, tabs);
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接