【问题标题】:New area not repaints when user-drawn control size is increased当用户绘制的控件大小增加时,新区域不会重新绘制
【发布时间】:2016-09-11 05:33:17
【问题描述】:

我想我在这里遗漏了一些微不足道的东西。我直接从Control 派生了简单的控制。我将覆盖OnPaint 并绘制矩形(e.Graphics.DrawRectangle)和其中的文本(e.Graphics.DrawString)。我没有覆盖任何其他成员。

当控件被调整为较小的尺寸时,它会很好地绘制自己,但是当它被调整为较大的尺寸时,新区域不会正确地重新绘制。一旦我再次将其调整为较小的尺寸,即使缩小一个像素,一切都会正确重绘。

OnPaint 被正确调用(将适当的PaintEventArgs.ClipRectangle 正确设置为新区域),但无论如何都不会绘制新区域(出现伪影)。

我错过了什么?

编辑:

代码:

protected override void OnPaint(PaintEventArgs e)
{
    // Adjust control's height based on current width, to fit current text:

    base.Height = _GetFittingHeight(e.Graphics, base.Width);

    // Draw frame (if available):

    if (FrameThickness != 0)
    {
        e.Graphics.DrawRectangle(new Pen(FrameColor, FrameThickness),
            FrameThickness / 2, FrameThickness / 2, base.Width - FrameThickness, base.Height - FrameThickness);
    }

    // Draw string:

    e.Graphics.DrawString(base.Text, base.Font, new SolidBrush(base.ForeColor), new RectangleF(0, 0, base.Width, base.Height));
}

private int _GetFittingHeight(Graphics graphics, int width)
{
    return (int)Math.Ceiling(graphics.MeasureString(base.Text, base.Font, width).Height);
}

【问题讨论】:

  • 能否请您发布您正在使用的代码(OnPaint)来绘制控件?

标签: c# .net winforms drawing


【解决方案1】:

尝试在你的构造函数中添加这个:

public MyControl() {
  this.ResizeRedraw = true;
  this.DoubleBuffered = true;
}

并在您的绘画事件中,清除之前的绘图:

protected override void OnPaint(PaintEventArgs e) {
  e.Graphics.Clear(SystemColors.Control);
  // yada-yada-yada
}

【讨论】:

  • ResizeRedraw 完成了这项工作!不需要设置DoubleBuffered(尽管我一直在使用它),也不需要设置Graphics.Clear()。在构造函数中将ResizeRedraw 设置为true 解决了这个问题。非常感谢:)
【解决方案2】:

虽然ResizeRedraw 会起作用,但它会强制整个控件为每个调整大小事件重新绘制,而不是只绘制由调整大小显示的区域。这可能是可取的,也可能是不可取的。

OP 遇到的问题是由于旧矩形没有失效造成的;只有显露的区域会被重新粉刷,而旧的图形会留在原来的位置。要纠正此问题,请检测矩形的大小是否垂直或水平增加,并使矩形的适当边缘无效。

您具体如何处理这将取决于您的实施。您需要有一些东西可以擦除旧的矩形边缘,并且您必须调用 Invalidate 传递一个包含旧矩形边缘的区域。让它正常工作可能有点复杂,这取决于你在做什么,如果性能差异可以忽略不计,使用ResizeRedraw毕竟可能会简单得多。

例如,您可以在绘制边框时针对此问题执行以下操作。

// member variable; should set to initial size in constructor
// (side note: should try to remember to give your controls a default non-zero size)
Size mLastSize;
int borderSize = 1; // some border size

...

// then put something like this in the resize event of your control
var diff = Size - mLastSize;
var wider = diff.Width > 0;
var taller = diff.Height > 0;

if (wider)
   Invalidate(new Rectangle(
      mLastSize.Width - borderSize, // x; some distance into the old area (here border)
      0,                            // y; whole height since wider
      borderSize,                   // width; size of the area (here border)
      Height                        // height; all of it since wider
   ));

if (taller)
   Invalidate(new Rectangle(
      0,                              // x; whole width since taller
      mLastSize.Height - borderSize,  // y; some distance into the old area
      Width,                          // width; all of it since taller
      borderSize                      // height; size of the area (here border)
   ));

mLastSize = Size;

【讨论】:

  • 这实际上是一个非常好的答案(如,它解释了它为什么会发生)。就我而言,因为我只在一个特定条件下重绘,所以当满足该条件时,我在整个控件上手动调用 Invalidate()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
相关资源
最近更新 更多