C# 使用 TextBox 绘制线条

C# Drawing Lines with TextBox

我有一个可以在屏幕上添加文本框并移动它的应用程序。 当我添加两个以上的文本框时,我双击两个文本框的顶部,一条线将两者连接起来。

我的问题是:如何让线条随着文本框一起移动? 代码如下:

public partial class principal : Form
{
    int posMouseFormX, posMouseFormY;
    int posMouseTXT_X, posMouseTXT_Y;
    int posActTXT_X, posActTXT_Y;
    bool txtPressionado = false;
    int qntClick;
    Pen myPen = new Pen(System.Drawing.Color.DarkGreen, 1);
    Graphics Tela;
    List<TextBox> listaNós = new List<TextBox>();
    List<Point> origem = new List<Point>();
    List<Point> destino = new List<Point>();
    Point ponto1, ponto2;
    ContextMenuStrip menu;

    public principal()
    {
        InitializeComponent();
        menu = new ContextMenuStrip();
        menu.Items.Add("Remover");
        menu.ItemClicked += new ToolStripItemClickedEventHandler(contextMenuStrip1_ItemClicked);
    }

    //TextBox event when the mouse moves over the TXT
    private void txtMover_MouseMove(object sender, MouseEventArgs e)
    {
        TextBox textBox = sender as TextBox;

        posMouseFormX = textBox.Location.X + e.Location.X;
        posMouseFormY = textBox.Location.Y + e.Location.Y;

        if (txtPressionado == true) moverTxt(textBox);
    }

    //Retrieve the X and Y coordinates where clicked within the component. 
    private void txtMover_MouseDown(object sender, MouseEventArgs e)
    {
        posMouseTXT_X = e.Location.X;
        posMouseTXT_Y = e.Location.Y;
        txtPressionado = true;
    }

    private void txtMover_MouseUp(object sender, MouseEventArgs e)
    {
        txtPressionado = false;
    }

    private void moverTxt(TextBox a)
    {
        a.Location = new System.Drawing.Point(posMouseFormX - posMouseTXT_X, posMouseFormY - posMouseTXT_Y);
        posActTXT_X = a.Location.X;
        posActTXT_Y = a.Location.Y;

        System.Drawing.Graphics graphicsObj;
        graphicsObj = this.CreateGraphics();
    }

    //insert new TextBox
    private void sb_Inserir_No_Click(object sender, EventArgs e)
    {

        TextBox noFilho = new TextBox();

        noFilho = new System.Windows.Forms.TextBox();
        noFilho.Location = new System.Drawing.Point(379, 284);
        noFilho.Size = new System.Drawing.Size(100, 30);
        noFilho.TabIndex = 20;
        noFilho.Text = "";
        noFilho.BackColor = Color.White;

        posActTXT_X = noFilho.Location.X;
        posActTXT_Y = noFilho.Location.Y;

        this.Controls.Add(noFilho);
        noFilho.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
        noFilho.DoubleClick += new System.EventHandler(this.textBox1_Click);
        noFilho.MouseUp += new System.Windows.Forms.MouseEventHandler(txtMover_MouseUp);
        noFilho.MouseDown += new System.Windows.Forms.MouseEventHandler(txtMover_MouseDown);
        noFilho.MouseMove += new System.Windows.Forms.MouseEventHandler(txtMover_MouseMove);
        noFilho.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox1_KeyDown);

        noFilho.ContextMenuStrip = menu;   
    }

    //event to resize the txt on the screen as the content.
    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        TextBox textBox1 = sender as TextBox;
        Size size = TextRenderer.MeasureText(textBox1.Text, textBox1.Font);
        textBox1.Width = size.Width + 10;
        textBox1.Height = size.Height;
    }

    //Event to control the connection between two give us when double click on the textbox
    private void textBox1_Click(object sender, EventArgs e)
    {
        TextBox textBox1 = sender as TextBox;
        int meio = textBox1.Size.Width / 2;
        Tela = CreateGraphics();

        qntClick = qntClick + 1;

        if (this.qntClick == 1)
        {
            origem.Add(ponto1);
            ponto1 = new Point(textBox1.Location.X + meio, textBox1.Location.Y);
        }
        if (this.qntClick == 2)
        {
            qntClick = 0;
            destino.Add(ponto2);
            ponto2 = new Point(textBox1.Location.X + meio, textBox1.Location.Y);
            DesenhaSeta(Tela, ponto1, ponto2);
        }
    }

    //draw arrow between two TXT
    void DesenhaSeta(Graphics Tela, Point x, Point y)
    {
        myPen.StartCap = LineCap.Triangle;
        myPen.EndCap = LineCap.ArrowAnchor;
        Tela.DrawLine(myPen, x, y);
    }

    private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
        ContextMenuStrip menu = sender as ContextMenuStrip;
        //recuperando o controle associado com o contextmenu
        Control sourceControl = menu.SourceControl;

        DialogResult result = MessageBox.Show("Tem Certeza que deseja remover o nó selecionado?", "Excluir", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

        if(result == DialogResult.Yes)
        {
            sourceControl.Dispose();
        }
    }

    private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
        // Determine whether the key entered is the F1 key. Display help if it is.
        if (e.KeyCode == Keys.Space)
        {
            TextBox textBox1 = sender as TextBox;
            novoNó tela = new novoNó(textBox1.Text);
            tela.Show();
        }
    }
}

包含的每个控件 TextBox 都有一个 Move 事件。在那里打一个 Invalidate() 电话!

线条应该在容纳 TextBoxes 的容器的 Paint 事件中绘制,可能是 Form;如果是 Form 确实调用 this.Invalidate().

请将画线代码从DoubleClick事件中移到Paint事件中,否则线条将不会持续存在,比如minimize/maximize事件或其他情况,当系统必须重新绘制应用程序!

您可能需要创建一个数据结构来维护有关需要连接哪些 TextBox 对的信息,可能是 List<Tuple>List<someStructure>。这将在 DoubleClick 事件中得到 filled/modified,然后调用 this.Invalidate() 并且在 Form.Paint 中你有一个 foreach 循环遍历 TextBox 的列表-对..

如果您在 Form 上绘图,请确保打开 DoubleBuffered

更新:为了比较结果,这里是一个最小的例子,它期望 Form 上有两个 TextBoxes

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
        this.DoubleBuffered = true;
        pairs.Add(new Tuple<Control, Control>(textBox1, textBox2));
    }

    List<Tuple<Control, Control>> pairs = new List<Tuple<Control, Control>>();
    Point mDown = Point.Empty;

    private void Form2_Paint(object sender, PaintEventArgs e)
    {
        foreach (Tuple<Control, Control> cc in pairs)
            drawConnection(e.Graphics, cc.Item1, cc.Item2);
    }

    void drawConnection(Graphics G, Control c1, Control c2)
    {
        using (Pen pen = new Pen(Color.DeepSkyBlue, 3f) )
        {
            Point p1 = new Point(c1.Left + c1.Width / 2, c1.Top + c1.Height / 4);
            Point p2 = new Point(c2.Left + c2.Width / 2, c2.Top + c2.Height / 4);
            G.DrawLine(pen, p1, p2);
        }
    }

    void DragBox_MouseDown(object sender, MouseEventArgs e)
    {
        mDown = e.Location;
    }

    void DragBox_MouseMove(object sender, MouseEventArgs e)
    {
        TextBox tb = sender as TextBox;
        if (e.Button == MouseButtons.Left)
        {
            tb.Location = new Point(e.X + tb.Left - mDown.X, e.Y + tb.Top - mDown.Y);
        }
    }

    void DragBox_MouseUp(object sender, MouseEventArgs e)
    {
        mDown = Point.Empty;
    }

    private void DragBox_Move(object sender, EventArgs e)
    {
        this.Invalidate();
    }

}