在文本框后面绘制线条

本文关键字:绘制 文本 | 更新日期: 2023-09-27 18:08:04

我正在创建一个简单的笔记本应用程序。我被要求让输入区域看起来像一张笔记本纸,文本位于浅蓝色的线条上。我正在努力使这项工作,但它似乎是失败的悲惨。

到目前为止,我已经创建了一个透明的RichTextBox,它位于面板的顶部。文本框为:
using System;
using System.Windows.Forms;
public class TransparentTextBox : RichTextBox
{
    public TransparentTextBox()
    {
        this.SetStyle(ControlStyles.Opaque, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
    }
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams parms = base.CreateParams;
            parms.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
            return parms;
        }
    }
}

面板的油漆代码:

private void paper_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    g.Clear(Color.White);
    g.DrawLine(new Pen(Brushes.LightPink, 2), 20, 0, 20, paper.Height);
    int h = TextRenderer.MeasureText("Testj", txtBody.Font).Height;
    for (int x = 2 + h; x < paper.Height; x += h)
    {
        g.DrawLine(new Pen(Brushes.LightSkyBlue, 2), 0, x, paper.Width, x);
    }
}

这些行是静态的,它们会变长以适应所选择的任何字体大小/字体系列。问题是当文本框滚动时。线条不会随着文字移动。我已经尝试将滚动条的手柄链接到行,但它们似乎不能正确链接。

获取当前滚动位置的代码:[StructLayout (LayoutKind.Sequential)]

public struct SCROLLINFO
{
    public int cbSize;
    public uint fMask;
    public int nMin;
    public int nMax;
    public uint nPage;
    public int nPos;
    public int nTrackPos;
}
public enum ScrollBarDirection
{
    SB_HORZ = 0,
    SB_VERT = 1,
    SB_CTL = 2,
    SB_BOTH = 3
}
public enum ScrollInfoMask
{
    SIF_RANGE = 0x1,
    SIF_PAGE = 0x2,
    SIF_POS = 0x4,
    SIF_DISABLENOSCROLL = 0x8,
    SIF_TRACKPOS = 0x10,
    SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS
}
...

public partial class Form1 : Form
{
    [DllImport("User32.dll", EntryPoint = "GetScrollInfo")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetScrollInfo([In]IntPtr hwnd, [In]int fnBar, [In, Out]ref SCROLLINFO lpsi);
...
    private void txtBody_VScroll(object sender, EventArgs e)
    {
        inf.cbSize = Marshal.SizeOf(inf);
        inf.fMask = (int)ScrollInfoMask.SIF_ALL;
        GetScrollInfo(txtBody.Handle, 1, ref inf);
        Console.WriteLine(inf.nTrackPos + ":" + inf.nPos + ":" + TextRenderer.MeasureText("Testj", txtBody.Font).Height);
        paper.Invalidate();
    }    

然后将上面的油漆修改为:

for (int x = inf.nPos % h; x < paper.Height; x += h)
{
    g.DrawLine(new Pen(Brushes.LightSkyBlue, 2), 0, x, paper.Width, x);
}    

我也试过使用nTrackPos,但似乎都没有像我想要的那样跟随文本。我不太熟悉c#,所以我想知道我缺少什么/可以做得更好。我使用的是Visual Studio 2008,带有Visual c# 2008. net框架3.5 SP1

在文本框后面绘制线条

所以,这是我经过一番密集的谷歌搜索后得出的结果。我决定进一步研究Gusman对我的问题的评论,并再次研究在文本框上绘图。玩了一会儿之后,我意识到我计算起跑线位置的方法不正确。所以,我重新配置了我的自定义RichTextBox,看起来像:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Journal
{
    class CustomRichTextBox : RichTextBox
    {
        private const int WM_HSCROLL      = 0x114;
        private const int WM_VSCROLL      = 0x115;
        private const int WM_MOUSEWHEEL   = 0x20A;
        private const int WM_PAINT        = 0x00F;
        private const int EM_GETSCROLLPOS = 0x4DD;
        public int lineOffset = 0;
       [DllImport("user32.dll")]
        public static extern int SendMessage(
              IntPtr hWnd,
              int Msg,
              IntPtr wParam,
              ref Point lParam 
              );
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_PAINT)
            {
                using (Graphics g = base.CreateGraphics())
                {
                    Point p = new Point();
                    //get the position of the scrollbar to calculate the offset
                    SendMessage(this.Handle, EM_GETSCROLLPOS, IntPtr.Zero, ref p);
                    //draw the pink line on the side
                    g.DrawLine(new Pen(Brushes.LightPink, 2), 0, 0, 0, this.Height);
                    //determine how tall the text will be per line
                    int h = TextRenderer.MeasureText("Testj", this.Font).Height;
                    //calculate where the lines need to start
                    lineOffset = h - (p.Y % h);
                    //draw lines until there is no more box
                    for (int x = lineOffset; x < Height; x += h)
                    {
                        g.DrawLine(new Pen(Brushes.LightSkyBlue, 2), 0, x, Width, x);
                    }
                    //force the panel under us to draw itself.
                    Parent.Invalidate();
                }
            }
        }
        public CustomRichTextBox()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}

然后我将这个框设置在面板内以获得我想要的填充。面板被强制用文本框重新绘制。