Перенос текста в расширенное текстовое поле, но не перенос слова - PullRequest
5 голосов
/ 15 октября 2010

У меня есть форма Windows с элементом управления Rich Textbox на форме.То, что я хочу сделать, это сделать так, чтобы каждая строка принимала только 32 символа текста.После 32 символов я хочу, чтобы текст перешел на следующую строку (я НЕ хочу вставлять возврат каретки).Свойство WordWrap почти делает это, за исключением того, что оно перемещает весь введенный текст до последнего места в тексте и перемещает все это.Я просто хочу аккуратно обернуть текст сразу после 32 символов.Как я могу это сделать?Я использую C #.

Ответы [ 4 ]

4 голосов
/ 18 октября 2010

Хорошо, я нашел способ сделать это (после многих поисков в Google и ссылок на API Windows), и я публикую здесь решение на тот случай, если кому-нибудь еще понадобится выяснить это. Чистого решения .NET для этого не существует, но, к счастью, Windows API позволяет переопределить процедуру по умолчанию, которая вызывается при обработке переноса слов. Сначала вам нужно импортировать следующую DLL:

[DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

Тогда вам нужно определить эту константу:

 const uint EM_SETWORDBREAKPROC = 0x00D0;

Затем создайте делегат и событие:

    delegate int EditWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);

    event EditWordBreakProc myCallBackEvent;

Затем создайте нашу новую функцию для обработки переноса слов (что в данном случае я не хочу, чтобы она что-либо делала):

     private int myCallBack(IntPtr text, int pos_in_text, int bCharSet, int action)

    {

        return 0;

    }

Наконец, в показанном событии вашей формы:

        myCallBackEvent = new EditWordBreakProc(myCallBack);

        IntPtr ptr_func = Marshal.GetFunctionPointerForDelegate(myCallBackEvent);

        SendMessage(txtDataEntry.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, ptr_func);
2 голосов
/ 15 октября 2010

Если вы используете только (один) шрифт фиксированной ширины для текста в поле расширенного текста, тогда вы можете использовать MeasureString , чтобы подсчитать ширину, необходимую для 32 символов, а затем соответствующим образом настроить ширину поля расширенного текста. Это должно сделать перенос в пределах 32 символов.

0 голосов
/ 12 июля 2019

Принятый ответ почти работает, но немного неловко из-за ненужного использования event, явного создания экземпляра делегата и нестатического метода обратного вызова.

Я говорю «почти», потому что онтакже есть небольшая ошибка: делегат, созданный для обратного вызова, не сохраняется ни в одной переменной, что делает его пригодным для сбора мусора.Сборщик мусора не имеет никакого способа узнать, что вы передали делегат, завернутый в указатель на объект окна, и, таким образом, в конечном итоге сможет отказаться от делегата, что приведет к аварийному завершению приложения.в следующий раз элемент управления TextBox необходим для переноса любого текста.

Вот версия, которая мне больше нравится:

public partial class Form1 : Form
{
    [System.Runtime.InteropServices.DllImport("user32.dll")]

    extern static IntPtr SendMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam);

    private const uint EM_SETWORDBREAKPROC = 0x00D0;

    private delegate int SetWordBreakProc(IntPtr text, int pos_in_text, int bCharSet, int action);
    private readonly SetWordBreakProc _wordBreakCallback = (text, pos_in_text, bCharSet, action) => 0;

    public Form1()
    {
        InitializeComponent();
        textBox1.HandleCreated += TextBox1_HandleCreated;
    }

    private void TextBox1_HandleCreated(object sender, EventArgs e)
    {
        IntPtr callback = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_wordBreakCallback);

        SendMessage(((Control)sender).Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, callback);
    }
}

Другое отличие состоит в том, что я инициализирую слово-прервать процесс в обработчике событий TextBox.HandleCreated.Это выполняет две вещи: во-первых, инициализация происходит как можно скорее, сразу после того, как дескриптор элемента управления является действительным, и, во-вторых, путем инициализации на этой ранней стадии процесса, если свойство TextBox.Text уже было установлено, например, в Designer.или конструктор формы, обтекание все равно будет выполнено правильно даже для этого исходного текста.

Текст, вставленный позже, все еще будет в порядке, и, конечно, вы могли бы даже временно временно сбросить текст после инициализации, чтобы вызвать пересчетупаковкаНо ИМХО, во-первых, лучше просто заставить его работать достаточно рано.

Также обратите внимание, что приведенное выше требует явной инициализации каждого TextBox, который вы добавили в форму.Очевидно, что если вы хотите применить эту технику более чем к одному TextBox, имеет смысл создать новый подкласс TextBox, который выполняет эту инициализацию в своем собственном методе переопределения OnHandleCreated().

0 голосов
/ 03 августа 2012

Я сам изучал эту проблему и нашел действительно простой способ обойти это. Вам нужно поместить небольшой фрагмент кода в событие Key_Down в элементе управления TextBox или RichTextBox.

Убедитесь, что свойства Word Wrap и Multiline по-прежнему установлены в true, тогда вам просто нужно проверить нажатие клавиши KeyCode.Return & Keycode.Enter.

Как показано ниже: -

private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
            {
                e.Handled = true;
            }

        }

Устанавливая обработанное вами значение в значение true, отправляет обратно сообщение о том, что мы имели дело с событием нажатия клавиши, и ничего не происходит. Text Control продолжает использовать Word Wrap и блокирует возврат каретки.

Надеюсь, это поможет.

...