C# PictureBox.Invalidate未正确重新渲染
我正在尝试构建一个小的测试应用程序(我的WinForm技能已经有些生锈),上面有一个图像和一些覆盖层 我的图像在PictureBox中设置为拉伸,但我右侧的字段希望来自图像的原点。因此,我决定直接在PictureBox使用的图像上渲染,以确保坐标始终正确。以下是白盒渲染:C# PictureBox.Invalidate未正确重新渲染,c#,winforms,C#,Winforms,我正在尝试构建一个小的测试应用程序(我的WinForm技能已经有些生锈),上面有一个图像和一些覆盖层 我的图像在PictureBox中设置为拉伸,但我右侧的字段希望来自图像的原点。因此,我决定直接在PictureBox使用的图像上渲染,以确保坐标始终正确。以下是白盒渲染: private void pbImage_Paint(object sender, PaintEventArgs e) { try { if (this.r
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高度和宽度)。尝试重新调整大小以查看所需的效果 控件和窗体已经有了
刷新
方法。你真的在调用你的刷新
方法吗?难道你没有收到警告,说你应该使用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\u Paint
方法
另一种可能是以另一种方式使用事件处理程序。调用绘制图像但保持图像本身不变的图片框的
base.Paint()
处理程序。而是使用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));
}
}
我真的不完全理解这个问题。对不起。但是,为什么不直接在PictureBox中绘制呢?好的,如果您决定在
Image
中绘制,那么您需要绘制一次,缓存图像并显示它。无论何时更新值,都需要使缓存无效。另外,我也不确定Refresh
方法中的front
和back
来自何处。@SriramSakthivel:front/back,因为我有两个图像可以切换。直接绘制到PictureBox的问题是坐标0,0可能不在图像上(因为PictureBox已经缩放并居中),而在图像上它会。@SriramSakthivel:我已经添加了项目的下载链接-认为它可能有用。这是真的-但不是问题所在。