I want to have TextBox with bottom border but Graphics drawn for TextBox is distorted/broken on resize because of Color.Transparent.
Using an code I found, I was able to create a underlined TextBox (Drawn Rectangle with tranparent top, left, right). The problem is when I resize the form/window: when I resize it to smaller, then resize again to expand it, the graphics drawn is distorted. Any fix for this?
Here are photos: The second photo has been already resized smaller, then back to a larger size.
Here's the code:
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
struct RECT {
public int left, top, right, bottom;
}
struct NCCALSIZE_PARAMS {
public RECT newWindow;
public RECT oldWindow;
public RECT clientWindow;
IntPtr windowPos;
}
float clientPadding = 0;
int actualBorderWidth = 2;
Color borderColor = Color.Black;
protected override void WndProc(ref Message m) {
//We have to change the clientsize to make room for borders
//if not, the border is limited in how thick it is.
if (m.Msg == 0x83) { //WM_NCCALCSIZE
if (m.WParam == IntPtr.Zero) {
RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
rect.left += 2;
rect.right -= 2;
rect.top += 0;
rect.bottom -= 0;// (int)clientPadding;
Marshal.StructureToPtr(rect, m.LParam, false);
} else {
NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
rects.newWindow.left += (int)clientPadding;
rects.newWindow.right -= (int)clientPadding;
rects.newWindow.top += (int)clientPadding;
rects.newWindow.bottom -= 2;
Marshal.StructureToPtr(rects, m.LParam, false);
}
}
if (m.Msg == 0x85) {//WM_NCPAINT
IntPtr wDC = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(wDC)) {
ControlPaint.DrawBorder(g, new Rectangle(0, 0, Size.Width, Size.Height),
Color.Transparent, 1, ButtonBorderStyle.Solid,
Color.Transparent, 1, ButtonBorderStyle.Solid,
Color.Transparent, 1, ButtonBorderStyle.Solid,
borderColor, actualBorderWidth, ButtonBorderStyle.Solid);
}
return;
}
base.WndProc(ref m);
}
EDIT : I already found the issue, it's because of the Color.Transparent I fixed it by changing it to Color.White, since I have a white background. But then, that would not always be the case, how would I prevent that "Flickering/Tearing" while using Color.Transparent?
To have a TextBox with bottom border, The most simple workaround that I can offer is docking a 1 pixel height lable (or other control) to bottom of the TextBox:
using System.Drawing;
using System.Windows.Forms;
public class MyTextBox : TextBox
{
public MyTextBox()
{
BorderStyle = System.Windows.Forms.BorderStyle.None;
AutoSize = false; //Allows you to change height to have bottom padding
Controls.Add(new Label()
{ Height = 1, Dock = DockStyle.Bottom, BackColor = Color.Black });
}
}
Related
I have a form with rounded borders by codes below:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Form1()
{
InitializeComponent();
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
But the problem is:When I Maximize the form, It doesn't maximize correctly.
It Maximizes like this:Image
Please Help Me...
I Found The Answer ...
I should clear the all borders that I set before like this:
private void btnMaximize_Click(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
btnMaximize.Image = Properties.Resources.maximize_Black;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
else
{
this.WindowState = FormWindowState.Maximized;;
btnMaximize.Image = Properties.Resources.maximize_Black_copy;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 0, 0));
}
}
Thanks For All Friends Wanted To Help Me.
I have a form with it's FormBorderStyle set to Sizable. This creates the grip in the bottom right. The only way to resize the window is to get your mouse right exactly on the edge. I'm wondering if there is a way to change the cursor to be able to resize when the user mouses over the grip, or if I can increase the range at which it will allow you to resize on the edge so that you don't have to be so precise with your mouse location.
Here is a link to a similar SO question. This guy has no borders, so you may have to do it a little differently, but should give you a direction to go in. I will repaste his code here for completion:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
private const int cGrip = 16; // Grip size
private const int cCaption = 32; // Caption bar height;
protected override void OnPaint(PaintEventArgs e) {
Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
}
protected override void WndProc(ref Message m) {
if (m.Msg == 0x84) { // Trap WM_NCHITTEST
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
pos = this.PointToClient(pos);
if (pos.Y < cCaption) {
m.Result = (IntPtr)2; // HTCAPTION
return;
}
if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {
m.Result = (IntPtr)17; // HTBOTTOMRIGHT
return;
}
}
base.WndProc(ref m);
}
}
try this
yourObject.Cursor = Cursors.SizeAll;
More on this site: MSDN
Is it possible to change the BackColor of ToolStripSeparator control?
There is a BackColor property in the designer, but it doesn't appear to be used - the color is always white.
I just pointed my separators' Paint event to this custom proc:
private void mnuToolStripSeparator_Custom_Paint (Object sender, PaintEventArgs e)
{
ToolStripSeparator sep = (ToolStripSeparator)sender;
e.Graphics.FillRectangle(new SolidBrush(CUSTOM_COLOR_BACKGROUND), 0, 0, sep.Width, sep.Height);
e.Graphics.DrawLine(new Pen(CUSTOM_COLOR_FOREGROUND), 30, sep.Height / 2, sep.Width - 4, sep.Height / 2);
}
Where the CUSTOM_COLOR_FOREGROUND is a solid/named Color, such as Color.White for example.
I see the question was asked 2 years ago, but I still can't find a simple and clear solution for this on the web. So...
I've just faced the problem today and found that it's pretty simple to solve it.
Having the same situation:
Solution:
Create a class which inherits the ToolStripSeparator class and add a method to the Paint EventHandler to draw the separator:
public class ExtendedToolStripSeparator : ToolStripSeparator
{
public ExtendedToolStripSeparator()
{
this.Paint += ExtendedToolStripSeparator_Paint;
}
private void ExtendedToolStripSeparator_Paint(object sender, PaintEventArgs e)
{
// Get the separator's width and height.
ToolStripSeparator toolStripSeparator = (ToolStripSeparator)sender;
int width = toolStripSeparator.Width;
int height = toolStripSeparator.Height;
// Choose the colors for drawing.
// I've used Color.White as the foreColor.
Color foreColor = Color.FromName(Utilities.Constants.ControlsRelatedConstants.standardForeColorName);
// Color.Teal as the backColor.
Color backColor = Color.FromName(Utilities.Constants.ControlsRelatedConstants.standardBackColorName);
// Fill the background.
e.Graphics.FillRectangle(new SolidBrush(backColor), 0, 0, width, height);
// Draw the line.
e.Graphics.DrawLine(new Pen(foreColor), 4, height / 2, width - 4, height / 2);
}
}
Then add the separator:
ToolStripSeparator toolStripSeparator = new ExtendedToolStripSeparator();
this.DropDownItems.Add(newGameToolStripMenuItem);
this.DropDownItems.Add(addPlayerToolStripMenuItem);
this.DropDownItems.Add(viewResultsToolStripMenuItem);
// Add the separator here.
this.DropDownItems.Add(toolStripSeparator);
this.DropDownItems.Add(exitToolStripMenuItem);
Result:
The default toolstrip renderer ignores the BackColor property and uses hard-coded colors.
You can refer following link to use your own renderer to paint the separators the way you want them.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
toolStrip1.Renderer = new MyRenderer();
}
private class MyRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
if ((e.Item as ToolStripSeparator) == null)
{
base.OnRenderSeparator(e);
return;
}
Rectangle bounds = new Rectangle(Point.Empty, e.Item.Size);
bounds.Y += 3;
bounds.Height = Math.Max(0, bounds.Height - 6);
if (bounds.Height >= 4)
bounds.Inflate(0, -2);
int x = bounds.Width / 2;
using(Pen pen = new Pen(Color.DarkBlue))
e.Graphics.DrawLine(pen, x, bounds.Top, x, bounds.Bottom - 1);
using (Pen pen = new Pen(Color.Blue))
e.Graphics.DrawLine(pen, x + 1, bounds.Top + 1, x + 1, bounds.Bottom);
}
}
}
Source: http://social.msdn.microsoft.com/forums/en-US/winforms/thread/6cceab5b-7e06-40cf-82da-56cdcc57eb5d
I am reading data from a file and would like to attach a progress bar to this operation. I found the following code on stackoverflow - this code is due to William Daniel, Sept 20, stackoverflow post titled, " How to Change Color of Progress Bar in C#.Net 3.5"
class CustomProgressBar : ProgressBar
{
public CustomProgressBar()
{
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// None... Helps control the flicker.
}
protected override void OnPaint(PaintEventArgs e)
{
const int inset = 2;
using (Image offscreenImage = new Bitmap(this.Width, this.Height))
{
using (Graphics offscreen = Graphics.FromImage(offscreenImage))
{
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
if (ProgressBarRenderer.IsSupported)
ProgressBarRenderer.DrawHorizontalBar(offscreen, rect);
rect.Inflate(new Size(-inset, -inset)); // Deflate inner rectangle
rect.Width = (int)(rect.Width * ((double)this.Value / this.Maximum));
if (rect.Width == 0) rect.Width = 1;
LinearGradientBrush brush = new LinearGradientBrush(rect,
this.BackColor, this.ForeColor, LinearGradientMode.Vertical);
offscreen.FillRectangle(brush, inset, inset, rect.Width, rect.Height);
e.Graphics.DrawImage(offscreenImage, 0, 0);
offscreenImage.Dispose();
}
}
}
}
The code works fine except the following:
The gradient does not seem to extend the entire width of the bar. It is there but is much more heavily concentrated near the bottom of the bar and thins out very quickly as we get to the top of the bar. Any suggestions as to how I can fix this?
If I place the progress bar on a form and open an Internet Explorer window over the portion of the form with the progress bar on it, some of the text from the internet window bleeds onto the progress bar in the form. I have no idea why, and how to fix this.
As an aside, how does one estimate the length of an operation that you wish to show via a progress bar?
Any help would be greatly appreciated. Thank you.
As for first part of your question - try using following constructor for your brush:
new LinearGradientBrush(new Point(0, 0), new Point(0, Height - inset * 2), BackColor, ForeColor);
Your current brush has top control point at Y=inset - that's why area from Y=0 to Y=inset is all painted in solid color.
You are not drawing at all in the non-filled portion of your progressbar. Try calling FillRectangle for area from rect.Right to this.Width with background color. It should prevent bleeding from overlapping windows.
try this one, you don't need on each paint to create an image...
class CustomProgressBar : ProgressBar
{
public CustomProgressBar()
{
this.SetStyle(ControlStyles.UserPaint|ControlStyles.OptimizedDoubleBuffer|ControlStyles.DoubleBuffer, true);
this.UpdateStyles();
}
protected override void OnPaint(PaintEventArgs e)
{
const int inset = 2;
Rectangle rect = this.ClientRectangle;
var offscreen = e.Graphics;
if (ProgressBarRenderer.IsSupported){
ProgressBarRenderer.DrawHorizontalBar(offscreen, rect);
}
rect.Inflate(new Size(-inset, -inset)); // Deflate inner rectangle
rect.Width = Convert.ToInt32(Math.Round((rect.Width * ((double)this.Value / this.Maximum))));
if (rect.Width == 0) rect.Width = 1;
LinearGradientBrush brush = new LinearGradientBrush(rect,this.BackColor, this.ForeColor, LinearGradientMode.Vertical);
offscreen.FillRectangle(brush, inset, inset, rect.Width, rect.Height);
offscreen.DrawString(Value.ToString(), this.Font,Brushes.Black,rect);
}
}
use
const int inset = 1;
for your other question
I have drawn a rectangle. It is undreneath a horizontal scroll bar on screen. Now i want to zoom the rectangle. On zooming the height of rectangle increases, the location shifts up and horizontal scroll bar moves up. How to do this? I am writing this piece of code:
rect = new Rectangle(rect.Location.X, this.Height - rect.Height,rect.Width, Convert.ToInt32(rect.Size.Height * zoom));
g.FillRectangle(brush, rect);
This works for the location of the rectangle that is the rectangle shifts up but the height doesn't increase. Help!
If you simply want to scale the rectangle around the center of the rectangle then you need to increase the width and height of the rectangle and subtract half the increase from the location.
This is not tested, but should give you the general idea
double newHeight = oldHeight * scale;
double deltaY = (newHeight - oldHeight) * 0.5;
rect = new Rectangle(
rect.Location.X, (int)(rect.Location.Y - deltaY),
rect.Width, (int)newHeight);
Possibly a better alternative would be to look at using Graphics.ScaleTransform.
Just add a txtZoom to your form:
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.txtZoom.Text = "1";
this.txtZoom.KeyDown += new KeyEventHandler(txtZoom_KeyDown);
this.txtZoom_KeyDown(txtZoom, new KeyEventArgs(Keys.Enter));
}
void txtZoom_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Enter)
{
this.Zoom = int.Parse(txtZoom.Text);
this.Invalidate();
}
}
public int Zoom { get; set; }
protected override void OnPaint(PaintEventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new Rectangle(10, 10, 100, 100));
Matrix m = new Matrix();
m.Scale(Zoom, Zoom);
path.Transform(m);
this.AutoScrollMinSize = Size.Round(path.GetBounds().Size);
e.Graphics.FillPath(Brushes.Black, path);
}
}
}