0

I'm trying to draw a binary tree - tree representation of it and I'm failing to do so.

I've tried drawing with GDI on Image bound to PictureBox, but eventually my Image is getting way too big and I can't resize it, then I did take Panel and I tried to draw on it directly - it works much better, but:

I start at the top middle of my control and draw it down, unfortunately at some point my drawings goes on -x and x bigger than width of my control (Panel to remind) and first of all, the drawings on the left do not appear to be drawn (I assume it's because they go out-of-bounds of the Panel), second thing, despite my Panel is having AutoSize property set to True, it does not get resized.

I'll appreciate any idea of how I should implement it to be drawn.

pzaj
  • 1,062
  • 1
  • 17
  • 37
  • 1
    You need to be be able to scroll the image when it is too big to fit to the area on the form or do You want to resize it? – Antonín Lejsek Nov 26 '15 at 15:05
  • 1
    Note the overdrawing alone does not cause a Control to resize. You need to set the Size yourself! - You can change the sizes of both a Panel or a PictureBox at any time. - 2) whichever way you do it, you ought to __first find out the size__ you need! Then you can draw it into a Bitmap (recommended), Assign this to a PB's Image and set the PB.SizeMode=Autosize. Finally put the PB into a Panel with AutoScroll = true: Done. – TaW Nov 26 '15 at 16:31
  • @AntonínLejsek the control I'm building has Dock property set to Fill and it's contained within a SplitContainer, therefore it should be scrolled. But it doesn't really, matter, I can handle that myself. I would rather focus on drawing the diagram itself. Can I draw, using GDI+, "virtually" and then copy/clip/whatever what has been drawn onto the control??? – pzaj Nov 26 '15 at 18:18
  • @user1970395 how many nodes do you need? I just tried adding 10000 nodes to my [Nodes Editor Sample](http://stackoverflow.com/a/15580293/643085) and, while it takes a while to load, usage performance is acceptable. – Federico Berasategui Nov 27 '15 at 14:52
  • @HighCore I need a range from 1 0000 to 1 000 000 to be honest ;p I thought of drawing only those "visible" and holding all of them within some sort of a structure, quite similar to the binary tree, but holding points with several properties. What I really need now is how to make sure it doesn't go off the boundaries to the left (< 0). – pzaj Nov 27 '15 at 17:57
  • @user1970395 if you're open to use WPF instead of winforms, [this](http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx) seems to work very well with 1 million items. You could combine that with my example linked above to achieve what you need. – Federico Berasategui Nov 27 '15 at 18:11

1 Answers1

0

I think @TaW already said that, unfortunately not as an answer. Panel would handle the scrolling and PictureBox would contain the image.

  • You need Panel with AutoScroll set to True
  • You need PictureBox inside this panel with SizeMode set to AutoSize
  • You do all drawing to Bitmap. When finished, assing this bitmap to PictureBox

example of drawing:

Bitmap bmp = new Bitmap(1000, 1000);
using (Graphics g = Graphics.FromImage(bmp))
{
    g.FillRectangle(Brushes.Green, 0, 0, 10, 10);
    g.DrawEllipse(Pens.Black, 10, 10, 900, 900);
}

pictureBox1.Image = bmp;

EDIT

So the problem is the size. You can choose to rasterize only the part that is visible. There can be problem with speed, but memory footprint would be minimal. Simple proof of concept:

System.Windows.Forms.TableLayoutPanel tableLayoutPanel1 = null;

private void Form1_Load(object sender, EventArgs e)
{
    this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
    // 
    // tableLayoutPanel1
    // 
    this.tableLayoutPanel1.AutoScroll = true;
    this.tableLayoutPanel1.ColumnCount = 1;
    this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 2000));
    this.tableLayoutPanel1.Location = new System.Drawing.Point(25, 25);
    this.tableLayoutPanel1.Name = "tableLayoutPanel1";
    this.tableLayoutPanel1.RowCount = 1;
    this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1000));
    this.tableLayoutPanel1.Size = new System.Drawing.Size(this.Width - 50, this.Height - 80);
    this.tableLayoutPanel1.TabIndex = 21;
    this.tableLayoutPanel1.Paint += new System.Windows.Forms.PaintEventHandler(this.tableLayoutPanel1_Paint);
    this.tableLayoutPanel1.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
    this.Controls.Add(this.tableLayoutPanel1);
    this.tableLayoutPanel1.BringToFront();
}

private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
{
    float virtualWidth = tableLayoutPanel1.ColumnStyles[0].Width;
    if (virtualWidth < 40000) //You can resize the area any time
    {
        tableLayoutPanel1.ColumnStyles[0].Width = 40000;
        tableLayoutPanel1.RowStyles[0].Height = 20000;
        tableLayoutPanel1.Invalidate();
        return;
    }

    e.Graphics.TranslateTransform(
        virtualWidth / 2 - tableLayoutPanel1.HorizontalScroll.Value,
        -tableLayoutPanel1.VerticalScroll.Value);

    int size = 50;
    for (int i = 0; i < 200; ++i)
    {
        for (int j = -i; j <= i; j++)
        {
            e.Graphics.DrawEllipse(Pens.Black, j * size * 2, i * size * 2, size, size);
        }
    }
}

I chose tableLayoutPanel1 with one row and one column, it does the scrolling and let me set the working area. tableLayoutPanel1 can be made in designer, I decided to construct it dynamically only to show fully working example (only Form1_Load event has to be assigned). You can speed this up by skipping parts that can not be visible, like lower and upper range of "i" variable. You can also rasterize bigger portion into bitmap and copy from that bitmap while You are within its bounds.

Antonín Lejsek
  • 6,003
  • 2
  • 16
  • 18
  • picture box is not good because I need this to be large, .NET can't create such a big bitmap for me ~(20000 x 20000). That's why I need to draw on something else. Also it doesn't solve the problem, as my drawing goes on -x position and it's not included in a bitmap anyway. I need to do it virtually somehow to get bitmap/image/whatever having bounds sized to the content and then copy it to a Control. – pzaj Nov 26 '15 at 19:57