2016-11-21 10 views
0

私はカスタムのRichTextBoxコントロールを作成して、テキスト領域にグラフィックを追加しています。私が読んできたことから、このコントロールはデフォルトでPaintイベントを公開しません。PAINTSTRUCTの空の更新領域を返すPInvokeからBeginPaintを呼び出す

MSDN(Painting on a RichTextBox Control)の提案に従って、Paintイベントを再度公開し、WM_PAINTメッセージによってトリガーされるOnPaintイベントハンドラーを作成しました。

OnPaintメソッドでは、BeginPaint()をWin32 APIから呼び出していくつかの図形を描画しようとしていますが、何も描画されていません。 PAINTSTRUCT構造体内のrcPaintフィールドを調べると、常に空になります(すべての値は0です)。だから私の質問は、なぜ更新領域は常に空ですか?私は何かを欠いているに違いない。

関連するコード:

public partial class RichTextBoxEnhanced : RichTextBox 
{ 

    private PAINTSTRUCT ps; 


    new public void OnPaint(PaintEventArgs e) 
    { 
     var hdc = BeginPaint(this.Handle, out ps); 

     FillRect(hdc, ref ps.rcPaint, CreateSolidBrush(100)); 

     Rectangle(hdc, 1000, 2000, 1000, 2000); 

     EndPaint(this.Handle, ref ps); 

     Paint?.Invoke(this, e); 
    } 

    [DllImport("user32.dll")] 
    static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint); 

    [DllImport("user32.dll")] 
    static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint); 

    [DllImport("gdi32.dll")] 
    static extern IntPtr CreateSolidBrush(uint crColor); 
} 
+2

私は時間によって 'のOnPaintを()'と呼ばれていることを推測しています、.NETがすでに 'BeginPaint関数(と呼ばれた)':

間違っコード:

protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_PAINT: mBaseControl.Invalidate(); base.WndProc(ref m); OnPaint(); break; default: base.WndProc(ref m); break; } } 

正しいコード'PaintEventArgs'を取り込むため、返されたDCは' NULL'(失敗を示すため)になるかもしれません... – andlabs

+0

@andlabs、これは確かに問題でした。どうやら、私のOnPaintメソッドに達する前に、Base.WndPrcがBeginPaintを呼び出していました。 –

答えて

0

この問題が見つかりました。 @andlabsのコメントは、私のオーバーライドされたWndProcメソッドを見て私につながる。明らかにBeginPaintを実行するbase.WndProc(ref msg)の後に私のペインティングメソッドが呼び出されました。上記の私のOnPaint()メソッドを移動すると、問題が修正されました。あなたのための

protected override void WndProc(ref Message m) 
     { 
      switch (m.Msg) 
      { 
       case WM_PAINT: 
        mBaseControl.Invalidate(); 
        OnPaint(); 
        base.WndProc(ref m); 
        break; 
       default: 
        base.WndProc(ref m); 
        break; 
      } 

     } 
+0

私の提案は 'PaintEventArgs'の' Graphics'オブジェクトだけを使うことでした。それは動作しませんか? – andlabs

+0

はい、それは動作します。私はBeginPaintを試しています。 –

+0

。 'BeginPaint()'について注意すべき重要な点は、更新矩形を検証することです。そのため、同じ 'WM_PAINT'呼び出しで2回呼び出すと、異なる更新矩形値が得られます。確かに、 'WM_PAINT'が生成されるかどうかを判断する更新矩形が存在するので、' BeginPaint() 'はWindowsに"大丈夫です、今は絵を描いているので、これ以上WM_PAINTを気にする必要はありません次に更新矩形が変更されたときに表示されます。 – andlabs

1

あなたがWndProcを通過し、コントロールがデフォルトの塗装を行うことができるようにする必要があります。塗装にはGraphicsオブジェクトを使用できます。例:

public partial class MyRichEdit : RichTextBox 
{ 
    public MyRichEdit() 
    { 
     InitializeComponent(); 
    } 

    protected override void WndProc(ref Message msg) 
    { 
     switch (msg.Msg) 
     { 
      case 15://WM_PAINT 
       base.WndProc(ref msg); 
       Graphics g = Graphics.FromHwnd(Handle); 
       Pen pen = new Pen(Color.Red); 
       g.DrawRectangle(pen, 0, 0, 10, 10); 
       return; 
     } 
     base.WndProc(ref msg); 
    } 
} 
+0

ありがとう、Barmak。私はGraphicsクラスを使ってテストを行いましたが、うまくいきましたが、私がBeginPaintメソッドでテストしたいときは、問題に遭遇しました。私はそのbase.WndProcが既にBeginPaintと呼ばれていたことを知らなかったので、前に私のOnPaintメソッドを呼び出すロジックを変更しなければなりませんでした。 –

関連する問題