Click here to Skip to main content
15,912,977 members
Please Sign up or sign in to vote.
2.00/5 (1 vote)
See more:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using System.Drawing.Drawing2D;


namespace sampledrawline
{
    public partial class Form1 : Form
    {
        int x1 = 0;
        int y1 = 0;
        int Xto = 0;
        int Yto = 0;
        int YOffSet = 3;
        int hW = 0;
        int hH = 0;
        PictureBox pb = new PictureBox();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
            string filename = "XMLFile.xml";

            XmlDocument xd = new XmlDocument();
            xd.Load(filename);
            XmlNodeList xnl = xd.SelectSingleNode("root").ChildNodes;
            foreach (XmlNode xN in xnl)
            {
                XmlElement xElem = (XmlElement)xN;
                XmlNodeList c = xElem.GetElementsByTagName("c");
                XmlNodeList loc = xElem.GetElementsByTagName("loc");
                XmlNodeList Xto = xElem.GetElementsByTagName("Xto");
                XmlNodeList Yto = xElem.GetElementsByTagName("Yto");
		XmlNodeList x = xElem.GetElementsByTagName("x");
                XmlNodeList y = xElem.GetElementsByTagName("y");

                for (int i = 0; i < c.Count; i++)
                {
                    x1 = Convert.ToInt32(x[i].InnerText);
                    y1 = Convert.ToInt32(y[i].InnerText);
                    Xto = Convert.ToInt32(Xto[i].InnerText);
                    Yto = Convert.ToInt32(Yto[i].InnerText);

                    pb = new PictureBox();
                    pb.Location = new Point(x1, y1);
                    Image image = Image.FromFile(loc[i].InnerText);
                    pb.ImageLocation = loc[i].InnerText;
                    pb.Load(loc[i].InnerText);
                    pb.Height = 100;
                    pb.Width = 100;
                    pb.SizeMode = PictureBoxSizeMode.StretchImage;
                    hH = pb.Size.Height / 2;
                    hW = pb.Size.Width / 2;

                    panel1.Paint += new PaintEventHandler(panel1_Paint);
 		    panel1.Controls.Add(pb);
                                        
                }
            }
        }

        void panel1_Paint(object sender, PaintEventArgs e)
        {
            
            Graphics g = e.Graphics;
            Pen myPen = new Pen(System.Drawing.Color.Red, 5);
            g.DrawLine(myPen, pb.Location.X + hW, pb.Location.Y + hH, pb.Location.X + hW, pb.Location.Y - hH);
            g.DrawLine(myPen, pb.Location.X + hH, pb.Location.Y - hH, Xto + hH, Yto + hW);
            
        }  
    }
}


Hi! Above is the codes I have as of now. My problem is that the paint event is not making lines that will connect to all pictureboxes in a form. Help me. :)
Posted
Updated 5-Jan-11 16:23pm
v2

Without the test data, it's very difficult to test, but, it's probably because the lines are being drawn under the picture boxes, not on top of them.

Truthfully, I don't see why you need picture boxes at all. You can just load the bitmap images and paint them yourself in the Panel's paint event, along with the lines, and get much greater control over what gets painted, how, and in what order.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 6-Jan-11 0:03am    
Dave, this is not the first question, when somebody tried to make something like diagrams. Main elements are bitmaps; and connections are the lines connecting those elements. The key is that main elements are maybe fixed.

Personally, I agree with you (but in real life I would not event thin about Forms and did all in WPF, unless Linux support is required). This is a very bad design, not flexible at all. But what do you think about their level? I looks like they hope to do everything quickly without learning anything. To them, it seems easier to use the way they understand.

You know what? I'll vote 5 to support your idea. May be it will convince them.
Sergey Alexandrovich Kryukov 6-Jan-11 0:09am    
Oops! I just pay attention who is asking. Be careful. This is already a question #5 on the same topic from the same person. I'm already sorry I started answering. Anyway, all the advices are there; and they are useful.
Sergey Alexandrovich Kryukov 6-Jan-11 0:16am    
Frankly, whole idea of using any bitmaps at all for diagramming is bad -- they do not scale. When we worked with native code, we did all in vector graphics, later on, we used vector graphics with XAML (pre-created patterns translated to XAML from SVG) and had no problems.
yummy02 6-Jan-11 0:21am    
@SAKryukov: Actually you're right, lines are used as the connections to the pictureboxes. I was also thinking of doing it at WPF but lack of time to do so.
yummy02 6-Jan-11 0:25am    
One thing, I asked questions several times, not to fool anyone, but to further gain knowledge to those who knows and shares knowledge. :)
I cannot reproduce all you application (I don't have your data file, etc.).

First thing I can see with unarmed eye is the lack of invalidation.

Assuming your data is correct (lines are not out of bounds, not closed by other controls, etc.) your method of rendering should work, everything looks fine, except one thing: who said that WM_PAIN message (the only thing that fire your panel's Paint event) is sent at the moment our data used by panel1_Paint is set up?

Make one experiment: show your application the at the moment you expect your lines rendered. ALT+TAB your application away to be fully closed by some other window and activateit back. You may have two results:

#1. Lines appear => make sure you call panel1.Invalidate() after line data is ready -- it will fire Paint event. Later on, you may get better results calling panel1.Invalidate() with parameters to invalidate not full panel, but smaller region or rectangle.

#2. Lines did not appear => Set a breakpoint inside panel1_Paint and under debugger examine coordinate of each line, compare them with panel bounds, make sure lines are not hidden under some other controls, etc.



By the way, this

C#
panel1.Paint += new PaintEventHandler(panel1_Paint);


is a stone-age syntax used by Microsoft because they don't want to re-write code auto-generation (I would understand them).

Better manually write:

C#
panel1.Paint += (sender, eventArgs) => {
    Graphics g = eventArgs.Graphics;
    Pen myPen = new Pen(System.Drawing.Color.Red, 5);
    g.DrawLine(myPen, ...);
    g.DrawLine(myPen, ...);    
};


The code above is using lambda form not available in older C# versions. For C# v.2 a different syntax should be used:

C#
panel1.Paint += delegate(object sender, PaintEventArgs eventArgs) { /* ... */ };


The supportability of the code is greatly improved if you stop adding event handlers in design-time. In this case, this code (setting up of the event handler to anonymous method in lambda form) anywhere to be called before first Paint event, in practice before showing of the form. Good place to set up all event handlers for the form and its component is right after InitializeComponent(); (normally auto-generated in the form constructor).

There are many benefits: you don't have to write down exact profile with exact types of event arguments (type inference helps). You can place whole code of the handler right in the block (as it is shown above), but you can also make it a single call to a separate method, but now this separate method does not have to be of exact same profile as the delegate (for example, sender is rarely used, and event arguments parameter sometimes is not used), so the dead parameter are removed which simplified the code.

The code becomes more observable and controllable. You can place setting up of the handler (with += operator) and the body of handler together or close, or at your convenience. You can better isolate auto-generated code from your own (I usually create yet another separate file with with yet another declaration public partial class of the same form) -- many improvements.
 
Share this answer
 
v3
Comments
Sergey Alexandrovich Kryukov 5-Jan-11 23:54pm    
Is is diagramming application? No matter, what you do is much better to do with WPF. Did you think about it?
yummy02 6-Jan-11 0:31am    
@SAKryukov: Thanks for this one. I have a lot about using Invalidate. But actually, to be honest with you, I did not understand the last code that you'd posted. It's something to do with "panel1.Paint += (sender, eventArgs) => {". I didn't understand that maybe because I haven't use it in anyways. Where should I put that code? Thanks for the help. I appreciated it a lot even though sometimes, you ruin my day with our comments. :)
yummy02 6-Jan-11 0:32am    
I haven't tried WPF. I will search for it first.
Sergey Alexandrovich Kryukov 6-Jan-11 0:48am    
Ok, I'll add some clarification. This style is really beneficial.
Sergey Alexandrovich Kryukov 6-Jan-11 0:49am    
@yummy02: you should put this code anywhere to be called before first Paint event

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900