简体   繁体   中英

C# Drawing Lines with TextBox

I have an application where I can add a textBox on the screen and move it. When I add more than two textBox, I double-click on top of two textbox and a line connects both.

My question is: How to make the line move along with the textBox? code below:

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();
        }
    }
}

Each control, TextBox included has a Move , event. Put an Invalidate() call there!

The lines should be drawn in the Paint event of the container that holds the TextBoxes , probably the Form ; if it is the Form indeed call this.Invalidate() .

Please move the line drawing code out of the DoubleClick event into the Paint event or else the lines will not persist, say minimize/maximize events or other situation, when the system has to redraw the application!

You probably will need to create a data structure to maintain information about which TextBox -pairs need to be connected, maybe a List<Tuple> or a List<someStructure> . This would get filled/modified in the DoubleClick event, then call this.Invalidate() and in the Form.Paint you have a foreach loop over the list of TextBox -pairs..

If you are drawing on the Form do make sure to turn DoubleBuffered on!

Update: To compare the reults here is a minimal example the expects two TextBoxes on a Form :

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();
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM