Question

I have a panel divided into 10 equal rows. Then I have markers (squares with the height == height of a row) which I want to be able to drag up and down, but a markers need to be exactly fitting into a row. A marker cannot be dragged in a position where it has a half in row 1 and the other half in row 2. Therefore the dragging must be in certain specific vertical positions. I need to drag only vertically. Then I need to assign the row were the markers has been moved to as a property of the object. E.g. if marker has been placed in row 5 then the rank of that object is to be assigned to 5. This is what i've done so far, I am able to drag each marker vertically, the problem is that they can be ragged outside the parent container and that I can't make them move only into the desired y Location. Any ideas or explanation of how I can achieve this... please feel free to ask if my question is not so clear.. Thank You.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace MouseDragTest
{
    class Marker : PictureBox
    {
        public Label lb1 = new Label();
        public Label lb2 = new Label();
        bool isDragging = false;
        int rank;

        //-------Constructor----------
        public Marker(int xLoc, int yLoc)
        {
            Location = new Point(xLoc, yLoc);
            this.Size = new Size(20, 20);
            this.BackColor = Color.Blue;
            this.BringToFront();

        //-------Mouse Event Handlers--------
            this.MouseDown += new MouseEventHandler(StartDrag);
            this.MouseUp += new MouseEventHandler(StopDrag);
            this.MouseMove += new MouseEventHandler(OnDrag);
        }

        //-------Mouse Event Handlers Implementation---------
        private void StartDrag(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isDragging = true;
                rank = (this.Top + e.Y);
            }
        }

        private void StopDrag(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isDragging = false;
                rank = this.Top + e.Y;                
                lb1.Text = rank.ToString(); //Info on blue square
                lb2.Text = rank.ToString(); //Info on red square
            }
        }

        private void OnDrag(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                this.Top = this.Top + e.Y; //move vertically;
            }
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
           base.OnPaint(pe);
        }
    }
  }

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MouseDragTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Pen p = new Pen(Color.Black, 1);

            int yLoc = 20;
            for (int i = 0; i < 10; i++)
            {
                g.DrawLine(p, 0, yLoc, this.Width, yLoc);yLoc += 20;
            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Marker mk1 = new Marker(0, 0);
            panel1.Controls.Add(mk1);
            /*For testing*/  mk1.lb1 = label1;

            Marker mk2 = new Marker(20,0);
            panel1.Controls.Add(mk2);
            /*For testing*/ mk2.lb2 = label2;
            mk2.BackColor = Color.Red;
        }
    }
}
Was it helpful?

Solution

In the 'OnDrag' event you need to check the current Y co-ordinate is within your bounds, and then perform an update to the Top value only if the values are in the desired range.

In the StopDrag event, you will need to calculate the correct position for an item in this rank, and set the 'Top' value of the object to the required value to make it 'snap' to the right position.

The issue that I can see is that the events doing the handling of the drag and drop are inside your Marker class and not aware of the global environment, thus stopping you writing code such as 'if (this.Y < lowerY || this.Y > upperY) then do nothing. There are a number of solutions to this: move the drag event handlers onto the parent container so they are aware of the data required, make the parent container have some form of globally visible properties which are visible from within the scope of one of the markers, or possibly add a property to each marker that allows them to be aware of their parent 'container'.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top