C# 避免一次又一次地创建PictureBox
我有以下问题。我的意图是在Windows窗体中从右向左移动多个图像。下面的代码工作得很好。困扰我的是,每次创建PictureBox对象时,这个过程都会消耗大量内存。每个图像从右到左不间断地跟随前一个图像。这些图像显示天空从一侧移动到另一侧。它应该看起来像一架飞机在空中飞行 如何避免使用过多内存?我能用PaintEvent和GDI做些什么吗?我对图形编程不是很熟悉C# 避免一次又一次地创建PictureBox,c#,winforms,memory,picturebox,C#,Winforms,Memory,Picturebox,我有以下问题。我的意图是在Windows窗体中从右向左移动多个图像。下面的代码工作得很好。困扰我的是,每次创建PictureBox对象时,这个过程都会消耗大量内存。每个图像从右到左不间断地跟随前一个图像。这些图像显示天空从一侧移动到另一侧。它应该看起来像一架飞机在空中飞行 如何避免使用过多内存?我能用PaintEvent和GDI做些什么吗?我对图形编程不是很熟悉 using System; using System.Drawing; using System.Windows.Forms; usi
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
public class Background : Form
{
private PictureBox sky, skyMove;
private Timer moveSky;
private int positionX = 0, positionY = 0, width, height;
private List<PictureBox> consecutivePictures;
public Background(int width, int height)
{
this.width = width;
this.height = height;
// Creating Windows Form
this.Text = "THE FLIGHTER";
this.Size = new Size(width, height);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
// The movement of the sky becomes possible by the timer.
moveSky = new Timer();
moveSky.Tick += new EventHandler(moveSky_XDirection_Tick);
moveSky.Interval = 10;
moveSky.Start();
consecutivePictures = new List<PictureBox>();
skyInTheWindow();
this.ShowDialog();
}
// sky's direction of movement
private void moveSky_XDirection_Tick(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
skyMove = consecutivePictures[i];
skyMove.Location = new Point(skyMove.Location.X - 6, skyMove.Location.Y);
}
}
private void skyInTheWindow()
{
for (int i = 0; i < 100; i++)
{
// Loading sky into the window
sky = new PictureBox();
sky.Image = new Bitmap("C:/MyPath/Sky.jpg");
sky.SetBounds(positionX, positionY, width, height);
this.Controls.Add(sky);
consecutivePictures.Add(sky);
positionX += width;
}
}
}
使用系统;
使用系统图;
使用System.Windows.Forms;
使用System.Collections.Generic;
公共课背景:表格
{
私人图片盒天空,天空移动;
私人定时器移动天空;
专用int位置X=0,位置Y=0,宽度,高度;
私人列表连续图片;
公共背景(整数宽度、整数高度)
{
这个。宽度=宽度;
高度=高度;
//创建Windows窗体
this.Text=“飞行者”;
此尺寸=新尺寸(宽度、高度);
this.StartPosition=FormStartPosition.CenterScreen;
this.FormBorderStyle=FormBorderStyle.FixedSingle;
this.ebox=false;
//通过计时器,天空的运动成为可能。
moveSky=新计时器();
Tick+=新事件处理程序(moveSky\u XDirection\u Tick);
时间间隔=10;
moveSky.Start();
连续图片=新列表();
天空窗口();
this.ShowDialog();
}
//天空的运动方向
私有void moveSky\u XDirection\u Tick(对象发送方,事件参数e)
{
对于(int i=0;i<100;i++)
{
skyMove=连续图片[i];
skyMove.Location=新点(skyMove.Location.X-6,skyMove.Location.Y);
}
}
私有窗口()
{
对于(int i=0;i<100;i++)
{
//将天空载入窗口
天空=新图片框();
sky.Image=新位图(“C:/MyPath/sky.jpg”);
天空.立根(位置X、位置Y、宽度、高度);
this.Controls.Add(天空);
连续图片。添加(天空);
位置X+=宽度;
}
}
}
您似乎正在加载相同的位图100次。这就是你的记忆问题,而不是100PictureBox
s。PictureBox
应该具有较低的内存开销,因为它们的内存消耗中不包括图像,而引用的位图更可能消耗大量内存
<强>它很容易被固定< /强> -考虑加载位图一次,然后将它应用到所有的<代码>图片框< /代码> S.
更改:
private void skyInTheWindow()
{
for (int i = 0; i < 100; i++)
{
// Loading sky into the window
sky = new PictureBox();
sky.Image = new Bitmap("C:/MyPath/Sky.jpg");
sky.SetBounds(positionX, positionY, width, height);
this.Controls.Add(sky);
consecutivePictures.Add(sky);
positionX += width;
}
}
这并不是对这个问题的直接回答——我认为这主要是因为您正在创建的所有位图
图像。您应该只创建一个,然后问题就消失了
我在这里建议的是另一种编码方式,它极大地减少了代码
我所有的代码在this.MaximizeBox=false一行之后直接进入你的Background
构造函数代码>。之后的一切都被移除
因此,从加载图像开始:
var image = new Bitmap(@"C:\MyPath\Sky.jpg");
接下来,根据传入的宽度
和高度
计算出需要在表单上平铺多少个图片框:
var countX = width / image.Width + 2;
var countY = height / image.Height + 2;
现在创建将填充屏幕的实际图片框:
var pictureBoxData =
(
from x in Enumerable.Range(0, countX)
from y in Enumerable.Range(0, countY)
let positionX = x * image.Width
let positionY = y * image.Height
let pictureBox = new PictureBox()
{
Image = image,
Location = new Point(positionX, positionY),
Size = new Size(image.Width, image.Height),
}
select new
{
positionX,
positionY,
pictureBox,
}
).ToList();
接下来,将它们全部添加到控件
集合:
pictureBoxData.ForEach(pbd => this.Controls.Add(pbd.pictureBox));
最后,使用Microsoft的反应式框架(NuGetRx WinForms
)创建一个计时器,用于更新图片框的左侧位置:
var subscription =
Observable
.Generate(
0,
n => true,
n => n >= image.Width ? 0 : n + 1,
n => n,
n => TimeSpan.FromMilliseconds(10.0))
.ObserveOn(this)
.Subscribe(n =>
{
pictureBoxData
.ForEach(pbd => pbd.pictureBox.Left = pbd.positionX - n);
});
最后,在启动对话框之前,我们需要一种方法来清理上面的所有内容,以便窗体可以干净地关闭。这样做:
var disposable = new CompositeDisposable(image, subscription);
this.FormClosing += (s, e) => disposable.Dispose();
现在您可以执行ShowDialog
:
this.ShowDialog();
就这样
除了nugettingRx WinForms
,您还需要使用
语句在代码顶部添加以下:
using System.Reactive.Linq;
using System.Reactive.Disposables;
这一切对我来说都很好:
变量和名称尚未翻译成英语。尽管如此,我还是希望大家都能理解
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
/// <summary>
/// Scrolling Background - Bewegender Hintergrund
/// </summary>
public class ScrollingBackground : Form
{
/* this = fremde Attribute und Methoden,
* ohne this = eigene Attribute und Methoden
*/
private PictureBox picBoxImage;
private PictureBox[] listPicBoxAufeinanderfolgendeImages;
private Timer timerBewegungImage;
private const int constIntAnzahlImages = 2,
constIntInterval = 1,
constIntPositionY = 0;
private int intPositionX = 0,
intFeinheitDerBewegungen,
intBreite,
intHoehe;
private string stringTitel,
stringBildpfad;
// Konstruktor der Klasse Hintergrund
/// <summary>
/// Initialisiert eine neue Instanz der Klasse Hintergrund unter Verwendung der angegebenen Ganzzahlen und Zeichenketten.
/// Es wird ein Windows-Fenster erstellt, welches die Möglichkeit hat, ein eingefügtes Bild als bewegenden Hintergrund darzustellen.
/// </summary>
/// <param name="width">Gibt die Breite des Fensters an und passt den darin befindlichen Hintergrund bzgl. der Breite automatisch an.</param>
/// <param name="height">Gibt die Höhe des Fensters an und passt den darin befindlichen Hintergrund bzgl. der Höhe automatisch an.</param>
/// <param name="speed">Geschwindigkeit der Bilder</param>
/// <param name="title">Titel des Fensters</param>
/// <param name="path">Pfad des Bildes, welches als Hintergrund dient</param>
public ScrollingBackground(int width, int height, int speed, string title, string path)
{
// Klassennutzer können Werte setzen
intBreite = width;
intHoehe = height;
intFeinheitDerBewegungen = speed;
stringTitel = title;
stringBildpfad = path;
// Windows-Fenster wird erschaffen
this.Text = title;
this.Size = new Size(this.intBreite, this.intHoehe);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
// Die Bewegung des Bildes wird durch den Timer ermöglicht.
timerBewegungImage = new Timer();
timerBewegungImage.Tick += new EventHandler(bewegungImage_XRichtung_Tick);
timerBewegungImage.Interval = constIntInterval;
timerBewegungImage.Start();
listPicBoxAufeinanderfolgendeImages = new PictureBox[2];
imageInWinFormLadenBeginn();
this.ShowDialog();
}
// Bewegungsrichtung des Bildes
private void bewegungImage_XRichtung_Tick(object sender, EventArgs e)
{
for (int i = 0; i < constIntAnzahlImages; i++)
{
picBoxImage = listPicBoxAufeinanderfolgendeImages[i];
// Flackerreduzierung - Minimierung des Flackerns zwischen zwei Bildern
this.DoubleBuffered = true;
// Bilder werden in X-Richtung bewegt
picBoxImage.Location = new Point(picBoxImage.Location.X - intFeinheitDerBewegungen, picBoxImage.Location.Y);
// Zusammensetzung beider gleicher Bilder, welche den Effekt haben, die Bilder ewig fortlaufend erscheinen zu lassen
if (listPicBoxAufeinanderfolgendeImages[1].Location.X <= 0)
{
imageInWinFormLadenFortsetzung();
}
}
}
// zwei PictureBoxes mit jeweils zwei gleichen Bildern werden angelegt
private void imageInWinFormLadenBeginn()
{
Bitmap bitmapImage = new Bitmap(stringBildpfad);
for (int i = 0; i < constIntAnzahlImages; i++)
{
// Bild wird in Fenster geladen
picBoxImage = new PictureBox();
picBoxImage.Image = bitmapImage;
// Bestimmung der Position und Größe des Bildes
picBoxImage.SetBounds(intPositionX, constIntPositionY, intBreite, intHoehe);
this.Controls.Add(picBoxImage);
listPicBoxAufeinanderfolgendeImages[i] = picBoxImage;
// zwei PictureBoxes mit jeweils zwei gleichen Bildern werden nebeneinander angefügt
intPositionX += intBreite;
}
}
// Wiederholte Nutzung der PictureBoxes
private void imageInWinFormLadenFortsetzung()
{
// erste PictureBox mit Image wird wieder auf ihren Anfangswert "0" gesetzt - Gewährleistung der endlos laufenden Bilder
picBoxImage = listPicBoxAufeinanderfolgendeImages[0];
picBoxImage.SetBounds(intPositionX = 0, constIntPositionY, intBreite, intHoehe);
// zweite PictureBox mit Image wird wieder auf ihren Anfangswert "intBreite" gesetzt - Gewährleistung der endlos laufenden Bilder
picBoxImage = listPicBoxAufeinanderfolgendeImages[1];
picBoxImage.SetBounds(intPositionX = intBreite, constIntPositionY, intBreite, intHoehe);
}
}
使用系统;
使用系统图;
使用System.Windows.Forms;
使用System.Collections.Generic;
///
///滚动背景-Bewegender Hintergrund
///
公共类ScrollingBackground:表单
{
/*this=fremde属性和方法,
*ohne this=特征属性和方法
*/
私人PictureBox picBoxImage;
私人PictureBox[]列表PicboxAufeinanderFolgendeimages;
私人定时器定时器;
私有常量int constantanzahlimages=2,
constinterval=1,
constinty=0;
私有int intPositionX=0,
intFeinheitDerBewegungen,
英特布雷特,
在何处;
私有字符串stringTitel,
stringBildpfad;
//克拉斯·希特格朗德酒店
///
///在克拉斯暗示的新实例中,初始值不适用于Ganzzahlen和Zeichenketten。
///这是一个窗户玻璃窗,威尔士人戴着一顶莫格利奇基特帽子,这是一个秘密。
///
///在青苔自动生长和生长之前,植物的生长和繁殖都会受到影响。
///在地衣进入自动控制系统之前,必须要有一个安全的通道
using System.Reactive.Linq;
using System.Reactive.Disposables;
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
/// <summary>
/// Scrolling Background - Bewegender Hintergrund
/// </summary>
public class ScrollingBackground : Form
{
/* this = fremde Attribute und Methoden,
* ohne this = eigene Attribute und Methoden
*/
private PictureBox picBoxImage;
private PictureBox[] listPicBoxAufeinanderfolgendeImages;
private Timer timerBewegungImage;
private const int constIntAnzahlImages = 2,
constIntInterval = 1,
constIntPositionY = 0;
private int intPositionX = 0,
intFeinheitDerBewegungen,
intBreite,
intHoehe;
private string stringTitel,
stringBildpfad;
// Konstruktor der Klasse Hintergrund
/// <summary>
/// Initialisiert eine neue Instanz der Klasse Hintergrund unter Verwendung der angegebenen Ganzzahlen und Zeichenketten.
/// Es wird ein Windows-Fenster erstellt, welches die Möglichkeit hat, ein eingefügtes Bild als bewegenden Hintergrund darzustellen.
/// </summary>
/// <param name="width">Gibt die Breite des Fensters an und passt den darin befindlichen Hintergrund bzgl. der Breite automatisch an.</param>
/// <param name="height">Gibt die Höhe des Fensters an und passt den darin befindlichen Hintergrund bzgl. der Höhe automatisch an.</param>
/// <param name="speed">Geschwindigkeit der Bilder</param>
/// <param name="title">Titel des Fensters</param>
/// <param name="path">Pfad des Bildes, welches als Hintergrund dient</param>
public ScrollingBackground(int width, int height, int speed, string title, string path)
{
// Klassennutzer können Werte setzen
intBreite = width;
intHoehe = height;
intFeinheitDerBewegungen = speed;
stringTitel = title;
stringBildpfad = path;
// Windows-Fenster wird erschaffen
this.Text = title;
this.Size = new Size(this.intBreite, this.intHoehe);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
// Die Bewegung des Bildes wird durch den Timer ermöglicht.
timerBewegungImage = new Timer();
timerBewegungImage.Tick += new EventHandler(bewegungImage_XRichtung_Tick);
timerBewegungImage.Interval = constIntInterval;
timerBewegungImage.Start();
listPicBoxAufeinanderfolgendeImages = new PictureBox[2];
imageInWinFormLadenBeginn();
this.ShowDialog();
}
// Bewegungsrichtung des Bildes
private void bewegungImage_XRichtung_Tick(object sender, EventArgs e)
{
for (int i = 0; i < constIntAnzahlImages; i++)
{
picBoxImage = listPicBoxAufeinanderfolgendeImages[i];
// Flackerreduzierung - Minimierung des Flackerns zwischen zwei Bildern
this.DoubleBuffered = true;
// Bilder werden in X-Richtung bewegt
picBoxImage.Location = new Point(picBoxImage.Location.X - intFeinheitDerBewegungen, picBoxImage.Location.Y);
// Zusammensetzung beider gleicher Bilder, welche den Effekt haben, die Bilder ewig fortlaufend erscheinen zu lassen
if (listPicBoxAufeinanderfolgendeImages[1].Location.X <= 0)
{
imageInWinFormLadenFortsetzung();
}
}
}
// zwei PictureBoxes mit jeweils zwei gleichen Bildern werden angelegt
private void imageInWinFormLadenBeginn()
{
Bitmap bitmapImage = new Bitmap(stringBildpfad);
for (int i = 0; i < constIntAnzahlImages; i++)
{
// Bild wird in Fenster geladen
picBoxImage = new PictureBox();
picBoxImage.Image = bitmapImage;
// Bestimmung der Position und Größe des Bildes
picBoxImage.SetBounds(intPositionX, constIntPositionY, intBreite, intHoehe);
this.Controls.Add(picBoxImage);
listPicBoxAufeinanderfolgendeImages[i] = picBoxImage;
// zwei PictureBoxes mit jeweils zwei gleichen Bildern werden nebeneinander angefügt
intPositionX += intBreite;
}
}
// Wiederholte Nutzung der PictureBoxes
private void imageInWinFormLadenFortsetzung()
{
// erste PictureBox mit Image wird wieder auf ihren Anfangswert "0" gesetzt - Gewährleistung der endlos laufenden Bilder
picBoxImage = listPicBoxAufeinanderfolgendeImages[0];
picBoxImage.SetBounds(intPositionX = 0, constIntPositionY, intBreite, intHoehe);
// zweite PictureBox mit Image wird wieder auf ihren Anfangswert "intBreite" gesetzt - Gewährleistung der endlos laufenden Bilder
picBoxImage = listPicBoxAufeinanderfolgendeImages[1];
picBoxImage.SetBounds(intPositionX = intBreite, constIntPositionY, intBreite, intHoehe);
}
}