Custom TextBox Control About OnPaint Method - c#

This probably is an embarrassing question but I have created a custom textbox which has a red border using help from MSDN website.
I understand I have inherited from the UserControl class and overridden its OnPaint() method.
Can someone tell me where the OnPaint() method is being called as I can't see it in the code.
Here is the code -
namespace CustomTextBox
{
public partial class BorderTextBox : UserControl
{
private TextBox textBox;
private Color myColor = Color.Red;
public BorderTextBox()
{
InitializeComponent();
this.textBox = new TextBox();
this.DoubleBuffered = true;
this.Padding = new Padding(2);
this.textBox.BorderStyle = BorderStyle.None;
this.textBox.Dock = DockStyle.Fill;
this.Controls.Add(this.textBox);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen borderPen = new Pen(myColor);
e.Graphics.DrawRectangle(borderPen,
new Rectangle(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1));
}
}
}

Related

GroupBox Border not visible on Server 2016 when using the background color Gainsboro

We use the standard GroupBox and the Flat-Style. The form backgroundcolor is Gainsboro.
On my Windows 7 development machine it looks like this:
However, when running the app in a Windows Server 2016 Machine, it looks like this:
The borders are gone (not visible).
It appears to has something to do with the Background Color, but we're not sure how to fix it. When using a light blue Color, this happens on Server 2016:
Do you guys have any clue, why we can't see the white border with the BG-Color Gainsboro? It doesn't make any sense....
I dont have server 2016 to test it, but maybe overriding the Paint event of the borderColor will solve this problem, here is a custom GroupBox control, you can change borderColor Color inside the constructor.
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
CustomGroupBox gb = new CustomGroupBox();
gb.Location = new Point(5, 5);
gb.Size = new Size(200, 100);
this.Controls.Add(gb);
}
}
public class CustomGroupBox : GroupBox
{
private Color borderColor;
public Color BorderColor
{
get { return this.borderColor; }
set { this.borderColor = value; }
}
public CustomGroupBox()
{
this.borderColor = Color.Red;
}
protected override void OnPaint(PaintEventArgs e)
{
Size tSize = TextRenderer.MeasureText(this.Text, this.Font);
Rectangle borderRect = e.ClipRectangle;
borderRect.Y += tSize.Height / 2;
borderRect.Height -= tSize.Height / 2;
ControlPaint.DrawBorder(e.Graphics, borderRect, this.borderColor, ButtonBorderStyle.Solid);
Rectangle textRect = e.ClipRectangle;
textRect.X += 6;
textRect.Width = tSize.Width;
textRect.Height = tSize.Height;
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), textRect);
e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), textRect);
}
}
}

Transparent control over drew shape

I'm new for create user control, and in my first usercontrol i used from picturebox and label ,
picturebox for draw a shape and label for show text over that shape.
i was set picturebox parent for label, and label backcolor to transparent also if don't have any text label set to visible = false
now i have a problem, when label is visible, i can't see picturebox correctly.
how can i solve this problem ?
also paint event on user control not work
private void Ucontrol_Paint(object sender, PaintEventArgs e)
{
if (RightToLeft)
{
lblTxt.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
}
else
{
lblTxt.RightToLeft = System.Windows.Forms.RightToLeft.No;
}
lblTxt.ForeColor = FontColor;
lblTxt.Text = Txt;
if (Question)
{
BorderColor = Color.DarkBlue;
BackColor = Color.FromArgb(75, 163, 234);
CreateQuestion(BorderColor, BackColor);
}
else
{
BorderColor = Color.DarkGreen;
BackColor = Color.FromArgb(59, 226, 75);
CreateAnswer(BorderColor, BackColor);
}
}
Forms controls don't have really a transpartent background, they copy it's parent content.
Also, a PictureBox can't be parent of another control as they aren't container.
Then, instead of using a picturebox just set the usercontrol background image and put the label on it, the transparency should work.
Here is a working example manually drawing the control content:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
Label lbl = new Label();
lbl.Location = new Point(10, 10);
lbl.Width = 150;
lbl.Height = 150;
lbl.BackColor = Color.Transparent;
lbl.Text = #"asdfasdfasdfasdf\r\nasdfasdfasdf\r\n\r\nasdfasdfasdf";
lbl.Visible = true;
this.Controls.Add(lbl);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.Red, new Rectangle(10, 10, 100, 100));
e.Graphics.FillEllipse(Brushes.Yellow, new Rectangle(10, 10, 100, 100));
}
}

Painting a TextBox

I'm in need of a way to make TextBox appear like a parallelogram but i can't figure out how to do so. I currently have this code:
private void IOBox_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Point cursor = PointToClient(Cursor.Position);
Point[] points = { cursor, new Point(cursor.X + 50, cursor.Y), new Point(cursor.X + 30, cursor.Y - 20),
new Point(cursor.X - 20, cursor.Y - 20) };
Pen pen = new Pen(SystemColors.MenuHighlight, 2);
g.DrawLines(pen, points);
}
But apparently it's not working. Either i misplaced/misused it or i'm not doing something right.
This is the method that i use to add it.
int IOCounter = 0;
private void inputOutput_Click(object sender, EventArgs e)
{
IOBox box = new IOBox();
box.Name = "IOBox" + IOCounter;
IOCounter++;
box.Location = PointToClient(Cursor.Position);
this.Controls.Add(box);
}
Any idea how i can fix it? IOBox is a UserControl made by me which contains a TextBox. Is that rightful to do?
If its possible, you should make your application using WPF. WPF is designed to do exactly what you are trying to do.
However, it can be done in WinForms, though not easily. You will need to make a new class that inherits the TextBox WinForm control. Here is an example that makes a TextBox look like a circle:
public class MyTextBox : TextBox
{
public MyTextBox() : base()
{
SetStyle(ControlStyles.UserPaint, true);
Multiline = true;
Width = 130;
Height = 119;
}
public override sealed bool Multiline
{
get { return base.Multiline; }
set { base.Multiline = value; }
}
protected override void OnPaintBackground(PaintEventArgs e)
{
var buttonPath = new System.Drawing.Drawing2D.GraphicsPath();
var newRectangle = ClientRectangle;
newRectangle.Inflate(-10, -10);
e.Graphics.DrawEllipse(System.Drawing.Pens.Black, newRectangle);
newRectangle.Inflate(1, 1);
buttonPath.AddEllipse(newRectangle);
Region = new System.Drawing.Region(buttonPath);
base.OnPaintBackground(e);
}
}
Keep in mind that you will still have to do other things, such as clipping the text, etc. But this should get you started.

Change the borderColor of the TextBox

How can I change the BorderColor of the Textbox when a user Clicks on it or focuses on it?
You can handle WM_NCPAINT message of TextBox and draw a border on the non-client area of control if the control has focus. You can use any color to draw border:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ExTextBox : TextBox
{
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
private const int WM_NCPAINT = 0x85;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCPAINT && this.Focused)
{
var dc = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(dc))
{
g.DrawRectangle(Pens.Red, 0, 0, Width - 1, Height - 1);
}
}
}
}
Result
The painting of borders while the control is focused is completely flicker-free:
BorderColor property for TextBox
In the current post I just change the border color on focus. You can also add a BorderColor property to the control. Then you can change border-color based on your requirement at design-time or run-time. I've posted a more completed version of TextBox which has BorderColor property:
in the following post:
BorderColor property for TextBox
try this
bool focus = false;
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (focus)
{
textBox1.BorderStyle = BorderStyle.None;
Pen p = new Pen(Color.Red);
Graphics g = e.Graphics;
int variance = 3;
g.DrawRectangle(p, new Rectangle(textBox1.Location.X - variance, textBox1.Location.Y - variance, textBox1.Width + variance, textBox1.Height +variance ));
}
else
{
textBox1.BorderStyle = BorderStyle.FixedSingle;
}
}
private void textBox1_Enter(object sender, EventArgs e)
{
focus = true;
this.Refresh();
}
private void textBox1_Leave(object sender, EventArgs e)
{
focus = false;
this.Refresh();
}
This is an ultimate solution to set the border color of a TextBox:
public class BorderedTextBox : UserControl
{
TextBox textBox;
public BorderedTextBox()
{
textBox = new TextBox()
{
BorderStyle = BorderStyle.FixedSingle,
Location = new Point(-1, -1),
Anchor = AnchorStyles.Top | AnchorStyles.Bottom |
AnchorStyles.Left | AnchorStyles.Right
};
Control container = new ContainerControl()
{
Dock = DockStyle.Fill,
Padding = new Padding(-1)
};
container.Controls.Add(textBox);
this.Controls.Add(container);
DefaultBorderColor = SystemColors.ControlDark;
FocusedBorderColor = Color.Red;
BackColor = DefaultBorderColor;
Padding = new Padding(1);
Size = textBox.Size;
}
public Color DefaultBorderColor { get; set; }
public Color FocusedBorderColor { get; set; }
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
protected override void OnEnter(EventArgs e)
{
BackColor = FocusedBorderColor;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
BackColor = DefaultBorderColor;
base.OnLeave(e);
}
protected override void SetBoundsCore(int x, int y,
int width, int height, BoundsSpecified specified)
{
base.SetBoundsCore(x, y, width, textBox.PreferredHeight, specified);
}
}
WinForms was never good at this and it's a bit of a pain.
One way you can try is by embedding a TextBox in a Panel and then manage the drawing based on focus from there:
public class BorderTextBox : Panel {
private Color _NormalBorderColor = Color.Gray;
private Color _FocusBorderColor = Color.Blue;
public TextBox EditBox;
public BorderTextBox() {
this.DoubleBuffered = true;
this.Padding = new Padding(2);
EditBox = new TextBox();
EditBox.AutoSize = false;
EditBox.BorderStyle = BorderStyle.None;
EditBox.Dock = DockStyle.Fill;
EditBox.Enter += new EventHandler(EditBox_Refresh);
EditBox.Leave += new EventHandler(EditBox_Refresh);
EditBox.Resize += new EventHandler(EditBox_Refresh);
this.Controls.Add(EditBox);
}
private void EditBox_Refresh(object sender, EventArgs e) {
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.Clear(SystemColors.Window);
using (Pen borderPen = new Pen(this.EditBox.Focused ? _FocusBorderColor : _NormalBorderColor)) {
e.Graphics.DrawRectangle(borderPen, new Rectangle(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1));
}
base.OnPaint(e);
}
}
Using OnPaint to draw a custom border on your controls is fine. But know how to use OnPaint to keep efficiency up, and render time to a minimum. Read this if you are experiencing a laggy GUI while using custom paint routines: What is the right way to use OnPaint in .Net applications?
Because the accepted answer of PraVn may seem simple, but is actually inefficient. Using a custom control, like the ones posted in the answers above is way better.
Maybe the performance is not an issue in your application, because it is small, but for larger applications with a lot of custom OnPaint routines it is a wrong approach to use the way PraVn showed.
set Text box Border style to None
then write this code to container form "paint" event
private void Form1_Paint(object sender, PaintEventArgs e)
{
System.Drawing.Rectangle rect = new Rectangle(TextBox1.Location.X,
TextBox1.Location.Y, TextBox1.ClientSize.Width, TextBox1.ClientSize.Height);
rect.Inflate(1, 1); // border thickness
System.Windows.Forms.ControlPaint.DrawBorder(e.Graphics, rect,
Color.DeepSkyBlue, ButtonBorderStyle.Solid);
}
With PictureBox1
.Visible = False
.Width = TextBox1.Width + 4
.Height = TextBox1.Height + 4
.Left = TextBox1.Left - 2
.Top = TextBox1.Top - 2
.SendToBack()
.Visible = True
End With
Here is my complete Flat TextBox control that supports themes including custom border colors in normal and focused states.
The control uses the same concept mentioned by Reza Aghaei https://stackoverflow.com/a/38405319/5514131 ,however the FlatTextBox control is more customizable and flicker-free.
The control handles the WM_NCPAINT window message in a better way to help eliminate flicker.
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WindowMessage.WM_NCPAINT AndAlso _drawBorder AndAlso Not DesignMode Then 'Draw the control border
Dim w As Integer
Dim h As Integer
Dim clip As Rectangle
Dim hdc As IntPtr
Dim clientRect As RECT = Nothing
GetClientRect(Handle, clientRect)
Dim windowRect As RECT = Nothing
GetWindowRect(Handle, windowRect)
w = windowRect.Right - windowRect.Left
h = windowRect.Bottom - windowRect.Top
clip = New Rectangle(CInt((w - clientRect.Right) / 2), CInt((h - clientRect.Bottom) / 2), clientRect.Right, clientRect.Bottom)
hdc = GetWindowDC(Handle)
Using g As Graphics = Graphics.FromHdc(hdc)
g.SetClip(clip, CombineMode.Exclude)
Using sb = New SolidBrush(BackColor)
g.FillRectangle(sb, 0, 0, w, h)
End Using
Using p = New Pen(If(Focused, _borderActiveColor, _borderNormalColor), BORDER_WIDTH)
g.DrawRectangle(p, 0, 0, w - 1, h - 1)
End Using
End Using
ReleaseDC(Handle, hdc)
Return
End If
MyBase.WndProc(m)
End Sub
I have removed the default BorderStyle property and replaced it with a simple boolean DrawBorder property that controls whether to draw a border around the control or not.
Use the BorderNormalColor property to specify the border color when the TextBox has no focus, and the BorderActiveColor property to specify the border color when the control receives focus.
The FlatTextBox comes with two themes VS2019 Dark and VS2019 Light, use the Theme property to switch between them.
Complete FlatTextBox control code written in VB.NET
https://gist.github.com/ahmedosama007/37fe2004183a51a4ea0b4a6dcb554176

Customize ToolStripMenuItem

I want to customize ToolStripMenuItem by overriding OnPaint function. This is a MyToolStripMenuItem:
public class MyToolStripMenuItem : ToolStripMenuItem
{
public MyToolStripMenuItem()
:base()
{
}
public MyToolStripMenuItem(string t)
:base(t)
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle r = this.Bounds;
g.FillRectangle(Brushes.Blue, r);
g.DrawString(this.Text, this.Font, Brushes.Red, r);
}
}
In my code, I will fill a blue color in item's bound. Now, I will create a list of items on menustrip:
MyToolStripMenuItem1
|___MyToolStripMenuItem2
|___MyToolStripMenuItem3
I don't know why MyToolStripMenuItem3 don't have a blue background.
This is my source code:
http://www.mediafire.com/?2qhmjzzfzzn
Please help me. Thanks.
It's not the way it is done with a ToolStripMenuItem. You give the MenuStrip a custom renderer. For example:
For example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
menuStrip1.Renderer = new MyRenderer();
}
private class MyRenderer : ToolStripProfessionalRenderer {
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) {
if (!e.Item.Selected) base.OnRenderMenuItemBackground(e);
else {
Rectangle rc = new Rectangle(Point.Empty, e.Item.Size);
e.Graphics.FillRectangle(Brushes.Beige, rc);
e.Graphics.DrawRectangle(Pens.Black, 1, 0, rc.Width - 2, rc.Height - 1);
}
}
}
}
The problem with using OnRenderMenuItemBackground() is that it applies to the whole menu and not just the one ToolStripMenuItem.
The error in the code lies in Rectangle r = this.Bounds; which produces the wrong area. Change this to Rectangle r = e.ClipRectangle and it should work ok. (For some reason the Bounds has the wrong Y component).

Categories