我正在尝试构建一个小测试应用程序(并且我的WinForm技能已经有点生锈),并在其上面添加了一个Image和一些叠加层。
我的图像设置为在PictureBox中拉伸,但我右侧的字段我想要来自图像的原点。因此,我决定直接渲染PictureBox正在使用的图像,以确保坐标始终正确。这是白框渲染:
private void pbImage_Paint(object sender, PaintEventArgs e)
{
try
{
if (this.rdFront.Checked)
RenderFront(pbImage.Image, true);
else
RenderBack(pbImage.Image, true);
}
catch (ArgumentNullException ex)
{ }
}
public void RenderFront(Image image, bool includeBoxes)
{
// If we have no image then we can't render
if (image == null)
throw new ArgumentNullException("image");
Graphics gfx = Graphics.FromImage(image);
// Get the top label
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes)
{
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
我遇到的问题是如果我这样做并且总是在底层图像上绘制,那么当我移动白色叠加层时,我最终会得到未绘制的图像部分。所以我决定在每次重新渲染之前克隆图像(基于我不关心性能)。
因此,我决定在需要手动使其无效时克隆图像,并在设置更改时调用此图像:
public void Refresh()
{
if (this.rdFront.Checked)
pbImage.Image = new Bitmap(front);
else
pbImage.Image = new Bitmap(back);
this.pbImage.Invalidate();
}
现在我确定我必须遗漏一些明显的东西 - 如果我修改了我的企鹅渲染的其中一个没有叠加的值。但是,如果我强制调整应用程序的大小,那么企鹅和叠加层都会突然出现。
任何人都可以提出我可能做错的建议吗?
修改
这是项目的下载链接,因为它非常小。将图像路径粘贴到“正面图像”框中,然后尝试使用右侧的控件(设置100x100高度和宽度)。尝试重新调整大小以查看所需的效果。 https://dl.dropboxusercontent.com/u/41796243/TemplateTester.zip
答案 0 :(得分:2)
控件和表单已经有Refresh
方法。你真的打电话给你的 Refresh
方法吗?您是否收到警告,表示您应该使用new
关键字?最好为您的Refresh
方法添加其他名称(例如RefreshImage
)!
我真的不确定你为什么要使用一个图片框,但后来决定做你的绘画。我建议在屏幕外绘制一个图像,然后将其分配到图片框中:
public void RefreshImage()
{
Bitmap bmp;
if (this.rdFront.Checked)
bmp = new Bitmap(front);
else
bmp = new Bitmap(back);
using (Graphics gfx = Graphics.FromImage(bmp)) {
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes) {
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
pbImage.Image = bmp;
}
并删除pbImage_Paint
方法。
另一种可能性是以另一种方式使用pbImage_Paint
事件处理程序。调用绘制图像的图片框的base.Paint()
处理程序,但保持图像本身不变。而是使用Graphics
参数给出的PaintEventArgs e
对象在其上绘制。此Graphics对象表示图片框的客户区。这不会改变分配给图片框的位图,而只会在屏幕上绘制。
private void pbImage_Paint(object sender, PaintEventArgs e)
{
base.Paint(); // Paints the image
if (this.rdFront.Checked)
RenderFront(e.Graphics, true);
else
RenderBack(e.Graphics, true);
}
public void RenderFront(Graphics g, bool includeBoxes)
{
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front)) {
if (includeBoxes) {
g.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
g.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
g.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}