我正在使用Windows窗体。很长一段时间,pictureBox.Invalidate();
努力重新绘制屏幕。但是,它现在不起作用,我不知道为什么。
this.worldBox = new System.Windows.Forms.PictureBox();
this.worldBox.BackColor = System.Drawing.SystemColors.Control;
this.worldBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.worldBox.Location = new System.Drawing.Point(170, 82);
this.worldBox.Name = "worldBox";
this.worldBox.Size = new System.Drawing.Size(261, 250);
this.worldBox.TabIndex = 0;
this.worldBox.TabStop = false;
this.worldBox.MouseMove += new
System.Windows.Forms.MouseEventHandler(this.worldBox_MouseMove);
this.worldBox.MouseDown += new
System.Windows.Forms.MouseEventHandler(this.worldBox_MouseDown);
this.worldBox.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.worldBox_MouseUp);
在我的代码中调用以适当地绘制世界:
view.DrawWorldBox(worldBox, canvas, gameEngine.GameObjectManager.Controllers,
selectedGameObjects, LevelEditorUtils.PREVIEWS);
View.DrawWorldBox:
public void DrawWorldBox(PictureBox worldBox,
Panel canvas,
ICollection<IGameObjectController> controllers,
ICollection<IGameObjectController> selectedGameObjects,
IDictionary<string, Image> previews)
{
int left = Math.Abs(worldBox.Location.X);
int top = Math.Abs(worldBox.Location.Y);
Rectangle screenRect = new Rectangle(left, top, canvas.Width,
canvas.Height);
IDictionary<float, ICollection<IGameObjectController>> layers =
LevelEditorUtils.LayersOfControllers(controllers);
IOrderedEnumerable<KeyValuePair<float,
ICollection<IGameObjectController>>> sortedLayers
= from item in layers
orderby item.Key descending
select item;
using (Graphics g = Graphics.FromImage(worldBox.Image))
{
foreach (KeyValuePair<float, ICollection<IGameObjectController>>
kv in sortedLayers)
{
foreach (IGameObjectController controller in kv.Value)
{
// ...
float scale = controller.View.Scale;
float width = controller.View.Width;
float height = controller.View.Height;
Rectangle controllerRect = new
Rectangle((int)controller.Model.Position.X,
(int)controller.Model.Position.Y,
(int)(width * scale),
(int)(height * scale));
// cull objects that aren't intersecting with the canvas
if (controllerRect.IntersectsWith(screenRect))
{
Image img = previews[controller.Model.HumanReadableName];
g.DrawImage(img, controllerRect);
}
if (selectedGameObjects.Contains(controller))
{
selectionRectangles.Add(controllerRect);
}
}
}
foreach (Rectangle rect in selectionRectangles)
{
g.DrawRectangle(drawingPen, rect);
}
selectionRectangles.Clear();
}
worldBox.Invalidate();
}
我在这里做错了什么?
答案 0 :(得分:19)
要理解这一点,你必须要了解它在操作系统级别的工作方式。
绘制Windows控件以响应WM_PAINT
消息。当他们收到此消息时,他们会绘制自己无效的部分。特定控件可能无效,控件的特定区域可能无效,这样做是为了最大限度地减少重新绘制的数量。
最终,Windows会看到某些控件需要重新绘制并向其发出WM_PAINT
条消息。但它只在处理完所有其他消息后执行此操作,这意味着Invalidate
不会强制立即重绘。 Refresh
技术上应该,但并不总是可靠的。 (更新:这是因为Refresh
是virtual
并且在野外存在某些控件,这些控件使用不正确的实现覆盖此方法。)
有一种方法 通过发出WM_PAINT
消息强制立即绘制,即Control.Update
。因此,如果您想强制立即重绘,请使用:
control.Invalidate();
control.Update();
即使用户界面仍处理消息,无论发生什么事情,都会重新绘制控件。从字面上看,我认为它使用SendMessage
API代替PostMessage
,这迫使绘画同步完成,而不是在长消息队列的末尾抛出它。
答案 1 :(得分:1)
Invalidate()
仅“使控件或表单无效”(将其标记为重新绘制),但不强制重绘。当应用程序在消息队列中没有要处理的消息时再次重新绘制时,它将重新绘制。如果要强制重新绘制,可以使用Refresh()
。
答案 2 :(得分:0)
Invalidate
或Refresh
将执行相同的操作,并强制重绘(最终)。如果您没有看到任何重绘(永远),那么这意味着在DrawWorldBox
中根本没有绘制任何内容,或者从PictureBox图像的可见部分绘制的任何内容都被绘制出来。
确保(正在使用断点或记录或单步执行代码)某些正被添加到selectionRectangles
,并且至少有一个矩形覆盖PictureBox的可见部分。还要确保您正在绘制的笔与背景颜色不一样。