-1

So here is code i have in my Form class:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 private void Form1_Load(object sender, EventArgs e)
        {
            BstTree tree = new BstTree();
            tree.addRoot(50);
            for (int i = 1; i < 50; i++)
            {
                int b = rnd.Next(1, 100);
                listBox1.Items.Add(b);
                tree.AddNode(tree.root, b);
            }
            tree.treeOutput(tree.root, this);
        }
        public void draw(Point prevPT, Point currentPT)
        {
            Graphics p = CreateGraphics();
            Pen pen = new Pen(Color.Red, 5);
            p.DrawLine(pen, prevPT, currentPT);
        }
    }

And i have BstTree class and i call the draw method from there:

public Class BstTree
{
public void treeOutput(Node root, Form1 f)
        {
                Label node = new Label();
                node.AutoSize = true;
                node.Text = root.value.ToString();
                node.Location = pt;
                root.ancPT = pt;
                f.Controls.Add(node);
                f.draw(root.ancestor.ancPT, pt);
        }
}

but it doesnt draw anything, have no idea how to solve this...

WhiteRaven
  • 13
  • 3
  • 1
    Where are you calling the `treeOutput` method? Show the relevant code please (and your debugging efforts) – UnholySheep Nov 15 '17 at 15:01
  • Please provide testable code that reproduces the issue. There's too much missing here. What's `pt`? What's `Node`? I suspect those parts can simply be omitted and still reproduce the issue. – 15ee8f99-57ff-4f92-890c-b56153 Nov 15 '17 at 15:03
  • Well, to speak about debugging can say that draw method manages properly and gets all correct input parameters – WhiteRaven Nov 15 '17 at 15:04
  • 2
    You draw it before form is shown. See [order of events](https://stackoverflow.com/q/3070163/1997232) (namely `Load` event). Another thing is what this kind of drawing only persist until next `Paint` event. – Sinatr Nov 15 '17 at 15:05
  • I made it in form shown event and when i run the form i can see the lines drawn for a milisecond and then they dissapear) – WhiteRaven Nov 15 '17 at 15:08
  • 2
    Instead of `draw` method [override OnPaint](https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/overriding-the-onpaint-method) in `Form1`. The parameters should become properties, call `Invalidate()` if you change them to force redraw. – Sinatr Nov 15 '17 at 15:13
  • 2
    CreateGraphics is always a no no. In your case, it *really* doesn't work because the form isn't visible yet in the load event. Nothing to draw on. – LarsTech Nov 15 '17 at 15:14
  • How to call it then from BstTree Class then if i use override OnPaint? – WhiteRaven Nov 15 '17 at 15:14
  • Do you call `draw` multiple times with different parameters? Make a list (e.g. `List>`) to remember points and go through it in `OnPaint` to redraw all lines. – Sinatr Nov 15 '17 at 15:16
  • You are drawing into a `Graphics` object which is not tied to any `Control` or `Form`, i.e. you are only drawing in memory. Therefore you never see any result. You really must draw in a Paint event of the TreeView. See: [TreeView.DrawNode Event](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.treeview.drawnode?view=netframework-4.7.1). – Olivier Jacot-Descombes Nov 15 '17 at 15:33
  • @OlivierJacot-Descombes I don't believe that is correct. Looks to me like it would be a graphics object created via `this.CreateGraphics()`, which should be what ever is passed into `treeOutput(Node root, Form1 f)` as the `Form1` reference. Problem is that it might be drawing to the form, which might be under some other control in the z-order, thus obscuring the result? – DonBoitnott Nov 15 '17 at 15:49
  • You are right. The Graphics object belongs to the form. The problem probably is, that the regular Paint event paints over this one. – Olivier Jacot-Descombes Nov 15 '17 at 18:15

1 Answers1

1

Drawing in a bitmap is static and you can do so by using your own Graphics object; however, drawing in WinForms is very dynamic, as the drawing is very ephemeral. Minimizing a form, resizing a form, moving a form partly out of the visible screen area or opening another application on top of your form can destroy the drawn things. Therefore the Windows operating system implements a clever drawing mechanism by sending messages to the applications whenever a form, a control or parts of those must be redrawn. This raises paint events in the applications and means that the OS determines when things must be drawn (or redrawn). Therefore, your drawing routines must occur inside paint event handlers.

If you want to draw the tree nodes yourself, create your own tree control by deriving it from TreeView and change the DrawMode accordingly.

public class MyTreeView : TreeView
{
    public MyTreeView()
    {
        DrawMode = TreeViewDrawMode.OwnerDrawAll;
    }

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        if (e.Node.IsVisible) {
            // Draw background of node.
            if (e.Node == e.Node.TreeView.SelectedNode) {
                e.Graphics.FillRectangle(Brushes.LightBlue, e.Bounds);
            } else {
                e.Graphics.FillRectangle(Brushes.White, e.Bounds);
            }
            using (Pen p = new Pen(Color.Red, 5))
            {
                // TODO: Implement your drawing logic here
            }
            e.Graphics.DrawString(e.Node.Text, this.Font, Brushes.Black,
                                  e.Bounds.Left + delta, e.Bounds.Top + 1);
        }
    }
}

This is only a raw sketch. You might have to consider other details like e.Node.IsExpanded and e.State.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188