反转控件上的颜色

时间:2009-11-17 14:21:13

标签: .net user-controls colors

我制作了一个使用OnPaint和base.OnPaint的控件。 现在我想要在某些条件下反转所有颜色。但是我该怎么做?我知道如何反转图像,但如何处理Graphics对象?

protected override void OnPaint(PaintEventArgs e)
{
  base.OnPaint(e);
  MyOwnPaint(e);

  if(Condition)
    InvertColors(e);
}

2 个答案:

答案 0 :(得分:2)

在开始之前,我想说我同意Xaero的观点。似乎您的预期目标将从ErrorProvider类中受益。

也就是说,您可以通过P / Invoke使用BitBlt反转图形区域的内容。这是一个可以为你做的功能,虽然没有优化。我会把那部分留给你。此功能使用光栅操作来反转目标区域。在目的地上带有白色光源的XOR会导致目标处的颜色反转(按逻辑值,不一定是颜色空间)。

private void InvertGraphicsArea(Graphics g, Rectangle r)
{
    if (r.Height <= 0) { return; }
    if (r.Width <= 0) { return; }

    using (Bitmap bmpInvert = GetWhiteBitmap(g, r))
    {
        IntPtr hdcDest = g.GetHdc();
        using (Graphics src = Graphics.FromImage(bmpInvert))
        {
            int xDest = r.Left;
            int yDest = r.Top;
            int nWidth = r.Width;
            int nHeight = r.Height;
            IntPtr hdcSrc = src.GetHdc();
            BitBlt(hdcDest, xDest, yDest, nWidth, nHeight, 
                   hdcSrc, 0, 0, (uint)CopyPixelOperation.DestinationInvert);
            src.ReleaseHdc(hdcSrc);
        }
        g.ReleaseHdc(hdcDest);
    }
}

在包含此实用程序功能的类中,您需要导入System.Runtime.InteropServices以及BitBlt()的定义。此外,使用GetWhiteBitmap()辅助方法,此函数的内部更简洁。

using System.Runtime.InteropServices;

// ...

[DllImport("gdi32.dll", 
           EntryPoint="BitBlt", 
           CallingConvention=CallingConvention.StdCall)]
extern public static int BitBlt(
    IntPtr hdcDesc, int nXDest, int nYDest, int nWidth, int nHeight, 
    IntPtr hdcSrc, int nXSrc, int nYSrcs, uint dwRop);

private Bitmap GetWhiteBitmap(Graphics g, Rectangle r)
{
    int w = r.Width;
    int h = r.Height;

    Bitmap bmp = new Bitmap(w, h);
    using (Graphics gTmp = Graphics.FromImage(bmp))
    {
        gTmp.Clear(Color.White);
    }
    return bmp;
}

这不是图形表面颜色的真正颜色转换反转 - 但这与在旧的win32天中完成高光的方式非常类似。为了测试这个,我修改了一个默认的WinForms应用程序并添加了以下代码,它处理双击,绘制,并具有替换状态的成员变量。

bool m_Highlight = false;

private void Form1_DoubleClick(object sender, EventArgs e)
{
    m_Highlight = !m_Highlight;
    this.Invalidate();
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
    // Note: sloppy, but just to show that everything is inverted.
    using(Font font = new Font(FontFamily.GenericSerif, 20.0f, FontStyle.Bold))
    {
        e.Graphics.DrawString("Hello World!", font, Brushes.Red, 0.0f, 0.0f);
    }

    if (m_Highlight)
    {
        InvertGraphicsArea(e.Graphics, e.ClipRectangle);
    }
}

答案 1 :(得分:1)

这不是你问题的直接答案,而是一种可能的替代方案,它更加清晰,在我看来,它比Windows标准更接近于反转控件的颜色。

ErrorProvider Class

ErrorProvider Class