在文本框C#后面画线

时间:2014-06-10 18:12:12

标签: c# drawing richtextbox

我正致力于创建一个简单的笔记本应用程序。我被要求让输入区看起来像一张笔记本纸,文字坐在浅蓝色的线条上。我试图让这项工作,但它似乎失败了。

到目前为止,我已经创建了一个位于面板顶部的透明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 framework 3.5 SP1

1 个答案:

答案 0 :(得分:0)

所以,这是我在一些密集的谷歌搜索后想出来的。我决定更多地关注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);
        }

    }
}

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