11

I want to change the border color and the background of the square and the color of the check mark, but not the text. To better understand, what I want to accomplish is the following example:

  • checkBox1.Checked = false

  • checkBox1.Checked = true

Thanks so much to everyone of you responds exactly to this request!

user5894584
  • 113
  • 1
  • 1
  • 7
  • 1
    Please don't do this. Use a regular checkbox that everyone will recognize and know how to use. Use one that will correctly handle keyboard navigation. And use one that conforms to the user's chosen theme so that it won't stick out like a sore thumb. The built-in controls have already been thoroughly debugged; your one-off control is likely to be more like a square wheel. Your personal aesthetic sense is often not shared by your users. Best to direct your focus to functionality instead. – Cody Gray - on strike Feb 07 '16 at 13:45

2 Answers2

21

You can simply draw the checkmark in the Paint event:

enter image description here

private void checkBox1_Paint(object sender, PaintEventArgs e)
{
    Point pt = new  Point(e.ClipRectangle.Left + 2, e.ClipRectangle.Top + 4);
    Rectangle rect = new Rectangle(pt, new Size(22, 22));
    if (checkBox1.Checked)
    {
       using (Font wing = new Font("Wingdings", 14f))
          e.Graphics.DrawString("ü", wing, Brushes.DarkOrange,rect);
    }
    e.Graphics.DrawRectangle(Pens.DarkSlateBlue, rect);
}

for this to work you need to:

  • set Apperance = Appearance.Button
  • set FlatStyle = FlatStyle.Flat
  • set TextAlign = ContentAlignment.MiddleRight
  • set FlatAppearance.BorderSize = 0
  • set AutoSize = false

If you want to re-use this it will be best to subclass the checkbox and override the OnPaint event there. Here is an example:

enter image description here

public ColorCheckBox()
{
    Appearance = System.Windows.Forms.Appearance.Button;
    FlatStyle = System.Windows.Forms.FlatStyle.Flat;
    TextAlign = ContentAlignment.MiddleRight;
    FlatAppearance.BorderSize = 0;
    AutoSize = false;
    Height = 16;
}

protected override void OnPaint(PaintEventArgs pevent)
{
    //base.OnPaint(pevent);

    pevent.Graphics.Clear(BackColor);

    using (SolidBrush brush = new SolidBrush(ForeColor))
        pevent.Graphics.DrawString(Text, Font, brush, 27, 4);

    Point pt = new Point( 4 ,  4);
    Rectangle rect = new Rectangle(pt, new Size(16, 16));

    pevent.Graphics.FillRectangle(Brushes.Beige, rect);

    if (Checked)
    {
        using (SolidBrush brush = new SolidBrush(ccol))
        using (Font wing = new Font("Wingdings", 12f))
            pevent.Graphics.DrawString("ü", wing, brush, 1,2);
    }
    pevent.Graphics.DrawRectangle(Pens.DarkSlateBlue, rect);

    Rectangle fRect = ClientRectangle;

    if (Focused)
    {
        fRect.Inflate(-1, -1);
        using (Pen pen = new Pen(Brushes.Gray) { DashStyle = DashStyle.Dot })
            pevent.Graphics.DrawRectangle(pen, fRect);
    }
}

You may need to tweek the sizes of the control and the font.. And if you want to you expand the code to honor the TextAlign and the CheckAlign properties.

And if you need a three-state control you can adapt the code to display a third state appearance, especially if you think of one that looks better than the original..

TaW
  • 53,122
  • 8
  • 69
  • 111
  • I think this last code is what I am trying to do, but what comes out is just a square with colored border above a "Flat" button that does not allow any kind of interaction. – user5894584 Feb 07 '16 at 11:47
  • I missed the check for `Checked`, sorry; updated. Other than that it works here.. – TaW Feb 07 '16 at 11:49
  • I'm sorry but it still does not work. Why must it be considered as button? – user5894584 Feb 07 '16 at 11:53
  • That's so that it won't draw its own checkmark. The standard use it to see it like a button that stays pressed in. With the `if (Checked)` clause added, what does not work? Did you set the `CheckColor` property??? – TaW Feb 07 '16 at 11:55
  • Thank you very much for helping. If you'd wanted to place the text of checkBox1? – user5894584 Feb 07 '16 at 14:58
  • I don't understand. You can use the TextAlign property and the Rectangle that is supposed to contain it. There is also a DrawString overload with a [StringFormat](https://msdn.microsoft.com/en-us/library/system.drawing.stringformat%28v=vs.110%29.aspx) paramter. What do you want to achieve? – TaW Feb 07 '16 at 15:01
  • I'm sorry, I misspoke. I solved by adding TextRenderer.DrawText. I want the square is 16x16 size with white background and orange border and that starts at position (0, 0). How can I do it? – user5894584 Feb 07 '16 at 15:07
  • Using TextRenderer is ok, but its overload with the backcolor is probably not a good idea as it is rather hard to get pixel-perfect.. fill the background of the rectangle with a fillrectangle call that goes on before the other two calls.. – TaW Feb 07 '16 at 15:12
  • 1
    `base.OnPaint(pevent); Point pt = new Point(pevent.ClipRectangle.Left , pevent.ClipRectangle.Top + 4); Rectangle rect = new Rectangle(pt, new Size(16, 16)); pevent.Graphics.FillRectangle(Brushes.Beige, rect); if (Checked) { using (SolidBrush brush = new SolidBrush(ccol)) using (Font wing = new Font("Wingdings", 12f)) pevent.Graphics.DrawString("ü", wing, brush, -1,2); } pevent.Graphics.DrawRectangle(Pens.DarkSlateBlue, rect); Rectangle fRect = ClientRectangle;` – TaW Feb 07 '16 at 15:22
  • I have tweeked the values a little. Setting a FlattAppearance colors to transparent is also helping! – TaW Feb 07 '16 at 15:23
  • Hint: Do expose the checkBackColr as a property like the checkColor to make the class more flexible.. – TaW Feb 07 '16 at 15:32
  • Thanks for the advice. – user5894584 Feb 07 '16 at 15:53
  • I'm sorry but I have another question to ask: What is the property that shows the control when you press the TAB? – user5894584 Feb 07 '16 at 16:20
  • 1
    When you reach the control via the tab key it shows the 'focus rectangle'. If you want to you can draw it yourself in any way you want to but then you need to do __all__ the drawing: `protected override void OnPaint(PaintEventArgs pevent) { //base.OnPaint(pevent); pevent.Graphics.Clear(SystemColors.Control); using (SolidBrush brush = new SolidBrush(ForeColor)) pevent.Graphics.DrawString(Text, Font, brush, 22, 4);`.. – TaW Feb 07 '16 at 16:29
  • .. and `pevent.Graphics.DrawRectangle(Pens.DarkSlateBlue, rect); Rectangle fRect = ClientRectangle; if (Focused) { fRect.Inflate(-1, -1); using (Pen pen = new Pen(Brushes.DarkSalmon) { DashStyle = DashStyle.Dot }) pevent.Graphics.DrawRectangle(pen, fRect); }` – TaW Feb 07 '16 at 16:29
  • 1
    I have modified the class to include the focus rectangle and to do all the text drawing.. – TaW Feb 07 '16 at 16:42
  • I saw it and I thank you very much. The code function very well! – user5894584 Feb 07 '16 at 19:09
  • Thanks @TaW for the code, I was able to write a complete custom CheckBox control that has the following features: Predefined styles (VS 2019 Dark and Light). Support for AutoSize property. Support for custom colors in focused, mouse enter and mouse down events. Support for custom check mark (shape and color). Public properties to customize the look the CheckBox control. https://stackoverflow.com/a/70259657/5514131 – Ahmed Osama Dec 07 '21 at 12:05
3

You have to write your own checkbox. By making a custom control in which there's a blue square(possibly inherits from Button) that toggles between checked and not checked images by an OnClick event and place a label next to it.

Ilan Kutsman
  • 469
  • 3
  • 9