Winforms在文本框上画线

mv1qrgav  于 2023-10-23  发布在  其他
关注(0)|答案(3)|浏览(145)

我有一个自定义文本的显示器,当用户自定义它时,我希望显示文本。其中一个可用的自定义是一个“x-out”,它应该在文本的所有5个字符上绘制一个大的“X”。因此,当复选框“X-Out”被选中时,它应该从以下内容更新文本:

对此:

该框本身是一个包含在Panel中的RichTextBox。我尝试在面板中使用Paint事件,但它将其绘制在RichTextBox下面(即角落上的小红线)。我还尝试使用自定义RichTextBox控件,如at this website。这段代码可以工作,但前提是我没有在RichTextBox中设置文本和颜色。如果我设置文本和颜色,然后选中复选框,则不会调用WndProc方法。如何使用Message.msg15触发WndProc方法?代码如下:

形式

public partial class ButtonDataForm : Form
{
  CustomRichTextBox button1;

  public ButtonDataForm()
  {
    InitializeComponent()
  }

  void OnFormLoad(object sender, EventArgs e)
  {
    cstmRichTextBox = new CustomRichTextBox(richTextBox1);
  }

  void OnXOutChecked()
  {
    cstmRichTextBox.IsChecked = xoutCheckbox.Checked;
    cstmRichTextBox.ParentTex.Refresh(); // This does not trigger the WndProc message on cstmRichTextBox
  }
}

自定义RichTextBox

public class CustomRichTextBox : NativeWindow
{
  public RichTextBox ParentTextBox { get; private set; }
  Graphics textBoxGraphics;
  public bool IsChecked { get; set; }

  public CustomRichTextBox(RichTextBox tb)
  {
    ParentTextBox = tb;
    textBoxGraphics = Graphics.FromHwnd(tb.Handle);
    AssignHandle(ParentTextBox.Handle);
  }

  protected override void WndProc(ref Message m}
  {
    switch(m.Msg)
    {
      case 15:
        parentTextBox.Invalidate();
        base.WndProc(ref m);
        DrawXOut();
        break;
      default:
        base.WndProc(ref m);
        break;
    }
  }

  void DrawXOut()
  {
    if (IsChecked)
    {
      Pen xpen = new Pen(ParentTextBox.ForeColor, 3);
      Point topLeft = ParentTextBox.Location;
      int x1 = topLeft.X + ParentTextBox.Width;
      int y1 = topLeft.Y + ParentTextBox.Height;
      Point topRight = new Point(x1, topLeft.Y);
      Point bottomLeft = new Point(topLeft.X, y1);
      Point bottomRight = new Point(x1, y1);
      textBoxGraphics.DrawLine(xpen, topLeft, bottomRight);
      textBoxGraphics.DrawLine(xpen, bottomLeft, topRight); 
    }
  }
}

编辑:

我尝试在底部面板上放置一个透明面板,并在Paint事件触发时在其中进行绘制。事件触发,但面板中没有显示任何内容。我算错位置了吗?

void OnXOutChecked()
{
  panel1.Refresh();
}

void OnPanel1Paint(object sender, PaintEventArgs e)
{
    Pen xpen = new Pen(Color.Red, 3);
    Point topLeft = panel1.Location;
    int x1 = topLeft.X + panel1.Width;
    int y1 = topLeft.Y + panel1.Height;
    Point topRight = new Point(x1, topLeft.Y);
    Point bottomLeft = new Point(topLeft.X, y1);
    Point bottomRight = new Point(x1, y1);
    e.Graphics.DrawLine(xpen, topLeft, bottomRight);
    e.Graphics.DrawLine(xpen, bottomLeft, topRight);
}

3htmauhk

3htmauhk1#

我只是稍微修改了一下你的CustomRichTextBox

public class CustomRichTextBox : RichTextBox
{
    private bool xOut;

    public bool XOut
    {
        get => xOut;
        set
        {
            xOut = value;
            Invalidate();
        }
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case 15:
                base.WndProc(ref m);
                if (xOut)
                    DrawXOut();
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    private void DrawXOut()
    {
        using var g = Graphics.FromHwnd(Handle);
        g.DrawLine(Pens.Red, 0, 0, Width, Height);
        g.DrawLine(Pens.Red, 0, Height, Width, 0);
    }

    protected override void OnHScroll(EventArgs e)
    {
        base.OnHScroll(e);
        Invalidate();
    }

    protected override void OnVScroll(EventArgs e)
    {
        base.OnVScroll(e);
        Invalidate();
    }
}

niwlg2el

niwlg2el2#

这是一种非常不可靠的方法,在控件之上绘制并期望它在所有可能的场景中工作(可能有很多!).
你可以在文本框的顶部放置一个透明的图片框,上面有一个带有两条红色交叉线的透明位图。

gkl3eglg

gkl3eglg3#

老实说,我觉得你不想这么做你滥用了文本框,这不是它的本意。我不知道你的真实意图,但也许一个删除线可能是一个有效的解决方案?
我的经验告诉我,最好按原样使用组件,不要对它们做太多更改。

实际答案

如果你真的想,你可以这样做:(根据尼克的回答)

public class MyTextbox : RichTextBox
    {
        PictureBox pictureBox = new PictureBox();
        public MyTextbox()
        {
            this.Controls.Add(pictureBox);
            pictureBox.Dock = DockStyle.Fill;
            pictureBox.BackColor = Color.Transparent;
            pictureBox.Paint += PictureBox_Paint;
            pictureBox.BringToFront();
        }

        private void PictureBox_Paint(object? sender, PaintEventArgs e)
        {
            var pen = new Pen(this.ForeColor);
            e.Graphics.DrawLine(pen, 0, 0, this.Width, this.Height);
            e.Graphics.DrawLine(pen, 0, this.Height, this.Width, 0);
        }
    }

相关问题