0

我正在为我的缩略图 UserControl 完成代码,其中一项要求是能够在任何时候加载多达 3,000 张图像。可以想象,如果没有线程,这将使控件在实时环境中几乎毫无用处,因为加载它们可能需要相当长的时间,并且此时用户被冻结在任何使用该控件的程序之外。

我是线程新手,我所看到和尝试的要求我更改 GenerateThumbnails 的签名并生成错误(不包含在此代码中)。

我想知道的是,在将图像加载到 PictureBox 中时,我将如何实现线程以允许用户交互。

此控件的代码如下(我将其全部包含在内) - 更新为实现了 BackgroundWorker。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ImageViewerPlus
{

    public partial class Filmstrip : UserControl
    {

        //private BackgroundWorker bwAsyncWorker = new BackgroundWorker();

        public Filmstrip()
        {
            InitializeComponent();
            log = log + "Initialized Filmstrip Form: \r\n";
            //bwAsyncWorker.WorkerReportsProgress = true;
            //bwAsyncWorker.WorkerSupportsCancellation = true;
            //bwAsyncWorker.ProgressChanged += new ProgressChangedEventHandler(bwAsync_ProgressChanged);
            //bwAsyncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwAsync_RunWorkerCompleted);
            //bwAsyncWorker.DoWork += new DoWorkEventHandler(bwAsync_DoWork);

            toolStripProgressBar1.Minimum = 0;
            toolStripProgressBar1.Maximum = 100;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            SolidBrush b = new SolidBrush(this.BackColor);
            pe.Graphics.FillRectangle(b, this.ClientRectangle);
        }

        public string log;
        private string selectedImagePath;
        private List<PictureBox> pictureBoxes;
        private List<string> imagePaths;
        private int imageCount;
        private int selectedImageIndex;
        private int pictureBoxIndex;
        private int oldSelectedImageIndex;


        public SelectedImageDelegate SelectedImageCallback;

        private static int THUMBNAIL_SIZE = 100;

        private List<PictureBox> PictureBoxes
        {
            set
            {
                pictureBoxes = value;
            }
            get
            {
                return pictureBoxes;
            }
        }

        public List<string> ImagePaths
        {
            set
            {
                imagePaths = value;
            }
            get
            {
                return imagePaths;
            }
        }

        private int ImageCount
        {
            set
            {
                imageCount = value;
            }
            get
            {
                return imageCount;
            }
        }

        public int SelectedImageIndex
        {
            set
            {
                selectedImageIndex = value;
            }
            get
            {
                return selectedImageIndex;
            }
        }

        public string SelectedImagePath
        {
            set
            {
                selectedImagePath = value;
            }
            get
            {
                return selectedImagePath;
            }
        }

        private int PictureBoxIndex
        {
            set
            {
                pictureBoxIndex = value;
            }
            get
            {
                return pictureBoxIndex;
            }
        }

        public void GenerateThumbnails(List<string> images)
        {
            log = log + "GenerateThumbnails() Entered: \r\n";
            ImagePaths = images;
            ImageCount = ImagePaths.Count;
            int pictureBoxTopInterval = THUMBNAIL_SIZE + 4;
            int pictureBoxLeftInterval = THUMBNAIL_SIZE + 4;
            int thumbnailColumns = this.panelDoubleBuffered1.Width / (THUMBNAIL_SIZE);
            int remainder;
            int thumbnailRows = Math.DivRem(ImageCount, thumbnailColumns, out remainder);
            int thumbnailBreak = 0;

            if (remainder > 0)
            {
                thumbnailRows = thumbnailRows + 1;
            }

            PictureBoxes = new List<PictureBox>();
            pictureBoxIndex = 0;

            log = log + "Generating PictureBox array: \r\n";
            for (int i = 0; i < thumbnailRows; i = i + 1)
            {
                log = log + "Row " + i.ToString() + ", Column ";
                for (int j = 0; j < thumbnailColumns; j = j + 1)
                {
                    log = log + j.ToString() + ", ";
                    if (thumbnailBreak == ImageCount)
                    {
                        break;
                    }
                    else
                    {
                        PictureBox nextPictureBox = new PictureBox();

                        PictureBoxes.Add(nextPictureBox);

                        PictureBoxes[PictureBoxIndex].ImageLocation = ImagePaths[PictureBoxIndex];
                        PictureBoxes[PictureBoxIndex].Parent = panelDoubleBuffered1;
                        PictureBoxes[PictureBoxIndex].Width = THUMBNAIL_SIZE;
                        PictureBoxes[PictureBoxIndex].Height = THUMBNAIL_SIZE;
                        PictureBoxes[PictureBoxIndex].Tag = pictureBoxes[PictureBoxIndex].ImageLocation;
                        PictureBoxes[PictureBoxIndex].Top = 3 + (i * pictureBoxTopInterval);
                        PictureBoxes[PictureBoxIndex].Left = 3 + (j * pictureBoxLeftInterval);
                        PictureBoxes[PictureBoxIndex].Show();
                        PictureBoxes[PictureBoxIndex].Click += new EventHandler(OnButtonClick);
                        PictureBoxIndex = PictureBoxIndex + 1;
                        this.Refresh();
                        thumbnailBreak = thumbnailBreak + 1;
                    }
                }
                log = log + ": Initialised\r\n";
            }

            PictureBoxIndex = 0;
            log = log + "if (bwAsyncWorker.IsBusy) - ";
            if (bwAsyncWorker.IsBusy)
            {
                log = log + "bgw is busy: \r\n";
                //toolStripStatusLabel1.Text = "Cancelling...";
                //bwAsyncWorker.CancelAsync();
            }
            else
            {
                toolStripStatusLabel1.Text = "Loading...";
                log = log + "bwAsyncWorker.RunWorkerAsync(); - ";
                bwAsyncWorker.RunWorkerAsync();
            }
        }

        private void bwAsync_DoWork(object sender, DoWorkEventArgs e)
        {
            log = log + "Executed:\r\n";
            BackgroundWorker bwAsync = sender as BackgroundWorker;

            for (int i = 0; i < ImageCount; i = i + 1)
            {
                try
                {
                    log = log + "bwAsync.ReportProgress(Convert.ToInt32(i * (100.0 / ImageCount))); - ";
                    bwAsync.ReportProgress(Convert.ToInt32(i * (100.0 / ImageCount)));
                    log = log + "Executed:\r\n";

                    log = log + "ProgressBar updated to: " + (Convert.ToInt32(i * (100.0 / ImageCount))) + "\r\n";

                    log = log + "Image " + i.ToString();
                    PictureBoxes[i].Load();
                    log = log + " Has Loaded\r\n";

                    log = log + "SetImage(PictureBoxes[i]); - ";
                    SetImage(PictureBoxes[i]);
                    log = log + "Executed:\r\n";

                    if (bwAsync.CancellationPending)
                    {
                        log = log + "e.Cancel = true; - ";
                        e.Cancel = true;
                        log = log + "Executed\r\n";

                        log = log + "return;\r\n";
                        return;
                    }

                }
                catch
                {
                }
            }
        }

        private void bwAsync_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                log = log + "RunWorkerComplete: " + e.Error.Message + "\r\n";
                MessageBox.Show(e.Error.Message);
                return;
            }

            if (e.Cancelled)
            {
                log = log + "RunWorkerComplete: Cancelled...\r\n";
                toolStripStatusLabel1.Text = "Cancelled...";
            }
            else
            {
                log = log + "RunWorkerComplete: Completed...\r\n";
                toolStripStatusLabel1.Text = "Completed...";
                toolStripProgressBar1.Value = 100;
            }
        }

        private void bwAsync_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            log = log + " + "; // shows that ProgressChanged was entered.
            toolStripProgressBar1.Value = e.ProgressPercentage;
            Application.DoEvents();
        }

        public void OnButtonClick(object sender, EventArgs e)
        {
            log = log + "Selected image changed to: " + SelectedImageIndex.ToString() + ": \r\n";
            oldSelectedImageIndex = SelectedImageIndex;
            SelectedImagePath = ((PictureBox)sender).Tag.ToString();
            SelectedImageCallback(SelectedImagePath);
            SelectedImageIndex = ImagePaths.IndexOf(SelectedImagePath);
            oldSelectedImageIndex = SelectedImageIndex;
            Refresh();

            Graphics dc = this.panelDoubleBuffered1.CreateGraphics();
            Pen Redpen = new Pen(Color.Red, 2);
            dc.DrawRectangle(Redpen, PictureBoxes[SelectedImageIndex].Left - 2, PictureBoxes[SelectedImageIndex].Top - 2, 104, 104);
        }

        public static Bitmap ConvertToRGB(Bitmap original)
        {
            Bitmap newImage = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb);
            newImage.SetResolution(original.HorizontalResolution, original.VerticalResolution);
            using (Graphics g = Graphics.FromImage(newImage))
            {
                g.DrawImageUnscaled(original, 0, 0);
            }
            return newImage;
        }

        //Generate new image dimensions
        public Size GenerateImageDimensions(int currW, int currH, int destW, int destH)
        {
            //double to hold the final multiplier to use when scaling the image
            double multiplier = 0;

            //string for holding layout
            string layout;

            //determine if it's Portrait or Landscape
            if (currH > currW) layout = "portrait";
            else layout = "landscape";

            switch (layout.ToLower())
            {
                case "portrait":
                    //calculate multiplier on heights
                    if (destH > destW)
                    {
                        log = log + "multiplier = (double)destW / (double)currW;";
                        multiplier = (double)destW / (double)currW;
                        log = log + "Executed\r\n";
                    }

                    else
                    {
                        log = log + "multiplier = (double)destH / (double)currH;";
                        multiplier = (double)destH / (double)currH;
                        log = log + "Executed\r\n";
                    }
                    break;
                case "landscape":
                    //calculate multiplier on widths
                    if (destH > destW)
                    {
                        log = log + "multiplier = (double)destW / (double)currW;";
                        multiplier = (double)destW / (double)currW;
                        log = log + "Executed\r\n";
                    }

                    else
                    {
                        log = log + "multiplier = (double)destH / (double)currH;";
                        multiplier = (double)destH / (double)currH;
                        log = log + "Executed\r\n";
                    }
                    break;
            }

            //return the new image dimensions
            try
            {
                return new Size((int)(currW * multiplier), (int)(currH * multiplier));
            }
            catch (System.Exception e)
            {
                log = log + "Calling from GenerateImageDimensions(): " + e.Message;
                return new Size((int)(currW * multiplier), (int)(currH * multiplier));
            }

        }

        //Resize the image
        public void SetImage(PictureBox pb)
        {
            try
            {
                //create a temp image
                log = log + "Image imgtmp = pb.Image; - ";
                Image imgtmp = pb.Image;
                log = log + "Executed\r\n";
                //calculate the size of the image
                log = log + "Size imgSize = GenerateImageDimensions(imgtmp.Width, imgtmp.Height, pb.Width, pb.Height); - ";
                Size imgSize = GenerateImageDimensions(imgtmp.Width, imgtmp.Height, pb.Width, pb.Height);
                log = log + "Executed\r\n";

                //create a new Bitmap with the proper dimensions
                log = log + "Bitmap finalImg = new Bitmap(imgtmp, imgSize.Width, imgSize.Height);";
                Bitmap finalImg = new Bitmap(imgtmp, imgSize.Width, imgSize.Height);
                log = log + "Executed\r\n";

                log = log + "Bitmap img = ConvertToRGB(finalImg);";
                Bitmap img = ConvertToRGB(finalImg);
                log = log + "Executed\r\n";

                //create a new Graphics object from the image
                log = log + "Graphics gfx = Graphics.FromImage(img);";
                Graphics gfx = Graphics.FromImage(img);
                log = log + "Executed\r\n";

                //clean up the image (take care of any image loss from resizing)
                log = log + "gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;";
                gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
                log = log + "Executed\r\n";

                //empty the PictureBox
                log = log + "pb.Image = null;";
                pb.Image = null;
                log = log + "Executed\r\n";

                //center the new image
                log = log + "pb.SizeMode = PictureBoxSizeMode.CenterImage;";
                pb.SizeMode = PictureBoxSizeMode.CenterImage;
                log = log + "Executed\r\n";

                //set the new image
                log = log + "pb.Image = finalImg;";
                pb.Image = finalImg;
                log = log + "Executed\r\n";
            }
            catch (System.Exception e)
            {
                log = log + "Calling from SetImage: - " + e.Message + "\r\n";
                MessageBox.Show(e.Message);
            }
        }
    }
}

这是应用程序的图像,请注意一些缩略图没有调整大小,我完全无法理解为什么。

由于防止垃圾邮件,我还不能发布图片,但你可以在这里找到一张。

如果需要,我也可以提供日志输出。

4

1 回答 1

0

使用 BackgroundWorker 线程。

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    for (int i = 1; (i <= 10); i++)
    {
        if ((worker.CancellationPending == true))
        {
            e.Cancel = true;
            break;
        }
        else
        {
            // **Perform your uploads here** and report progress.
            System.Threading.Thread.Sleep(500);
            worker.ReportProgress((i * 10));
        }
    }
}
于 2012-06-26T11:25:44.133 回答