winforms 如何将listBox中的项目着色为不同的颜色?设置DataSource属性后,无法修改项集合

z18hc3ub  于 2023-01-02  发布在  其他
关注(0)|答案(1)|浏览(106)

在listBox1属性的设计器中,我将DrawMode设置为OwnerDrawFixed
然后添加这个类来着色:

public class MyListBoxItem
        {
            public MyListBoxItem(Color c, string m)
            {
                ItemColor = c;
                Message = m;
            }
            public Color ItemColor { get; set; }
            public string Message { get; set; }
        }

添加了DrawItem的事件:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
        {
            MyListBoxItem item = listBox1.Items[e.Index] as MyListBoxItem; // Get the current item and cast it to MyListBoxItem
            if (item != null)
            {
                e.Graphics.DrawString( // Draw the appropriate text in the ListBox
                    item.Message, // The message linked to the item
                    listBox1.Font, // Take the font from the listbox
                    new SolidBrush(item.ItemColor), // Set the color 
                    0, // X pixel coordinate
                    e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.
                );
            }
            else
            {
                // The item isn't a MyListBoxItem, do something about it
            }
        }

然后我尝试在构造函数中添加一些测试项:每个项目都应该是另一种颜色:

listBox1.Items.Add(new MyListBoxItem(Colors.Green, "Validated data successfully"));
listBox1.Items.Add(new MyListBoxItem(Colors.Red, "Failed to validate data"));

但在第一个listBox1.Items.Add行上出现异常:
System.ArgumentException: '设置DataSource属性后,无法修改Items集合。'
这是完整的代码:

using Newtonsoft.Json;
using Ookii.Dialogs.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;

namespace Image_Crop
{
    public partial class Form1 : Form
    {
        Rectangle rect;
        int pixelsCounter = 0;
        Color SelectedColor = Color.LightGreen;
        List<DrawingRectangle> DrawingRects = new List<DrawingRectangle>();
        Bitmap rectImage;
        int saveRectanglesCounter = 1;
        bool drawBorder = true;
        bool clearRectangles = true;
        bool saveRectangles = true;
        string rectangleName;
        Dictionary<string, string> FileList = new Dictionary<string, string>();
        string selectedPath;
        int x, y;
        private bool crop = false;

        public Form1()
        {
            InitializeComponent();

            textBox1.Text = Properties.Settings.Default.ImageToCropFolder;
            textBox2.Text = Properties.Settings.Default.CroppedImagesFolder;

            selectedPath = textBox2.Text;

            if (textBox1.Text != "")
            {
                Bitmap bmp = new Bitmap(Image.FromFile(textBox1.Text),
                    pictureBox2.Width, pictureBox2.Height);
                pictureBox2.Image = bmp;
            }
            
            checkBoxDrawBorder.Checked = true;
            checkBoxClearRectangles.Checked = true;
            checkBoxSaveRectangles.Checked = true;

            if (selectedPath != "" && selectedPath != null)
            {
                if (System.IO.File.Exists(Path.Combine(selectedPath, "rectangles.txt")))
                {
                    string g = System.IO.File.ReadAllText(Path.Combine(selectedPath, "rectangles.txt"));
                    g = g.Remove(0, 32);
                    
                    FileList = JsonConvert.DeserializeObject<Dictionary<string, string>>(g);
                    listBox1.DataSource = FileList.Keys.ToList();
                    label2.Text = listBox1.Items.Count.ToString();
                    listBox1.SelectedIndex = listBox1.Items.Count - 1;
                }
                else
                {
                    label2.Text = "0";
                }
            }
            else
            {
                label2.Text = "0";
            }

            if ((selectedPath != "" && selectedPath != null) && textBox1.Text != "")
            {
                crop = true;
            }
            else
            {
                crop = false;
            }

            listBox1.Items.Add(new MyListBoxItem(Color.Green, "Validated data successfully"));
            listBox1.Items.Add(new MyListBoxItem(Color.Red, "Failed to validate data"));
        }

        public class DrawingRectangle
        {
            public Rectangle Rect => new Rectangle(Location, Size);
            public Size Size { get; set; }
            public Point Location { get; set; }
            public Control Owner { get; set; }
            public Point StartPosition { get; set; }
            public Color DrawingcColor { get; set; } = Color.LightGreen;
            public float PenSize { get; set; } = 3f;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void pictureBox2_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || crop == false) return;

            x = 0;
            y = 0;

            if (pictureBox2.Image != null && selectedPath != null)
            {
                if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))
                {
                    DrawingRects.Add(new DrawingRectangle()
                    {
                        Location = e.Location,
                        Size = Size.Empty,
                        StartPosition = e.Location,
                        Owner = (Control)sender,
                        DrawingcColor = SelectedColor
                    });
                }
            }
        }

        private void pictureBox2_MouseMove(object sender, MouseEventArgs e)
        {
            int X = e.X;
            int Y = e.Y;

            if (e.Button != MouseButtons.Left || crop == false) return;

            if ((X >= 0 && X <= pictureBox2.Width) && (Y >= 0 && Y <= pictureBox2.Height))
            {
                if (pictureBox2.Image != null && selectedPath != null && DrawingRects.Count > 0)
                {
                    if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))
                    {
                        x = e.X;
                        y = e.Y;

                        var dr = DrawingRects[DrawingRects.Count - 1];
                        if (e.Y < dr.StartPosition.Y) { dr.Location = new Point(dr.Rect.Location.X, e.Y); }
                        if (e.X < dr.StartPosition.X) { dr.Location = new Point(e.X, dr.Rect.Location.Y); }

                        dr.Size = new Size(Math.Abs(dr.StartPosition.X - e.X), Math.Abs(dr.StartPosition.Y - e.Y));
                        pictureBox2.Invalidate();
                    }
                }
            }

        }

        int count = 0;
        private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || crop == false) return;

            if (DrawingRects.Count > 0 && pictureBox2.Image != null && selectedPath != "")
            {
                if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))
                {
                    var dr = DrawingRects.Last();
                    if (dr.Rect.Width > 0 && dr.Rect.Height > 0)
                    {
                        rectImage = cropAtRect((Bitmap)pictureBox2.Image, dr.Rect);

                        if (saveRectangles)
                        {
                            count++;
                            rectangleName = GetNextName(Path.Combine(selectedPath, "Rectangle"), ".bmp");
                            FileList.Add($"{dr.Location}, {dr.Size}", rectangleName);
                            string json = JsonConvert.SerializeObject(
        FileList,
        Formatting.Indented
    );
                            using (StreamWriter sw = new StreamWriter(Path.Combine(selectedPath, "rectangles.txt"), false))
                            {
                                sw.WriteLine("Total number of rectangles: " + count + Environment.NewLine);
                                sw.Write(json);
                                sw.Close();
                            }

                            rectImage.Save(rectangleName);
                            saveRectanglesCounter++;
                        }
                        else
                        {
                            var stream = ToMemoryStream(rectImage);
                            var image  = System.Drawing.Image.FromStream(stream);
                            pictureBox1.Image = image;
                        }
                        
                        pixelsCounter = rect.Width * rect.Height;
                        pictureBox1.Invalidate();
                        listBox1.DataSource = FileList.Keys.ToList();
                        listBox1.SelectedIndex = listBox1.Items.Count - 1;

                        pictureBox2.Focus();
                        Graphics g = Graphics.FromImage(this.pictureBox1.Image);
                        g.Clear(this.pictureBox1.BackColor);
                    }
                }
                else
                {
                    if (clearRectangles)
                    {
                        DrawingRects.Clear();
                        pictureBox2.Invalidate();
                    }

                    x = 0;
                    y = 0;
                }
            }
        }

        public class MyListBoxItem
        {
            public MyListBoxItem(Color c, string m)
            {
                ItemColor = c;
                Message = m;
            }
            public Color ItemColor { get; set; }
            public string Message { get; set; }
        }

        public MemoryStream ToMemoryStream(Bitmap b)
        {
            MemoryStream ms = new MemoryStream();
            b.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            return ms;
        }

        string GetNextName(string baseName, string extension)
        {
            int counter = 1;
            string nextName = baseName + counter + extension;
            while (System.IO.File.Exists(nextName))
            {
                counter++;
                nextName = baseName + counter + extension;
            }
            return nextName;
        }

        private void pictureBox2_Paint(object sender, PaintEventArgs e)
        {
            if (drawBorder)
            {
                ControlPaint.DrawBorder(e.Graphics, pictureBox2.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
            }

            if (pictureBox2.Image != null && selectedPath != null && DrawingRects.Count > 0)
            {
                DrawShapes(e.Graphics);
            }
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (drawBorder)
            {
                ControlPaint.DrawBorder(e.Graphics, pictureBox1.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);
            }

            if (rectImage != null && DrawingRects.Count > 0)
            {
                var dr = DrawingRects.Last();
                e.Graphics.DrawImage(rectImage, dr.Rect);

                if (clearRectangles)
                {
                    DrawingRects.Clear();
                    pictureBox2.Invalidate();
                }
            }
        }

        private void DrawShapes(Graphics g)
        {
            if (DrawingRects.Count == 0) return;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            foreach (var dr in DrawingRects)
            {
                if (dr.Rect.Width > 0 && dr.Rect.Height > 0)
                {
                    using (Pen pen = new Pen(dr.DrawingcColor, dr.PenSize))
                    {
                        g.DrawRectangle(pen, dr.Rect);
                    };
                }
            }
        }

        public Bitmap cropAtRect(Bitmap b, Rectangle r)
        {
            Bitmap nb = new Bitmap(r.Width, r.Height);
            using (Graphics g = Graphics.FromImage(nb))
            {
                g.DrawImage(b, -r.X, -r.Y);
                return nb;
            }
        }

        private void checkBoxDrawBorder_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxDrawBorder.Checked)
            {
                drawBorder = true;
            }
            else
            {
                drawBorder = false;
            }

            pictureBox1.Invalidate();
            pictureBox2.Invalidate();
        }

        private void checkBoxClearRectangles_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxClearRectangles.Checked)
            {
                clearRectangles = true;
            }
            else
            {
                clearRectangles = false;
            }

            pictureBox2.Invalidate();
        }

        private void checkBoxSaveRectangles_CheckedChanged(object sender, EventArgs e)
        {
            if(checkBoxSaveRectangles.Checked)
            {
                saveRectangles = true;
            }
            else
            {
                saveRectangles = false;
            }
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            var item = ((ListBox)sender).SelectedItem;
            var val = FileList[(string)item];
            if (File.Exists(val))
            {
                pictureBox1.Image = System.Drawing.Image.FromFile(val);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            VistaOpenFileDialog dialog = new VistaOpenFileDialog();
            {
                dialog.Filter = "Images (*.jpg, *.bmp, *.gif)|*.jpg;*.bmp;*.gif";
            };

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = dialog.FileName;

                Properties.Settings.Default.ImageToCropFolder = dialog.FileName;
                Properties.Settings.Default.Save();

                Bitmap bmp = new Bitmap(Image.FromFile(dialog.FileName),
                    pictureBox2.Width, pictureBox2.Height);
                pictureBox2.Image = bmp;

                if(textBox1.Text != "" && textBox2.Text != "")
                {
                    crop = true;
                }
            }
        }

        private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
        {
            MyListBoxItem item = listBox1.Items[e.Index] as MyListBoxItem; // Get the current item and cast it to MyListBoxItem
            if (item != null)
            {
                e.Graphics.DrawString( // Draw the appropriate text in the ListBox
                    item.Message, // The message linked to the item
                    listBox1.Font, // Take the font from the listbox
                    new SolidBrush(item.ItemColor), // Set the color 
                    0, // X pixel coordinate
                    e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.
                );
            }
            else
            {
                // The item isn't a MyListBoxItem, do something about it
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            VistaFolderBrowserDialog dialog = new VistaFolderBrowserDialog();

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                textBox2.Text = dialog.SelectedPath;
                selectedPath = dialog.SelectedPath;

                Properties.Settings.Default.CroppedImagesFolder = selectedPath;
                Properties.Settings.Default.Save();

                if (textBox1.Text != "" && textBox2.Text != "")
                {
                    crop = true;
                }
            }
        }
    }
}
evrscar2

evrscar21#

您的问题是**如何将listBox中的项目着色为不同的颜色?**而X-Y Problem的“Y”可能是当您尝试内联添加项目时会得到异常。仔细阅读代码后,在DataSource和Json序列化和反序列化中一致地使用MyListBoxItem类型会带来很大的不同。然后在希望添加内联项时追加数据源。

数据源

BindingList<MyListBoxItem> MyItems { get; } = new BindingList<MyListBoxItem>();

磁盘文件中JSON序列化形式的MyItems示例

[
  {
    "ItemColor": "Blue",
    "Message": "Blue Item"
  },
  {
    "ItemColor": "Green",
    "Message": "Green Item"
  },
  {
    "ItemColor": "Red",
    "Message": "Red Item"
  }
]

其中:

public class MyListBoxItem
{ 
    public Color ItemColor { get; set; }
    public string Message { get; set; }
}

listBox1绘图代码的主窗体初始化

public partial class MainForm : Form
{
    public MainForm() => InitializeComponent();
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        listBox1.DisplayMember = nameof(MyListBoxItem.Message);
        listBox1.DataSource = MyItems;
        listBox1.DrawItem += onDrawItem;
        listBox1.DrawMode = DrawMode.OwnerDrawFixed;
        listBox1.SelectedIndexChanged += (sender, e) => listBox1.Refresh();

        // Tests
        buttonTest.Click += onButtonTest;
        buttonReadJson.Click += onButtonReadJson;
    }
    private void onDrawItem(object sender, DrawItemEventArgs e)
    {
        if((e.Index == -1) || (e.Index >= MyItems.Count))
        {                
            e.DrawBackground();
        }
        else
        {
            var myItem = MyItems[e.Index];
            if (listBox1.SelectedItems.Contains(myItem))
            {
                using (var backgroundBrush = new SolidBrush(myItem.ItemColor))
                {
                    e.Graphics.FillRectangle(backgroundBrush, e.Bounds);
                }

                using (var textBrush = new SolidBrush(Color.White))
                {
                    e.Graphics.DrawString(myItem.Message, listBox1.Font, textBrush, e.Bounds);
                }
            }
            else
            {
                using (var backgroundBrush = new SolidBrush(SystemColors.Window))
                {
                    e.Graphics.FillRectangle(backgroundBrush, e.Bounds);
                }
                using (var textBrush = new SolidBrush(myItem.ItemColor))
                {
                    e.Graphics.DrawString(myItem.Message, listBox1.Font, textBrush, e.Bounds);
                }
            }
        }
    }
    BindingList<MyListBoxItem> MyItems { get; } = new BindingList<MyListBoxItem>();
    .
    .
    .
}

添加项目示例

private void onButtonTest(object sender, EventArgs e)
{
    MyItems.Clear();
    MyItems.Add(new MyListBoxItem
    {
        Message = "Validated data successfully",
        ItemColor = Color.Green,
    });
    MyItems.Add(new MyListBoxItem
    {
        Message = "Failed to validate data",
        ItemColor = Color.Red,
    });
}

反序列化文件的示例

private void onButtonReadJson(object sender, EventArgs e)
{
    MyItems.Clear();
    foreach (
        var myItem 
        in JsonConvert.DeserializeObject<List<MyListBoxItem>>(mockFileContents))
    {
        MyItems.Add(myItem);
    }
}

const string mockFileContents = 
@"[
  {
    ""ItemColor"": ""Blue"",
    ""Message"": ""Blue Item""
  },
  {
    ""ItemColor"": ""Green"",
    ""Message"": ""Green Item""
  },
  {
    ""ItemColor"": ""Red"",
    ""Message"": ""Red Item""
  }
]";

相关问题