【问题标题】:How to scroll Flow layout panel content as per mouse position如何根据鼠标位置滚动流布局面板内容
【发布时间】:2014-09-16 09:41:11
【问题描述】:

我采用了一个 Flow 布局面板并在其中放置了多个图片框。现在我想什么时候将鼠标放在流布局面板的最右边或最左边,然后图片的其余部分将滚动出来。想想 Windows 8 的开始屏幕,屏幕上出现了许多图块,当我们将鼠标放在屏幕的最右边时,其余的图块会滚动出来。我想用 Flow 布局面板在 windows 窗体中模拟相同的东西。

我希望我的 Flow 布局面板不会显示滚动条,但当我将鼠标放在面板的最右侧或左侧时,图像会滚动出来。这是我的屏幕截图

有人告诉我这样做...这是位代码 在 Panel 的 MouseMove 事件中设置 AutoScrollPosition 属性。

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

但是这个技巧并不好。 AutoScrollPosition 在滚动条可见时工作,但在我的情况下,我不想在 Flow 布局面板中显示滚动条。我想要从左到右或从右到左平滑滚动图像。任何人都可以帮助我实现我想要做的事情......如果可能的话,指导我进行编码。谢谢

编辑

在这里,我按照@Taw 的建议修改后给出了我的完整代码,但它不能正常工作....当图片移动时发现闪烁。无论如何,这里是完整的代码。

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;
        }
    }
}

基本上我正在尝试实现类似假设我有flow layout panel 并且其中有很多图片框,其中有很多图像作为屏幕截图,但滚动条不应该显示,而是当我将鼠标放在流布局面板的顶部或底部,例如 carousel

查看您的应用程序的这张图片

当我将鼠标放在右端时,它会滚动并形成我不想要的背景。我希望图片框将滚动并滚动到最后一个不超过那个。

知道怎么做。谢谢

第二次编辑

我根据您的建议添加了此代码

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;

            }

现在应用程序在添加新代码后执行有线行为。如果我犯了任何错误,请指导我。谢谢

【问题讨论】:

  • 你的意思是你有不可见的图片框并想要滚动它们?
  • 我的流程布局面板有很多图片框,如附加图片,全部不可见。所以当我将鼠标放在流程布局面板的底部边缘或流程布局面板的顶部边缘时,我想自动滚动流程布局面板。我清楚吗...如果不是,请问我。

标签: c# winforms


【解决方案1】:

这是一个由两部分组成的问题:

  • 如何抓住事件
  • 如何滚动 FlowLayoutPanel 并使其滚动条不可见。

其次。根据我的发现,这不是一件容易的事,除非您使用一个简单且相当常见的技巧:实际上不要滚动它!而是将其放入 Panel 中,然后控制其在 Panel 中的位置。

为此,您可以根据需要在表单中添加Panel panel1DockAnchor,并设置其Autoscroll = false (!)(这不是通常的方式,当您想要制作,比如说PictureBox 可滚动。但我们也不希望Panel 显示它Scrollbars。)

将 FLP 设置为所需的大小并将其放入面板中,它显然还有Autoscroll = false,我们已准备好解决设置事件的另一个问题..:

首先,您将下面的MouseScroll 事件添加到您的代码中,然后将您想要使用鼠标移动的每个控件(即 FLP)与它挂钩:

  flowLayoutPanel1.MouseMove += MouseScroll;

..还有你的每个图片框,可能是这样的

  // 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);

或者无论你如何创建它们..

编辑 2 我再次更改了我的原始代码。它现在包括外部检查、向最近边缘移动的检查以及鼠标移动错误的解决方法。它使用一个设置为 30 毫秒的定时器。速度映射是其自身的函数。

 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;}
}

当然你会想玩各种“神奇”数字:-)

现在包括停止代码和方向检查。

像往常一样,关键是准确地知道你想要什么。我希望这能让你开始实现它!

【讨论】:

  • 感谢您的回复,但您提供的代码未按预期工作。请查看我的编辑以获取我测试的完整代码。寻找建议。谢谢
  • 嗨,我的时间很紧,今天晚些时候会仔细查看您的帖子更新。我刚刚发布了我的最后一个版本,它发现有了很大的改进并且滚动非常流畅。但是有一个问题:您要左右滚动还是上下滚动,还是两者都滚动?我都实现了,但你的帖子不清楚..
  • 一个注释:foreach (Control x in this.Controls) 这似乎是错误的 - 图片框真的还在 this.Controls 中吗?将它们添加到 FLP 后,它们就在其 Controls 集合中!这意味着滚动只发生在它们之间的间隙!!
  • 你给出的逻辑不起作用。您的逻辑移动了 flp 容器,但是当鼠标触摸 flp 容器的上边缘或下边缘时,我想在 flp 容器中滚动图像。最好在最后编写逻辑并进行测试,然后您就可以了解发生了什么问题。
  • 我的逻辑工作正常并经过测试。 效果正是你想要的,即使它以不同的方式完成。不过,我怀疑您是否按照我的建议实施了它。当然,您可以尝试实际滚动 FLP,但我不知道该怎么做。你??如果没有滚动条显示这似乎几乎是不可能的。如果你愿意,我可以压缩解决方案并将其上传到某个地方,这样你就可以测试我拥有的版本..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
相关资源
最近更新 更多