Инвертировать цвета на элементе управления - PullRequest
0 голосов
/ 17 ноября 2009

Я сделал элемент управления, который использует OnPaint и base.OnPaint. Теперь я хочу, чтобы все цвета были инвертированы при определенных условиях. Но как мне это сделать? Я знаю, как инвертировать изображение, но как мне работать с графическим объектом?

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

  if(Condition)
    InvertColors(e);
}

Ответы [ 2 ]

2 голосов
/ 17 ноября 2009

Прежде чем я начну, я хотел бы сказать, что я согласен с Xaero по его вопросу. Кажется, что ваша намеченная цель выиграет от класса ErrorProvider.

Тем не менее, вы можете инвертировать содержимое графической области, используя BitBlt через P / Invoke. Вот функция, которая может сделать это для вас, но без оптимизации. Я оставлю эту часть на ваше усмотрение. Эта функция использует растровые операции для инвертирования целевой области. 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 голос
/ 17 ноября 2009

Это не прямой ответ на ваш вопрос, а возможная альтернатива, которая несколько чище и, на мой взгляд, соответствует стандартам Windows чуть ближе, чем инвертирование цвета элемента управления.

ErrorProvider Class

ErrorProvider Class

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...