0

I try to simulate trains movement in my application ,so i create trains map using this code :

 public void DrawMap()
        {
            Bitmap map = new Bitmap(pictureBoxMetroMap.Size.Width, pictureBoxMetroMap.Size.Height);
            var graph = Graphics.FromImage(map);
            List<Point> lstPointLeft = new List<Point>();
            foreach (var t in lstSensorLeft)
            {
                Point objPoint = new Point(t.XLocation, t.YLocation);
                lstPointLeft.Add(objPoint);
                Rectangle rectSens = new Rectangle(t.XLocation, t.YLocation, 3, 3);
                try
                {
                    graph.FillRectangle(whiteBrush, rectSens);
                }
                catch (Exception ea)
                {

                }
                if (t.StationId != null)
                {
                    Rectangle rectEhsansq = new Rectangle(t.XLocation - 6, t.YLocation - 6, 12, 12);
                    graph.FillRectangle(blueBrush, rectEhsansq);
                    Label ObjLable = new Label();
                    ObjLable.ForeColor = Color.Transparent;
                    ObjLable.Location = new Point(t.XLocation+40, t.YLocation +50);
                    ObjLable.Text = ObjStationRepository.FindBy(i => i.Id == t.StationId).First().Name;
                    ObjLable.BackColor = Color.Transparent;
                    ObjLable.Width = 70;
                    pictureBoxMetroMap.Controls.Add(ObjLable);

                }
            }

            List<Point> lstPointRight = new List<Point>();

            foreach (var t in lstSensorRight)
            {
                Point objPoint = new Point(t.XLocation + 30, t.YLocation + 30);
                lstPointRight.Add(objPoint);
                Rectangle rectSens = new Rectangle(t.XLocation + 30, t.YLocation + 30, 3, 3);
                graph.FillRectangle(whiteBrush, rectSens);
                if (t.StationId != null)
                {
                    Rectangle rectPosition = new Rectangle(t.XLocation + 24, t.YLocation + 24, 12, 12);
                    graph.FillRectangle(blueBrush, rectPosition);

                    Label ObjLable = new Label();
                    ObjLable.ForeColor = Color.Transparent;
                    ObjLable.Location = new Point(t.XLocation - 50, t.YLocation - 30);
                    ObjLable.Text = ObjStationRepository.FindBy(i => i.Id == t.StationId).First().Name;
                    ObjLable.BackColor = Color.Transparent;
                    ObjLable.Width = 70;
                    pictureBoxMetroMap.Controls.Add(ObjLable);

                }
            }

            graph.DrawLines(pLine, lstPointLeft.ToArray());
            graph.DrawLines(pLine, lstPointRight.ToArray());
            pictureBoxMetroMap.Image = map;

           // ShowOnlineTrain();
            //Thread newThread = new Thread(new ThreadStart(ShowOnlineTrain));

            //newThread.Start();

        }

So as you can see the DramMap draws my trains map ,i call this function in page_load of my application as you can see here :

private void frmMain_Load(object sender, EventArgs e)
    {
        UpdateListBox = new UpdateListBoxDelegate(this.UpdateStatus);
        // Initialise and start worker thread
        workerThread = new Thread(new ThreadStart(this.ShowOnlineTrain));
        workerThread.Start();
        DrawMap();
    }

So as you can see above i call my function and i create a thread in my pageload, so the thread do a vital operation ,it calls a function ShowOnlineTrain ,this function fetch the locations of online trains and i should show these trains on my map :

List<OnlineTrain> OnlineTrainList = new List<OnlineTrain>();
        public void ShowOnlineTrain()
        {

            OnlineTrainRepository objOnlineTrainRepository = new OnlineTrainRepository();


           while(true)
            {
                OnlineTrainList = objOnlineTrainRepository.GetAll().ToList();

                    Invoke(UpdateListBox);

            }



           }
  private void UpdateStatus()
        {
            lstLog.Items.Add("Train Id=" + OnlineTrainList.First().TrainId + " | Current x position=" + OnlineTrainList.First().XTrainLocation + " | Current y position=" + OnlineTrainList.First().YTrainLocation);

        }

This function fetches the location of online trains .so OnlineTrainList ** has the locations of online trains (i.e x and y and trainId).so i have to show the trains on my map .I call the **Paint event of my picturebox :

  private void pictureBoxMetroMap_Paint(object sender, PaintEventArgs e)
        {
            if (OnlineTrainList.Count > 0)
            {
                foreach (OnlineTrain t in OnlineTrainList)
                {
                    var g = pictureBoxMetroMap.CreateGraphics();
                    Rectangle rectTrainState = new Rectangle(t.XTrainLocation.Value - 3,
                                                             t.YTrainLocation.Value - 3,
                                                             7, 7);
                    g.FillRectangle(RedBrush, rectTrainState);
                }

            }
        }

It gets all positions of **OnlineTrainList ** and draws them ,but i have a big problem here ,i need to show the movement of my train ,i should clear the old location of my train ,but i don't know how can i do that??? and all positions of my trains is drawn on my picturebox !!any idea ?

Best regards

leppie
  • 115,091
  • 17
  • 196
  • 297
Ehsan Akbar
  • 6,977
  • 19
  • 96
  • 180

2 Answers2

1

If you have assigned an image to the PictureBox using pictureBoxMetroMap.Image =, then you should be able to draw onto the PictureBox surface without disturbing that image.

Now, if you are then drawing additional "map" graphics manually, then you must continue to do so on every Paint cycle. Meaning that Paint must handle redrawing the "map" detail, as well as refreshing the train graphics to simulate movement.

Make sure that the code responsible for recognize or recording train movement data is calling pictureBoxMetroMap.Invalidate(); to trigger Paint calls.

DonBoitnott
  • 10,787
  • 6
  • 49
  • 68
1

What if you create 2 same sized PictureBoxes: another one for the map and another over it for the trains, using transparency on the top one. Since they are the same size, the locations match, too: https://stackoverflow.com/a/9158849/2538037

When the form has loaded, you start a BackgroundWorker, which updates trains and locations to the top PictureBox via ProgressChanged-event. You could use it to draw the image and then set it to the top PictureBox. You could use some timing on it, so it would calculate a new updated train-image like every 2 seconds. You should also use Dispose() to the old image after changing in the new one. Remember to use Invalidate() so the PictureBoxes are updated.

Community
  • 1
  • 1
W0lfw00ds
  • 2,018
  • 14
  • 23
  • I want to try your method ,but how can i the map two pictureboxs? – Ehsan Akbar Jun 03 '14 at 05:56
  • I think it works, but you wanted to clear the trains on the map, therefore you need to separate the trains and map image. I provided the link above about how to use those 2 pictureboxes. Use the designer to drop another `PictureBox` over the old one, and check that the sizes match. – W0lfw00ds Jun 03 '14 at 05:58
  • It works great ,but in background image i had some labels ,when i put the train picturebox on it ,they disappear!!!why ?You can see my labels in DrawMap function – Ehsan Akbar Jun 03 '14 at 06:14
  • Try adding the labels to the new upper PictureBox instead. – W0lfw00ds Jun 03 '14 at 06:35