我正在为我的缩略图 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);
}
}
}
}
这是应用程序的图像,请注意一些缩略图没有调整大小,我完全无法理解为什么。
由于防止垃圾邮件,我还不能发布图片,但你可以在这里找到一张。
如果需要,我也可以提供日志输出。