5

選択を変更するたびに、RichTextBox が特定の他のテキストの色を変更する必要があるWinFormsプログラムがあります。これを行うには、そのテキストを選択する必要があるため、現在の選択が失われます。

SelectionStart プロパティと SelectionLength プロパティを保存して読み込むことはできますが、「選択方向」を維持することはできません: ユーザーがカーソルから前方または後方に強調表示されている場合。

選択方向を保存する方法、または選択を変更せずにテキストに色を付ける方法についてのアイデアはありますか?

4

3 に答える 3

2

私はちょうど同じ問題に遭遇しましたが、今ではEM_EXSETSELを使用してこれを解決しました。cpMin > cpMax の場合、「後方選択」(選択したテキストの先頭にあるキャレット) のように機能します。それでも、現在の選択方向を見つける他の方法は見つかりませんでした (EM_EXGETSEL は常に cpMin < cpMax を返しました) が、SelectionStart/Length の変更に従ってください...

編集:

それは私がこれを解決するために使用しているものです。もっと簡単な方法があるかもしれませんが、少なくとも次の方法でうまくいきます。

using System.Runtime.InteropServices;

//********************
//SendMessage stuff for EM_EXSETSEL
//********************

[StructLayout(LayoutKind.Sequential)]
public struct CHARRANGE
{
    public int cpMin;
    public int cpMax;
}

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref CHARRANGE lParam);

private const UInt32 WM_USER = 0x0400;
private const UInt32 EM_EXSETSEL = WM_USER + 55;
private const UInt32 EM_EXGETSEL = WM_USER + 52;

//********************
//event handlers
//********************

//locking variable to avoid stack overflow while setting selection in code
private bool richTextBox1_SelectionChanged_lock = false;

//handler for richTextBox selection change event
private void richTextBox1_SelectionChanged(object sender, EventArgs e)
{
    if (richTextBox1_SelectionChanged_lock) return;
    richTextBox1_SelectionChanged_lock = true;

    //detect selection changes and store information needed for restoring
    TrackRTBSelection(richTextBox1.SelectionStart, richTextBox1.SelectionLength);

    //here do whatever you want with selection (some analysis to show font name in font selection comboBox etc.)
    //...

    //restore selection from saved informations
    SetRTBSelectionBasedOnTracking();

    richTextBox1_SelectionChanged_lock = false;
}

//sample button click handler for changing fore color of selected text
private void buttonSetForeColor_Click(object sender, EventArgs e)
{
    if (colorDialog1.ShowDialog() == DialogResult.Cancel)
        return;

    //prevent selection change events while we are changing font colors
    if (richTextBox1_SelectionChanged_lock) return;
    richTextBox1_SelectionChanged_lock = true;

    //save selection parameters for use in loop
    int selStart = richTextBox1.SelectionStart;
    int selLength = richTextBox1.SelectionLength;

    for (int i = 0; i < selLength; i++)
    {
        richTextBox1.SelectionLength = 1;
        richTextBox1.SelectionStart = selStart + i;

        richTextBox1.SelectionColor = colorDialog1.Color;
    }

    //restore selection from saved informations
    SetRTBSelectionBasedOnTracking();

    richTextBox1_SelectionChanged_lock = false;
}

//********************
//selection tracking utilities
//********************

//false - caret at the beginning; true - caret at the end
private bool caretPosition = false;
private int lastSelectionStart = -1;
private int lastSelectionLength = -1;

//initialize selection informations. this must be called during Form_Load
private void InitRTBSelection()
{
    richTextBox1.SelectionStart = 0;
    richTextBox1.SelectionLength = 0;

    caretPosition = false;
    lastSelectionStart = 0;
    lastSelectionLength = 0;

    //force "selection changed" to detect "selection changes" for the first time
    richTextBox1_SelectionChanged(richTextBox1, new EventArgs());
}

//this method detects changes in selection, based on selection parameters received from richTextBox
private void TrackRTBSelection(int newSelectionStart, int newSelectionLength)
{
    int condition = 0;

    int s_change = (newSelectionStart - lastSelectionStart > 0) ?
                    1 :
                    (newSelectionStart - lastSelectionStart < 0) ? -1 : 0;
    int l_change = (newSelectionLength - lastSelectionLength > 0) ?
                    1 :
                    (newSelectionLength - lastSelectionLength < 0) ? -1 : 0;

    //these conditions where created over change table for all user-achievable scenarios
    condition = (newSelectionLength == 0 ||
                (l_change == 1 && s_change == -1) ||
                (l_change == -1 && s_change == 1 && caretPosition == false)) ? 1 : condition;
    condition = (s_change == 0 && (l_change == 1 || (caretPosition == true && l_change == -1))) ? 2 : condition;

    switch (condition)
    {
        case 1: caretPosition = false; break;
        case 2: caretPosition = true; break;
        default: break; //if no condition was satisfied then maintain current information
    }

    lastSelectionStart = newSelectionStart;
    lastSelectionLength = newSelectionLength;
}

//set richTextBox selection using EM_EXSETSEL
private void SetRTBSelectionBasedOnTracking()
{
    CHARRANGE chrrange = new CHARRANGE
    {
        cpMin = caretPosition ? lastSelectionStart : lastSelectionStart + lastSelectionLength,
        cpMax = caretPosition ? lastSelectionStart + lastSelectionLength : lastSelectionStart
    };
    SendMessage(richTextBox1.Handle, EM_EXSETSEL, IntPtr.Zero, ref chrrange);
}
于 2015-07-02T09:39:58.967 に答える
1

うん、醜い問題。いいえ、EM_SETPARAFORMATは現在の選択でのみ機能します。また、EM_EXSETSELは、常にカレットを選択の最後に配置します。SelectionStartの変化を観察することで選択方向を検出することはできますが、適切な場所にキャレットを配置することはできません。編集コントロールにも同じ問題があります。

色の変更は、ユーザーがテキストを選択しているときではなく、ユーザーがテキストを変更したときにのみ発生するため、通常は問題になりません。私が考えることができる唯一の回避策は、キーストロークを挿入することによって選択を復元することです。それは醜いです。

于 2010-09-27T07:23:46.390 に答える
0

もう 1 つの方法は、Rtf プロパティを直接設定することです。rtf 言語の構文を知っている必要があります。

PS。それも選択を無効にします。私は自分でキーストロークインジェクションを行いました。

于 2012-05-09T11:45:15.210 に答える