0
votes

i have taken one Flow layout panel and placed multiple picture box inside in it. now i want when i will place my mouse at the right or left most edge of the Flow layout panel then rest of picture will scroll out. just think about windows 8 start screen where many tiles appear in screen and when we place mouse at right most edge on the screen then rest of the tiles scroll out. i want to simulate same thing in windows form with Flow layout panel.

i want my Flow layout panel will not show scroll bar but images will scroll out when i will place mouse right or left most part on the panel. here is my screen shot enter image description here

some one told me to do it this way...here is bit code Set AutoScrollPosition property in MouseMove event of Panel.

private void panel1_MouseMove(object sender, MouseEventArgs e)
{
    panel1.AutoScrollPosition = new Point(e.X, e.Y);
}

but this trick was not good. AutoScrollPosition works when scroll bar is visible but in my case i do not want to show scroll bar with Flow layout panel. i want smooth scrolling images from left to right or right to left. anyone can help me to achieve what i am trying to do....if possible guide me with respect of coding. thanks

EDIT

Here i am giving my full code after modification following @Taw suggestion but it is not working fine....rather flickering found when picture move. anyway here is the full code.

namespace ScrollTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            flowLayoutPanel1.MouseMove += MouseScroll;

            foreach (Control x in this.Controls)
            {
                if (x is PictureBox)
                {
                    ((PictureBox)x).MouseMove += MouseScroll;         
                }
            }
        }

        int near = 33;
        private void MouseScroll(object sender, MouseEventArgs e)
        {
            Point mouse = flowLayoutPanel1.PointToClient(MousePosition);
            Rectangle C = flowLayoutPanel1.ClientRectangle;

            int dLeft = mouse.X - C.Left;
            int dTop = mouse.Y - C.Top;
            int dRight = C.Right - mouse.X;
            int dBottom = C.Bottom - mouse.Y;

            int dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
            int dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;

            if (dX != 0 | dY != 0) scrollFLP(dX, dY);
        }

        void scrollFLP(int deltaX, int deltaY)
        {
            flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
            flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
            System.Threading.Thread.Sleep(11);
        }

        int getSpeedFromDistance(int delta)
        {
            int sig = Math.Sign(delta);
            int d = Math.Abs(delta);
            if (d > near / 2) return sig;
            else if (d > near / 3) return near / 10 * sig;
            else if (d > near / 4) return near / 8 * sig;
            else if (d > near / 5) return near / 5 * sig;
            else return near * sig;
        }
    }
}

basically i am trying achieve something like suppose i have flow layout panel and which has many picture box inside it with many images as the screen shot but scroll bar should not show rather scroll will happen automatically when i will place my mouse at the top or bottom of the flow layout panel like carousel.

see this picture of your application enter image description here

when place my mouse at the right end then it scroll and form background shown which i do not want. i want picture box will scroll & scroll upto last one not more than that.

any idea how to do it. thanks

2nd Edit

enter image description here

this code i added as per your suggestion

public Form1()
            {
                InitializeComponent();

                for (int i = 0; i < 666; i++)
                {
                    PictureBox pan = new PictureBox();
                    //pan.MouseMove += MouseScroll;
                    //pan.MouseLeave += outSideCheck;
                    pan.Size = new Size(75, 75);
                    pan.BackColor = Color.FromArgb(255, (i * 2) & 255, (i * 7) & 255, (i * 4) & 255);
                    flowLayoutPanel1.Controls.Add(pan);

                }
                //flowLayoutPanel1.MouseMove += MouseScroll;
                //this.flowLayoutPanel1.MouseLeave += outSideCheck;

                mouseScroller MSC = new mouseScroller();
                MSC.registerControl(flowLayoutPanel1);  // FLP = your FlowLayouPanel
                MSC.timerSpeed = 5;  // optional
                MSC.nearness = 100;  // optional

                flowLayoutPanel1.AutoScroll = false;

            }

now the apps doing wired behavior after adding new code. if i am making any mistake then guide me please. thanks

1
What you mean is you have pictureboxes that are not visible and want to scroll them in? - γηράσκω δ' αεί πολλά διδασκόμε
my flow layout panel has many picture boxes like picture attached and all are not visible. so i want to scroll the flow layout panel automatically when i will place my mouse at the bottom edge of the flow layout panel or top edge of flow layout panel. am i clear...still if not then ask me. - Thomas

1 Answers

0
votes

This is a two-part problem:

  • How to grab the event
  • How to scroll a FlowLayoutPanel with its scrollbars invisible.

Second first. It is not an easy task from what I found, unless you use a simple and rather common trick: Don't actually scroll it! Instead place it into a Panel and then control its position inside that Panel.

To do this you add a Panel panel1 to your Form, Dock or Anchor it as you need to and set its Autoscroll = false (!) (Which is not the way it is usually done, when you want to make, say a PictureBox scrollable. But we don't want the Panel to show it Scrollbars either.)

Set the FLP to its desired size and place it into the Panel, it obviously also has Autoscroll = false, and we're ready to tackle the other problem of setting up the event..:

First you add the MouseScroll event below to your code and then you hook every control up to it you want to work with the mouse move, namely the FLP:

  flowLayoutPanel1.MouseMove += MouseScroll;

..and also each of your PictureBoxes, maybe like this

  // your creation loop..
  PictureBox pbox = new PictureBox();
  pbox.MouseMove += MouseScroll;           // <<--- hook into to the mousemove
  pan.MouseLeave += outSideCheck;          // <<--- hook into to the mouseleave

  // .. do your stuff.. here I put some paint on to test..
  pbox.BackColor = Color.FromArgb(255, 111, (i * 3) & 255, (i * 4) & 255);
  flowLayoutPanel1.Controls.Add(pbox);

or however you create them..

Edit 2 I have changed my original code once more. It now includes an outside check, a check for moving towards the closest edge and a workaround for tha mousemove bug. It uses a Timer set to maybe 30ms. The speed mapping is in a function of its own.

 flowLayoutPanel1.MouseMove += MouseScroll;
 this.flowLayoutPanel1.MouseLeave += outSideCheck;
 flowLayoutPanel1.AutoScroll = false;


int near = 33;
Point lastLocation = Point.Empty;
int dX = 0;
int dY = 0;

private void MouseScroll(object sender, MouseEventArgs e)
{
    Point  mouse = panel1.PointToClient(MousePosition);
    Rectangle C = panel1.ClientRectangle;
    // mouseMove has a bug, we need to workaround
    if (mouse == lastLocation) return;
    if (lastLocation == Point.Empty) { lastLocation = mouse; return; }


    // distance from each edge
    int dLeft = mouse.X - C.Left;
    int dTop = mouse.Y - C.Top;
    int dRight = C.Right - mouse.X;
    int dBottom = C.Bottom - mouse.Y;

    // relevant distances with sign
        dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
        dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;

        // we need the closest edge to check if we are moving in or out
    List<int> edges = new List<int>() { dLeft, dTop, dRight, dBottom };
    var closest = edges.IndexOf(edges.Min());

    // if we are moving
    if (dX != 0 | dY != 0)
        // if moving out: go else stop going
        if (!movingIn(mouse, closest)) timer1.Start(); else timer1.Stop();
    // remember position    
    lastLocation = mouse;
}

bool movingIn(Point current, int Edge)
{
    switch (Edge)
    {
        case 0:  return current.X > lastLocation.X;
        case 1:  return current.Y > lastLocation.Y;
        case 2:  return current.X < lastLocation.X;
        case 3:  return current.Y < lastLocation.Y;
    }
    return false;
}

void scrollFLP(int deltaX, int deltaY)
{
    flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
    flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
    Size C = panel1.ClientSize;
    if (flowLayoutPanel1.Left > 1) { flowLayoutPanel1.Left = 0; timer1.Stop(); }
    if (flowLayoutPanel1.Right < C.Width) 
        { flowLayoutPanel1.Left = C.Width - flowLayoutPanel1.Width; timer1.Stop(); }
    if (flowLayoutPanel1.Top > 1) { flowLayoutPanel1.Top = 0; timer1.Stop(); }
    if (flowLayoutPanel1.Bottom < C.Height) 
        { flowLayoutPanel1.Top = C.Height - flowLayoutPanel1.Height; timer1.Stop(); }
}

int getSpeedFromDistance(int delta)
{
    int sig = Math.Sign(delta); 
    int d = Math.Abs(delta);
    if (d > near / 2) return  sig;
    else if (d > near / 3) return 2 * sig;
    else if (d > near / 4) return 4 * sig;
    else if (d > near / 5) return 6 * sig;
    else return 10 * sig;
}

private void timer1_Tick(object sender, EventArgs e)  
{
        if (insidePanel()) scrollFLP(dX, dY); else timer1.Stop();
    }

bool insidePanel()
{
    return panel1.ClientRectangle.Contains(panel1.PointToClient(MousePosition));
}

private void outSideCheck(object sender, EventArgs e)
{
    if (!insidePanel()) {timer1.Stop(); lastLocation = Point.Empty;}
}

Of course you'll want to play with the various 'magic' numbers :-)

Stop code and direction check are now included.

As usual, key is to know precisely what you want.. I hope this gets you started on ways to achieve it!