How can I gray-out a disabled PictureBox used as Button?

…衆ロ難τιáo~ 提交于 2020-07-23 07:25:11

问题


I'm using Picturebox control as a Button in my app's main dashboard.
The PictureBox has of course an Image that identifies the Button function.

If I use normal Button controls, when disabled, the Buttons' Image it grayed out automatically.
This doesn't happen using a PictureBox.

How can I generated the same effect using a Picturebox.


回答1:


Option 1: CustomControl (PictureBox) + ColorMatrix

Since you don't want to use a Button, which would gray-out the Image for you when the Control is disabled, you can use a ColorMatrix to change the PictureBox.BackgroundImage or (Image) to a gray scale.

The GrayScale matrix you see here uses well-known values to convert an Image to a scaled gray color representation. You can find other interpretations of the same matrix object that may generate different results.
It can be fun to test some or tweak it yourself.

The GrayScale procedure is implemented as an Extension method, since it may come in handy in other situations.
It extends the Image class, adding a ToGrayScale() method (you can of course also extend the Bitmap class: you just need to call the Image extension, casting Bitmap to Image, or the other way around, as you prefer).


Assuming you have a Custom Control, when the BackgroundImage is changed, you create a GrayScale representation of it and store it.

Then override OnEnabledChanged to change the BackgroundImage to either the original or its GrayScale version. A simple check prevents the code from generating a new GrayScale image when the BackgroundImage is changed internally (it's a somewhat simplified method, you should paint the background instead. I'll update it when I can).

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

[DesignerCategory("Code")]
public class ButtonPicture : PictureBox
{
    private Image m_sourceImage = null;
    private Image m_grayImage = null;

    public ButtonPicture() { }

    protected override void OnEnabledChanged(EventArgs e) {
        base.OnEnabledChanged(e);
        this.BackgroundImage = this.Enabled ? m_sourceImage : m_grayImage;
    }
        
    protected override void OnBackgroundImageChanged(EventArgs e) {
        base.OnBackgroundImageChanged(e);
        if (this.BackgroundImage == m_sourceImage || 
            this.BackgroundImage == m_grayImage) return;
        m_sourceImage = this.BackgroundImage;
        m_grayImage = m_sourceImage.ToGrayScale();
    }

    protected override void Dispose(bool disposing) {
        if (disposing) {
            m_grayImage.Dispose();
        }
        base.Dispose(disposing);
    }
}

The extension method:

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

public static class ImageExtensions
{
    static ColorMatrix grayMatrix = new ColorMatrix(new float[][]
    {
        new float[] { .2126f, .2126f, .2126f, 0, 0 },
        new float[] { .7152f, .7152f, .7152f, 0, 0 },
        new float[] { .0722f, .0722f, .0722f, 0, 0 },
        new float[] { 0, 0, 0, 1, 0 },
        new float[] { 0, 0, 0, 0, 1 }
    });

    public static Bitmap ToGrayScale(this Image source) {
        var grayImage = new Bitmap(source.Width, source.Height, source.PixelFormat);
        grayImage.SetResolution(source.HorizontalResolution, source.VerticalResolution);

        using (var g = Graphics.FromImage(grayImage))
        using (var attributes = new ImageAttributes()) {
            attributes.SetColorMatrix(grayMatrix);
            g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
                        0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
            return grayImage;
        }
    }
}


Option 2: ControlPaint + PictureBox.Paint event (lame)

You can use the ControlPaint.DrawImageDisabled() method to draw a disabled Bitmap.

  • The Graphics object the methods needs is provided by the Control's PaintEventArgs: subscribe to the PictureBox.Paint event and pass the e.Graphics object to the method.
  • The Image argument can be a copy of the PictureBox.Image property value.
  • The only advantage is that you need quite less code, but the default implementation cannot be controlled and the result is, well, questionable (but probably good enough for a generic use).

► Compare the Image on the left, disabled using a ColorMatrix, with the Image on the right, disabled using the ControlPaint method:

private void buttonPicture_Paint(object sender, PaintEventArgs e)
{
    var pict = sender as PictureBox;
    if (pict != null && (!pict.Enabled)) {
        using (var img = new Bitmap(pict.Image, pict.ClientSize)) {
            ControlPaint.DrawImageDisabled(e.Graphics, img, 0, 0, pict.BackColor);
        }
    }
}


来源:https://stackoverflow.com/questions/61566125/how-can-i-gray-out-a-disabled-picturebox-used-as-button

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!