首页 新闻 会员 周边 捐助

通过Winform的用户控件写了一个一直转圈的进度条,但是运行起来内存一直增长

0
悬赏园豆:20 [待解决问题] 浏览: 103次

代码基本模仿
https://www.jb51.net/article/46069.htm
但是运行的时候,内存呈现阶梯式的上涨,内存占用越来越大,请教大神们这种问题怎么处理

源码:

public partial class LoadingPhoto : UserControl
{
private int count = -1;
private ArrayList images = new ArrayList();
public Bitmap[] bitmap = new Bitmap[8];
private int _value = 1;
private Color _circleColor = System.Drawing.Color.FromArgb(((int)(((byte)(156)))), ((int)(((byte)(121)))), ((int)(((byte)(58)))));
private Color _textColor = System.Drawing.Color.FromArgb(((int)(((byte)(156)))), ((int)(((byte)(121)))), ((int)(((byte)(58)))));
private float _circleSize = 0.8f;
private int width = 200;//设置圆的宽
private int height = 200;////设置圆的高

    public LoadingPhoto()
    {
        InitializeComponent();
        this.Paint += new PaintEventHandler(UserControl1_Paint);
    }

    [Category("TestGroup")]
    public bool StartOrStop
    {
        get => false;
        set
        {
            if (value)
            {
                StartWaiting();
            }
            else
            {
                StopWaiting();
            }
        }
    }
    [Category("TestGroup")]
    public Color CirCleColor
    {
        get => _circleColor;
        set => _circleColor = value;
    }
    [Category("TestGroup")]
    public Color TextColor
    {
        get => _textColor;
        set => label1.ForeColor = value;
    }

    public Bitmap DrawCircle(int j)
    {
        const float angle = 360.0F / 8;
        Bitmap map = new Bitmap(150, 150);
        Graphics g = Graphics.FromImage(map);

        g.TranslateTransform(width / 2.0F, height / 2.0F);
        g.RotateTransform(angle * _value);
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        int[] a = new int[8] { 25, 50, 75, 100, 125, 150, 175, 200 };

        for (int i = 1; i <= 8; i++)
        {
            int alpha = a[(i + j - 1) % 8];
            Color drawColor = Color.FromArgb(alpha, _circleColor);
            using (SolidBrush brush = new SolidBrush(drawColor))
            {
                float sizeRate = 3.5F / _circleSize;
                float size = width / (6 * sizeRate);
                float diff = (width / 10.0F) - size;
                float x = (width / 80.0F) + diff;
                float y = (height / 80.0F) + diff;
                g.FillEllipse(brush, x, y, size, size);
                g.RotateTransform(angle);
            }
        }
        return map;
    }

    public void Draw()
    {
        for (int j = 0; j < 8; j++)
        {
            bitmap[7 - j] = DrawCircle(j);
        }
    }

    protected override void OnResize(EventArgs e)
    {
        SetNewSize();
        base.OnResize(e);
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        SetNewSize();
        base.OnSizeChanged(e);
    }

    private void SetNewSize()
    {
        int size = Math.Max(width, height);
        pictureBox.Size = new Size(size, size);
    }

    public void set()
    {
        for (int i = 0; i < 8; i++)
        {
            Draw();
            Bitmap map = new Bitmap((bitmap[i]), new Size(250, 250));
            images.Add(map);
        }
        pictureBox.Image = (Image)images[0];
        pictureBox.Size = pictureBox.Image.Size;
    }

    private void Timer_Tick(object sender, EventArgs e)
    {
        set();
        count = (count + 1) % 8;
        pictureBox.Image = (Image)images[count];
    }

    private void StartWaiting()
    {
        timer1.Start();
        pictureBox.Visible = true;
    }

    private void StopWaiting()
    {
        timer1.Stop();
        pictureBox.Visible = false;

    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        set();
        count = (count + 1) % 8;
        pictureBox.Image = (Image)images[count];
    }

    private void LoadingPhoto_Load(object sender, EventArgs e)
    {
       
    }

    private void UserControl1_Paint(object sender, PaintEventArgs e)
    {
        // 创建GraphicsPath对象以定义圆角矩形的路径
        using (System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath())
        {
            int radius = 30;
            path.AddArc(0, 0, radius, radius, 180, 90); // 左上角
            path.AddArc(this.Width - radius, 0, radius, radius, 270, 90); // 右上角
            path.AddArc(this.Width - radius, this.Height - radius, radius, radius, 0, 90); // 右下角
            path.AddArc(0, this.Height - radius, radius, radius, 90, 90); // 左下角

            // 设置Region属性,但这一步在Paint事件中不是必需的,因为Region已经在Load或构造函数中设置过了
            // this.Region = new System.Drawing.Region(path);

            // 使用Graphics对象绘制边框
            //using (Pen pen = new Pen(Color.Black, 2)) // 可以自定义颜色和宽度
            //{
            //    e.Graphics.DrawPath(pen, path);
            //}
        }
    }
}
xiaozhuBJZ的主页 xiaozhuBJZ | 初学一级 | 园豆:113
提问于:2025-01-14 09:13
< > 人人可用的开源BI工具
分享
所有回答(3)
0

你跑一会暂停,看看images数组的长度.

www378660084 | 园豆:1325 (小虾三级) | 2025-01-14 11:11

多谢大神指点,这images数组的长度很大,我clear后,内存涨幅减缓了不少,但是还是缓慢增长
开始从800MB 涨到826MB,还有继续上涨的趋势。 请问代码还有哪里可能出现没有释放内存的地方呢

支持(0) 反对(0) xiaozhuBJZ | 园豆:113 (初学一级) | 2025-01-14 17:55

@xiaozhuBJZ: 缓慢上涨可能是new的对象没来得及gc,应该不会持续一直涨的.把需要的对象在构造函数里全部new完,需要时候复用,内存就不会怎么变化了.

支持(0) 反对(0) www378660084 | 园豆:1325 (小虾三级) | 2025-01-15 10:10
0

你不应该在计时器里面一直去循环创建bitmap,而且每次都创建8张,它是你内存上涨的主要原因
我看了你的需求,感觉你不应该使用image,和bitmap,
而是直接用UserControl1_Paint里面的e.Graphics,直接绘制小圆点就行,控制一下每个小球的颜色

q83821684 | 园豆:202 (菜鸟二级) | 2025-01-15 09:25
0

public void set()
{
for (int i = 0; i < 8; i++)
{
Draw();
Bitmap map = new Bitmap((bitmap[i]), new Size(250, 250));
images.Add(map);
}
pictureBox.Image = (Image)images[0];
pictureBox.Size = pictureBox.Image.Size;
}
额,我不知道你为啥需要在定时期里调用这个,这相当于个周期新增8个。 这个没必要。

传统游戏是一次生成8个,或者按规律一次生成一个,游戏上叫精灵图。如果只有8个,你只是定时器取模加载就好
如果是生成类似游戏精灵图的,只是按规则截取区域,下面我随便问问chatgpt,这是chatgpt的回复

public class SpriteAnimation : Form
{
private Bitmap spriteSheet; // 精灵图
private int currentFrame = 0; // 当前帧
private const int FRAME_COUNT = 8; // 总帧数
private int frameWidth; // 单帧宽度
private int frameHeight; // 单帧高度
private Timer animationTimer; // 动画计时器

public SpriteAnimation()
{
    // 加载精灵图
    spriteSheet = new Bitmap("spritesheet.png");
    
    // 计算单帧尺寸
    frameWidth = spriteSheet.Width / FRAME_COUNT;
    frameHeight = spriteSheet.Height;

    // 设置窗体
    this.DoubleBuffered = true;
    this.Size = new Size(frameWidth, frameHeight);

    // 设置动画计时器
    animationTimer = new Timer();
    animationTimer.Interval = 100; // 动画间隔(毫秒)
    animationTimer.Tick += AnimationTimer_Tick;
    animationTimer.Start();
}

private void AnimationTimer_Tick(object sender, EventArgs e)
{
    // 更新当前帧
    currentFrame = (currentFrame + 1) % FRAME_COUNT;
    this.Invalidate(); // 触发重绘
}

protected override void OnPaint(PaintEventArgs e)
{
    Graphics g = e.Graphics;
    
    // 计算当前帧在精灵图上的位置
    Rectangle sourceRect = new Rectangle(
        currentFrame * frameWidth, // X坐标
        0,                        // Y坐标
        frameWidth,               // 宽度
        frameHeight               // 高度
    );

    // 绘制当前帧
    g.DrawImage(
        spriteSheet,
        new Rectangle(0, 0, frameWidth, frameHeight), // 目标区域
        sourceRect,                                   // 源区域
        GraphicsUnit.Pixel
    );
}

}

gihelo01 | 园豆:206 (菜鸟二级) | 2025-01-21 15:34

当然还有其他方式,就是直接gdi+进行局部的擦除和更新,我同样问问chatgpt,下面依旧是chatgpt的回复(我个人认为局部擦除和更新,可能要好于生成)

public class RotatingObject : Form
{
private float angle = 0;
private Timer animationTimer;
private Point center;
private Rectangle updateRect; // 需要更新的区域

// 用于双缓冲的缓存
private Bitmap backBuffer;
private Graphics backGraphics;

public RotatingObject()
{
    this.DoubleBuffered = true;
    this.Size = new Size(400, 400);
    center = new Point(200, 200);

    // 创建后台缓冲
    backBuffer = new Bitmap(Width, Height);
    backGraphics = Graphics.FromImage(backBuffer);

    // 设置高质量绘图
    backGraphics.SmoothingMode = SmoothingMode.AntiAlias;
    backGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    // 初始化定时器
    animationTimer = new Timer();
    animationTimer.Interval = 16; // 约60FPS
    animationTimer.Tick += AnimationTimer_Tick;
    animationTimer.Start();
}

private void AnimationTimer_Tick(object sender, EventArgs e)
{
    // 计算需要更新的区域
    updateRect = CalculateUpdateRect();

    // 更新角度
    angle = (angle + 1) % 360;

    // 触发重绘
    Invalidate(updateRect);
}

private Rectangle CalculateUpdateRect()
{
    // 计算对象的边界框
    int size = 100; // 对象大小
    int padding = 10; // 额外的边距,防止抗锯齿效果被裁剪

    // 计算旋转后的包围盒
    Rectangle bounds = new Rectangle(
        center.X - size/2 - padding,
        center.Y - size/2 - padding,
        size + padding * 2,
        size + padding * 2
    );

    return bounds;
}

protected override void OnPaint(PaintEventArgs e)
{
    // 清除上一帧
    backGraphics.SetClip(updateRect);
    backGraphics.Clear(BackColor);

    // 绘制新帧
    using (Matrix transform = new Matrix())
    {
        transform.RotateAt(angle, center);
        backGraphics.Transform = transform;

        // 绘制对象
        using (Pen pen = new Pen(Color.Blue, 2))
        using (Brush brush = new SolidBrush(Color.LightBlue))
        {
            Rectangle rect = new Rectangle(
                center.X - 50,
                center.Y - 50,
                100,
                100
            );
            backGraphics.FillRectangle(brush, rect);
            backGraphics.DrawRectangle(pen, rect);
        }
    }

    // 将后台缓冲复制到屏幕
    e.Graphics.DrawImage(backBuffer, updateRect, updateRect, GraphicsUnit.Pixel);
}

protected override void OnResize(EventArgs e)
{
    base.OnResize(e);

    // 重新创建后台缓冲
    if (backBuffer != null)
    {
        backBuffer.Dispose();
        backGraphics.Dispose();
    }

    backBuffer = new Bitmap(Width, Height);
    backGraphics = Graphics.FromImage(backBuffer);
    backGraphics.SmoothingMode = SmoothingMode.AntiAlias;
    backGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    // 更新中心点
    center = new Point(Width/2, Height/2);
}

protected override void OnClosing(CancelEventArgs e)
{
    base.OnClosing(e);
    
    // 清理资源
    backBuffer?.Dispose();
    backGraphics?.Dispose();
    animationTimer?.Dispose();
}

}

支持(0) 反对(0) gihelo01 | 园豆:206 (菜鸟二级) | 2025-01-21 15:40
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册
Top