WinForms中如何创建可存入数组并删除的叠加图像对象?
WinForms图像分层叠加程序:叠加图像无法删除的解决方案
问题描述
开发一款WinForms图像分层叠加程序,需求如下:
- 将叠加图像以对象形式存入集合,方便后续管理
- 通过列表选中指定叠加图像后,点击删除按钮移除该图像
目前已实现背景图功能,但添加叠加图像转为Bitmap后无法精准删除已叠加的图像,现有代码如上。
核心问题分析
当前代码直接将PictureBox添加到Strats.Controls中,但未维护独立集合追踪这些叠加图像对象,也未建立列表项与对应图像的关联,导致无法定位并删除指定叠加图像;同时直接引用Resources中的图像可能引发资源锁定问题。
修改方案与完整代码
1. 创建叠加图像实体类
封装叠加图像的名称与对应的PictureBox,实现列表项与图像的关联:
public class OverlayImage { public string Name { get; set; } public PictureBox PictureBox { get; set; } }
2. 完整修改后的Form代码
using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; namespace BattlePlannerTryTwo { public class OverlayImage { public string Name { get; set; } public PictureBox PictureBox { get; set; } } public partial class Form1 : Form { private Image file; private Image Mapfile; private List<OverlayImage> _overlayImages = new List<OverlayImage>(); public Form1() { InitializeComponent(); Strats.SizeMode = PictureBoxSizeMode.Zoom; textBox1.Location = new Point(); } private void Form1_Load(object sender, EventArgs e) { // 初始化控件布局 Strats.Width = this.Width - 400; Strats.Height = this.Height - 90; ObjectListView.Width = 300; ObjectListView.Height = this.Height - 70; ObjectListView.Location = new Point(this.Width - 330, 10); textBox2.Location = new Point(200, this.Height - 70); textBox1.Location = new Point(12, this.Height - 70); OperatorComboBox.Location = new Point(100, this.Height - 70); MapComboBox.Location = new Point(290, this.Height - 70); SaveBtn.Location = new Point(390, this.Height - 70); ClearPageBtn.Location = new Point(450, this.Height - 70); // 添加删除按钮(若窗体已存在则无需此段) Button deleteBtn = new Button(); deleteBtn.Text = "删除选中项"; deleteBtn.Location = new Point(520, this.Height - 70); deleteBtn.Click += DeleteBtn_Click; this.Controls.Add(deleteBtn); } private void StratBox_Click(object sender, EventArgs e) { if (file == null || OperatorComboBox.SelectedItem == null) return; // 创建独立Bitmap实例,避免资源锁定 Bitmap bitmap = new Bitmap(file); PictureBox operatorBox = new PictureBox(); operatorBox.Image = bitmap; operatorBox.Width = 100; operatorBox.Height = 100; // 转换为PictureBox内部坐标,确保图像添加到点击位置 Point clientPoint = Strats.PointToClient(MousePosition); operatorBox.Location = new Point(clientPoint.X - 50, clientPoint.Y - 50); operatorBox.SizeMode = PictureBoxSizeMode.Zoom; // 创建叠加图像对象并加入集合 string operatorName = OperatorComboBox.SelectedItem.ToString(); OverlayImage overlay = new OverlayImage { Name = operatorName, PictureBox = operatorBox }; _overlayImages.Add(overlay); Strats.Controls.Add(operatorBox); ObjectListView.Items.Add(operatorName); } private void OperatorComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (OperatorComboBox.SelectedItem == null) return; string selectedOperator = OperatorComboBox.SelectedItem.ToString(); // 使用switch表达式简化大量if-else逻辑 file = selectedOperator switch { "Ace" => new Bitmap(Properties.Resources.ace), "Alibi" => new Bitmap(Properties.Resources.alibi), "Amaru" => new Bitmap(Properties.Resources.amaru), "Aruni" => new Bitmap(Properties.Resources.aruni), "Ash" => new Bitmap(Properties.Resources.ash), "Azami" => new Bitmap(Properties.Resources.azami), "Bandit" => new Bitmap(Properties.Resources.bandit), "Blackbeard" => new Bitmap(Properties.Resources.blackbeard), "Blitz" => new Bitmap(Properties.Resources.blitz), "Buck" => new Bitmap(Properties.Resources.buck), "Capitao" => new Bitmap(Properties.Resources.capitao), "Castle" => new Bitmap(Properties.Resources.castle), "Caveira" => new Bitmap(Properties.Resources.caveira), "Clash" => new Bitmap(Properties.Resources.clash), "Doc" => new Bitmap(Properties.Resources.doc), "Dokkaebi" => new Bitmap(Properties.Resources.dokkaebi), "Echo" => new Bitmap(Properties.Resources.echo), "Ela" => new Bitmap(Properties.Resources.ela), "Finka" => new Bitmap(Properties.Resources.finka), "Flores" => new Bitmap(Properties.Resources.flores), "Frost" => new Bitmap(Properties.Resources.frost), "Fuze" => new Bitmap(Properties.Resources.fuze), "Glaz" => new Bitmap(Properties.Resources.glaz), "Goyo" => new Bitmap(Properties.Resources.goyo), "Gridlock" => new Bitmap(Properties.Resources.gridlock), "Grim" => new Bitmap(Properties.Resources.grim), "Hibana" => new Bitmap(Properties.Resources.hibana), "Iana" => new Bitmap(Properties.Resources.iana), "IQ" => new Bitmap(Properties.Resources.iq), "Jackal" => new Bitmap(Properties.Resources.jackal), "Jager" => new Bitmap(Properties.Resources.jager), "Kaid" => new Bitmap(Properties.Resources.kaid), "Kali" => new Bitmap(Properties.Resources.kali), "Kapkan" => new Bitmap(Properties.Resources.kapkan), "Lesion" => new Bitmap(Properties.Resources.lesion), "Lion" => new Bitmap(Properties.Resources.lion), "Maestro" => new Bitmap(Properties.Resources.maestro), "Maverick" => new Bitmap(Properties.Resources.maverick), "Melusi" => new Bitmap(Properties.Resources.melusi), "Mira" => new Bitmap(Properties.Resources.mira), "Montagne" => new Bitmap(Properties.Resources.montagne), "Mozzie" => new Bitmap(Properties.Resources.mozzie), "Mute" => new Bitmap(Properties.Resources.mute), "Nokk" => new Bitmap(Properties.Resources.nokk), "Nomad" => new Bitmap(Properties.Resources.nomad), "Oryx" => new Bitmap(Properties.Resources.oryx), "Osa" => new Bitmap(Properties.Resources.osa), "Pulse" => new Bitmap(Properties.Resources.pulse), "Rook" => new Bitmap(Properties.Resources.rook), "Sens" => new Bitmap(Properties.Resources.sens), "Sledge" => new Bitmap(Properties.Resources.sledge), "Smoke" => new Bitmap(Properties.Resources.smoke), "Solis" => new Bitmap(Properties.Resources.solis), "Tachanka" => new Bitmap(Properties.Resources.tachanka), "Thatcher" => new Bitmap(Properties.Resources.thatcher), "Thermite" => new Bitmap(Properties.Resources.thermite), "Thorn" => new Bitmap(Properties.Resources.thorn), "Thunderbird" => new Bitmap(Properties.Resources.thunderbird), "Twitch" => new Bitmap(Properties.Resources.twitch), "Valkyrie" => new Bitmap(Properties.Resources.valkyrie), "Vigil" => new Bitmap(Properties.Resources.vigil), "Wamai" => new Bitmap(Properties.Resources.wamai), "Warden" => new Bitmap(Properties.Resources.warden), "Ying" => new Bitmap(Properties.Resources.ying), "Zero" => new Bitmap(Properties.Resources.zero), "Zofia" => new Bitmap(Properties.Resources.zofia), _ => file }; } private void textBox1_TextChanged(object sender, EventArgs e) { // 暂不处理 } private void MapComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (MapComboBox.SelectedItem == null) return; string selectedMap = MapComboBox.SelectedItem.ToString(); Mapfile = selectedMap switch { "Oragan Basement" => new Bitmap(Properties.Resources.OraganBasement), "Oragan Kids" => new Bitmap(Properties.Resources.OraganKids), _ => Mapfile }; Strats.Image = Mapfile; } private void SaveBtn_Click(object sender, EventArgs e) { // 可在此实现保存逻辑:将背景图与所有叠加图像合并后保存 } private void ClearPageBtn_Click(object sender, EventArgs e) { // 清空所有叠加图像并释放资源 foreach (var overlay in _overlayImages) { Strats.Controls.Remove(overlay.PictureBox); overlay.PictureBox.Image.Dispose(); overlay.PictureBox.Dispose(); } _overlayImages.Clear(); ObjectListView.Items.Clear(); } private void DeleteBtn_Click(object sender, EventArgs e) { if (ObjectListView.SelectedItems.Count == 0) return; string selectedName = ObjectListView.SelectedItems[0].Text; // 根据列表项名称找到对应的叠加图像 OverlayImage targetOverlay = _overlayImages.FirstOrDefault(o => o.Name == selectedName); if (targetOverlay != null) { // 从控件移除并释放资源 Strats.Controls.Remove(targetOverlay.PictureBox); targetOverlay.PictureBox.Image.Dispose(); targetOverlay.PictureBox.Dispose(); // 从集合与列表中移除 _overlayImages.Remove(targetOverlay); ObjectListView.Items.Remove(ObjectListView.SelectedItems[0]); } } private void DisplayImage() { } private void Strats_Paint(object sender, PaintEventArgs e) { } } }
关键改进点
- 集合追踪:使用
List<OverlayImage>存储所有叠加图像,确保每个图像对象可被精准定位 - 资源管理:创建Bitmap独立实例并在删除时调用
Dispose(),避免资源锁定与内存泄漏 - 坐标修正:将屏幕坐标转换为
Strats内部坐标,确保图像添加到点击的正确位置 - 代码简化:用
switch表达式替代大量if-else,提升代码可读性与维护性
内容的提问来源于stack exchange,提问作者Cory G
相关产品推荐
相关产品推荐

