C#。在windows窗体上显示和移动图标

C#。在windows窗体上显示和移动图标,c#,winforms,transparency,icons,picturebox,C#,Winforms,Transparency,Icons,Picturebox,我需要在windows窗体上显示一组图标,并在运行时移动它们。我使用PictureBox控件来显示图标,但我必须要么不将PictureBox.SizeMode更改为“拉伸”,这会导致非常小的图标,要么在运行时它们看起来模糊而可怕,即使它们是高质量的图标 虽然很多人都有同样的问题,但我一直在谷歌上搜索解决方案,但毫无结果。你有解决办法吗 如果没有,您将如何在windows窗体上显示图标,以便在运行时轻松移动图标 谢谢分享你的时间和知识 编辑 下面是一些屏幕截图:上面的是设计时的PictureBox

我需要在windows窗体上显示一组图标,并在运行时移动它们。我使用PictureBox控件来显示图标,但我必须要么不将PictureBox.SizeMode更改为“拉伸”,这会导致非常小的图标,要么在运行时它们看起来模糊而可怕,即使它们是高质量的图标

虽然很多人都有同样的问题,但我一直在谷歌上搜索解决方案,但毫无结果。你有解决办法吗

如果没有,您将如何在windows窗体上显示图标,以便在运行时轻松移动图标

谢谢分享你的时间和知识

编辑 下面是一些屏幕截图:上面的是设计时的PictureBox,下面是运行时的PictureBox


覆盖
OnPaint()
并在需要的地方用e.Graphics.DrawImageUnscaled()绘制图标。

覆盖
OnPaint()
并在需要的地方用e.Graphics.DrawImageUnscaled()绘制图标。

我使用一组32x32.png图标来完成此操作。我使用FlowLayoutPanel作为容器,并向其中添加PictureBox控件。在这个代码段中,uxIconPanel是一个FlowLayoutPanel

foreach (Image img in GetImageListForClassification(entityClass))
{
    PictureBox box = new PictureBox();
    box.Image = img;
    box.Size = box.PreferredSize;
    box.Anchor = AnchorStyles.Top | AnchorStyles.Left;
    uxIconPanel.Controls.Add(box);
}

我使用一组32x32.png图标来实现这一点。我使用FlowLayoutPanel作为容器,并向其中添加PictureBox控件。在这个代码段中,uxIconPanel是一个FlowLayoutPanel

foreach (Image img in GetImageListForClassification(entityClass))
{
    PictureBox box = new PictureBox();
    box.Image = img;
    box.Size = box.PreferredSize;
    box.Anchor = AnchorStyles.Top | AnchorStyles.Left;
    uxIconPanel.Controls.Add(box);
}

从一个数组开始,保存需要的图像类

- image
- left
- top
- height
- width
重写OnPaint()并在阵列中的每个图像的位置绘制

处理MouseDown事件

- track the mouse down location
- determine whether the location hits one of the images 
  and track which one was hit
- track the original location of the hit image
处理MouseMove事件

- if not mouse button pressed then return
- if not tracking a hit from mouse down then return
- determine the change in position of the mouse from 
  what it was in the mouse down event
- apply the change in position to the original image position
  to set the new position of the tracked image
- Invalidate() to cause a repaint in the new position

此伪代码将提供基本的对象拖动功能。

从一个数组开始,以保存需要的图像类

- image
- left
- top
- height
- width
重写OnPaint()并在阵列中的每个图像的位置绘制

处理MouseDown事件

- track the mouse down location
- determine whether the location hits one of the images 
  and track which one was hit
- track the original location of the hit image
处理MouseMove事件

- if not mouse button pressed then return
- if not tracking a hit from mouse down then return
- determine the change in position of the mouse from 
  what it was in the mouse down event
- apply the change in position to the original image position
  to set the new position of the tracked image
- Invalidate() to cause a repaint in the new position

这个伪代码将提供基本的对象拖动功能。

我将使用位图而不是图标,正如其他人所说。我会这样做:

首先,创建一个保存位图的类和一个委托,该委托将指向一个方法,该方法将获取位图的位置作为时间的函数

delegate Point PositionFunction(int time);

class MovingBitmap
{
    private Bitmap bitmap;
    private PositionFunction positionFunction;

    public MovingBitmap(Bitmap bitmap, PositionFunction positionFunction)
    {
        if (bitmap == null)
        {
            throw new ArgumentNullException("bitmap");
        }
        else if (positionFunction == null)
        {
            throw new ArgumentNullException("bitmap");
        }

        this.bitmap = bitmap;
        this.positionFunction = positionFunction;
    }

    public Bitmap Bitmap
    {
        get { return this.bitmap; }
    }

    public PositionFunction PositionFunction
    {
        get { return this.positionFunction; }
    }
}
对于position函数,您需要决定位图的移动方式。(注意:时间以毫秒表示。)它可以简单到:

private Point SimpleTimeFunction(int time)
{
    return new Point(time / 5, time / 5);
}

private Point ParabolaFunction(int time)
{
    return new Point(time / 5, (time / 5) * (time / 5));
}
或者它可以是由多个方程组成的分段函数,例如:

if (time < 5000)
{
    return new Point(time / 5, 2 * (time / 5));
}
else
{
    return new Point(time / 5, time / 5) * time);
}
要实现动画效果,需要一个计时器。计时器过期时,刷新缓冲区,然后刷新控件

private System.Timers.Timer timer;
private ParameterlessVoid refreshMethod;
private delegate void ParameterlessVoid();

// Add these four lines to the constructor
this.timer = new System.Timers.Timer(1000 / 20);  // 20 times per second
this.timer.AutoReset = true;
this.timer.Elapsed += this.HandleTimerElapsed;
this.refreshMethod = new ParameterlessVoid(this.Refresh);

private void HandleTimerElapsed(object sender, EventArgs e)
{
    this.RefreshBuffer();
    this.Invoke(this.refreshMethod);
}

private void Start()
{
    this.startTime = System.Environment.TickCount;
    this.timer.Start();
}

我想这基本上就是你需要做的。它还没有经过充分的测试和调试,但它应该为您指明正确的方向。

我会使用位图,而不是像其他人所说的那样使用图标。我会这样做:

首先,创建一个保存位图的类和一个委托,该委托将指向一个方法,该方法将获取位图的位置作为时间的函数

delegate Point PositionFunction(int time);

class MovingBitmap
{
    private Bitmap bitmap;
    private PositionFunction positionFunction;

    public MovingBitmap(Bitmap bitmap, PositionFunction positionFunction)
    {
        if (bitmap == null)
        {
            throw new ArgumentNullException("bitmap");
        }
        else if (positionFunction == null)
        {
            throw new ArgumentNullException("bitmap");
        }

        this.bitmap = bitmap;
        this.positionFunction = positionFunction;
    }

    public Bitmap Bitmap
    {
        get { return this.bitmap; }
    }

    public PositionFunction PositionFunction
    {
        get { return this.positionFunction; }
    }
}
对于position函数,您需要决定位图的移动方式。(注意:时间以毫秒表示。)它可以简单到:

private Point SimpleTimeFunction(int time)
{
    return new Point(time / 5, time / 5);
}

private Point ParabolaFunction(int time)
{
    return new Point(time / 5, (time / 5) * (time / 5));
}
或者它可以是由多个方程组成的分段函数,例如:

if (time < 5000)
{
    return new Point(time / 5, 2 * (time / 5));
}
else
{
    return new Point(time / 5, time / 5) * time);
}
要实现动画效果,需要一个计时器。计时器过期时,刷新缓冲区,然后刷新控件

private System.Timers.Timer timer;
private ParameterlessVoid refreshMethod;
private delegate void ParameterlessVoid();

// Add these four lines to the constructor
this.timer = new System.Timers.Timer(1000 / 20);  // 20 times per second
this.timer.AutoReset = true;
this.timer.Elapsed += this.HandleTimerElapsed;
this.refreshMethod = new ParameterlessVoid(this.Refresh);

private void HandleTimerElapsed(object sender, EventArgs e)
{
    this.RefreshBuffer();
    this.Invoke(this.refreshMethod);
}

private void Start()
{
    this.startTime = System.Environment.TickCount;
    this.timer.Start();
}

我想这基本上就是你需要做的。它没有经过充分的测试和调试,但它应该为您指明正确的方向。

是否被用户或代码移动了?图标的格式是什么?以编程方式。图标是512x512。您是否正在WinForms应用程序中创建“抓住猴子”广告横幅?如果是这样,请给我的结果,最好的广告有史以来。移动周围的用户或代码?图标的格式是什么?以编程方式。图标是512x512。您是否正在WinForms应用程序中创建“抓住猴子”广告横幅?如果是这样,请给我的结果,有史以来最好的广告。同样的问题。图标太小了。如果我将box.SizeMode更改为拉伸图标,看起来会很糟糕。同样的问题。图标太小了。如果我将box.SizeMode更改为拉伸图标,看起来会很糟糕。我该如何移动它们?在不同的位置绘制它们?你可以通过定时器触发表单失效。我如何移动它们?在不同的位置绘制它们?您可以通过计时器触发表单失效。