[英]How to scroll Flow layout panel content as per mouse position
我已经采用了一个 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;
}
现在应用程序在添加新代码后执行有线行为。 如果我犯了任何错误,请指导我。 谢谢
这是一个两部分的问题:
FlowLayoutPanel
。 第二先。 根据我的发现,这不是一件容易的事,除非您使用一个简单且相当常见的技巧:实际上不要滚动它! 而是将其放入Panel
中,然后控制其在该Panel
中的位置。
为此,您可以根据需要将Panel panel1
添加到 Form、 Dock
或Anchor
中,并设置其PictureBox
Autoscroll = false
(!) . 但我们也不希望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;}
}
当然你会想玩各种“神奇”的数字:-)
现在包括停止代码和方向检查。
像往常一样,关键是准确地知道你想要什么。我希望这能让你开始实现它!
自从问这个问题以来已经有一段时间了。 我刚遇到这个问题。 我的情况有点不同,但我仍然认为这是解决同一问题的方法(最坏的情况是可以使用计时器控件,因为未打开自动滚动)。
这是我的场景:我有一个panel
控件(普通面板)。 我有一个用缩放制作的PictureBox
。 I'm making rectangular selections on top of this image, and when the selections spilled out of the panel, my panel was supposed to slide in the direction I was selecting. (在我的场景中,鼠标被按下)(在我的场景中,自动滚动也是打开的)。 这就是我在不写太多代码的情况下解决它的方法:
我为滚动位置添加了两个私有变量(对整个类范围有效)。
private int xPos;
private int yPos;
private int speed = 5;
我在加载表单时为它们分配了当前的滚动位置。
private void Form1_Load(object sender, EventArgs e)
{
//when I change the scrollbar manually or change with zoom I still
//need to add these lines to the related event
xPos = panel1.HorizontalScroll.Value;
yPos = panel1.VerticalScroll.Value;
}
在我的图片框的 mousemove 事件中
private void picturebox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
Point mouse = panel1.PointToClient(MousePosition);
if (!panel1.ClientRectangle.Contains( mouse ))
{
Rectangle CRect = panel1.ClientRectangle;
int dLeft = mouse.X - CRect.Left;
int dRight = CRect.Right - mouse.X;
int dTop = mouse.Y - CRect.Top;
int dBottom = CRect.Bottom - mouse.Y;
if(dLeft < 0 && panel1.HorizontalScroll.Value > 0)
{
xPos = -panel1.AutoScrollPosition.X - speed;
}
if (dRight < 0 && panel1.HorizontalScroll.Value < panel1.HorizontalScroll.Maximum)
{
xPos = -panel1.AutoScrollPosition.X + speed;
}
if (dTop < 0 && panel1.VerticalScroll.Value > 0)
{
yPos = -panel1.AutoScrollPosition.Y - speed;
}
if (dBottom < 0 && panel1.VerticalScroll.Value < panel1.VerticalScroll.Maximum)
{
yPos = -panel1.AutoScrollPosition.Y + speed;
}
panel1.AutoScrollPosition = new Point(xPos, yPos);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.