5

これにより、現在の行の背景色として透明な色をペイントすることで、各行の幅全体が強調されます。回線が切り替わると、元の背景色が復元されます。

したがって、私たちがやりたいことは次のとおりです。

  1. 以前の長方形と現在の長方形が一致しないことを確認して、同じ領域を 2 回ペイントしないようにします。
  2. コントロールの背景色を使用して、最後の行のハイライトを置き換えます
  3. 透明色を使用して現在の行を強調表示します
  4. mLastHighlight適用された各行のインデックスと長方形で設定

ただし、ハイライトを削除すると、テキストが塗りつぶされます。これは、ハイライトを適用する場合には発生しません。

1 つの解決策は、背景色をリセットした後で、コントロールのテキストを再描画することです。ただし、テキストの書式設定、選択色、フォント スタイル、ハイパーリンクなどをフィルタリングするのは面倒です。あまりエレガントではありません。

これにより、コントロールが更新され、よりシンプルなソリューションにつながります。それは大きなちらつきを引き起こすでしょうが。どちらも受け入れられません。

エレガントなソリューションはありますか?なぜこれが起こるのか、私は完全に困惑しています。

編集: Code Gray の応答を反映するように編集されました。

using System;

public class RTBHL : RichTextBox
{
    private LastHighlight mLastHighlight = new LastHighlight(0, Rectangle.Empty);

    private class LastHighlight
    {
        public int mCharIndex;
        public Rectangle mRectangle;

        public LastHighlight(int index, Rectangle r)
        {
            mCharIndex = index;
            mRectangle = r;
        }
    }

    public void PaintLineHighlight()
    {
        using (Graphics g = this.CreateGraphics)
        {
            // highlight color
            Color c = Color.Beige;
            // current pen color
            Pen cp = new Pen(Color.Beige);
            // color for removing highlight
            Pen lp = new Pen(this.BackColor);
            // brush for removing highlight
            SolidBrush lb = new SolidBrush(this.BackColor);
            // brush for applying highlight
            SolidBrush cb = new SolidBrush(Color.FromArgb(64, c.R, c.G, c.B));
            // index of the current line
            int index = this.GetFirstCharIndexOfCurrentLine;
            // rectangle to specify which region to paint too
            Rectangle r = new Rectangle();

            // specify dimensions
            r.X = 0;
            r.Y = this.GetPositionFromCharIndex(index).Y;
            r.Width = this.HorizontalScrollBarWidth;
            r.Height = Convert.ToInt32(this.Font.Height * this.ZoomFactor);

            // this will always be true unless the current line remains the same
            if (!(mLastHighlight.mCharIndex == index) && !(mLastHighlight.mRectangle == r))
            {
                // remove the last highlight. regardless of the brush specified, white is always applied, and the text is painted over
                g.DrawRectangle(lp, mLastHighlight.mRectangle);
                g.FillRectangle(lb, mLastHighlight.mRectangle);
                // apply highlight to the current line
                g.DrawRectangle(cp, r);
                g.FillRectangle(cb, r);
            }

            mLastHighlight = new LastHighlight(index, r);
        }
    }

#region RichScrollBars
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, ref SCROLLINFO si);

    [StructLayout(LayoutKind.Sequential)]
    public class SCROLLINFO
    {
        public int cbSize;
        public int fMask;
        public int nMin;
        public int nMax;
        public int nPage;
        public int nPos;
        public int nTrackPos;
        public SCROLLINFO()
        {
            this.cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
        }

        public SCROLLINFO(int mask, int min, int max, int page, int pos)
        {
            this.cbSize = Marshal.SizeOf(typeof(SCROLLINFO));
            this.fMask = mask;
            this.nMin = min;
            this.nMax = max;
            this.nPage = page;
            this.nPos = pos;
        }
    }

    private const int SIF_ALL = 0X17;
    private const int SB_HORZ = 0;
    private const int SB_VERT = 1;

    public int HorizontalScrollBarWidth()
    {
        SCROLLINFO si = new SCROLLINFO() {fMask = SIF_ALL};
        GetScrollInfo(this.Handle, SB_HORZ, si);

        return Math.Max(si.nMax, this.Width);
    }

    public int VerticalScrollBarHeight()
    {
        SCROLLINFO si = new SCROLLINFO() {fMask = SIF_ALL};
        GetScrollInfo(this.Handle, SB_VERT, si);

        return Math.Max(si.nMax, this.Height);
    }
#endregion
}
4

1 に答える 1

3

ここでの問題は、コピーしているコードが Scintilla 用に設計されていることです。SCI_*定数は Scintilla ヘッダーによって内部的に定義され、それらが参照するメッセージは Scintilla コントロールに対してのみ意味を持ちます。

これらのメッセージをネイティブの Win32 リッチ エディット コントロールに送信しても、これらのメッセージを処理するように設計されていないため、何も起こりません。(さらに悪いことに、1 つまたは複数のSCI_*定数が、リッチ エディット コントロール認識する 1 つまたは複数のメッセージ ID と衝突し、興味深い動作を引き起こす可能性があります。)

プロジェクトで実際に Scintilla エディット コントロールを使用していない限り (使用したくないと言った場合)、そのコードは興味深いことを何も行いません。これは Win32 リッチ エディット コントロール用に作成されたものではなく、Scintilla コントロールとのインターフェイス用に作成されたものです。

Scintilla コントロールは、Win32 リッチ エディット コントロールの単なるラッパーではありません。魔法のようにするには多くのカスタム描画を行う必要があり、そのすべてのコードを自分で正しく作成するのは困難です。それが、そもそも非常に多くの人が Scintilla を使用している理由です。その機能セットが必要な場合は、それに倣うことを強くお勧めします.

とにかく、これが Win32 リッチ エディット コントロールで可能かどうかは実際にはわかりません。そうではないと思いますが、その事実を断言することはできませんでした。選択色を設定することでハックできると思いますが、それはあまり良い解決策とは思えません。ダニエルのような何かがここで示唆しています。私は Scintilla の専門家ではありませんが、訓練を受けていない私の目には、これは Scintilla ベースのコードと道徳的に同等のように見えますが、Win32 リッチ エディット コントロール用に (その .NET WinForms ラッパーを介して) 書かれています。

于 2012-07-25T08:36:20.763 に答える