Ownerdrawn TreeView (WinForms) - c#

I have a TreeView control with checkboxes which is completely owner drawn (DrawMode = TreeViewDrawMode.OwnerDrawAll).
What I'm trying to do is to have the checkboxes owner drawn, so that they can have a grayed state. I'm using VisualStyleRenderer for this.
The problem arises when I have to correctly place the expand/collapse glyph and the checkbox in the item bounds, because the "hit-test areas" for both the glyph and the checkbox seems to be unknown and unchangeable.
Is there a way to get the bounds of those areas, or to replace the default ones with custom values?

I ran into the same problem. You have to offset your drawing by the proper amount, which is predictable.
There's probably more here than you need, but here's my drawing for a custom tree I used alongside a calendar control:
private void TreeViewControl_DrawNode(Object sender, DrawTreeNodeEventArgs e)
{
//What might seem like strange positioning/offset is to ensure that our custom drawing falls in
// line with where the base drawing would appear. Otherwise, click handlers (hit tests) fail
// to register properly if our custom-drawn checkbox doesn't fall within the expected coordinates.
Int32 boxSize = 16;
Int32 offset = e.Node.Parent == null ? 3 : 21;
Rectangle bounds = new Rectangle(new Point(e.Bounds.X + offset, e.Bounds.Y + 1), new Size(boxSize, boxSize));
ControlPaint.DrawCheckBox(e.Graphics, bounds, e.Node.Checked ? ButtonState.Checked : ButtonState.Normal);
if (e.Node.Parent != null)
{
Color c = Color.Black;
String typeName = e.Node.Name.Remove(0, 4);
Object o = Enum.Parse(typeof(CalendarDataProvider.CalendarDataItemType), typeName);
if (o != null && (o is CalendarDataProvider.CalendarDataItemType))
c = CalendarDataProvider.GetItemTypeColor((CalendarDataProvider.CalendarDataItemType)o);
bounds = new Rectangle(new Point(bounds.X + boxSize + 2, e.Bounds.Y + 1), new Size(13, 13));
using (SolidBrush b = new SolidBrush(c))
e.Graphics.FillRectangle(b, bounds);
e.Graphics.DrawRectangle(Pens.Black, bounds);
e.Graphics.DrawLine(Pens.Black, new Point(bounds.X + 1, bounds.Bottom + 1), new Point(bounds.Right + 1, bounds.Bottom + 1));
e.Graphics.DrawLine(Pens.Black, new Point(bounds.Right + 1, bounds.Y + 1), new Point(bounds.Right + 1, bounds.Bottom + 1));
}
Font font = new Font("Microsoft Sans Serif", 9f, e.Node.Parent == null ? FontStyle.Bold : FontStyle.Regular);
bounds = new Rectangle(new Point(bounds.X + boxSize + 2, e.Bounds.Y), new Size(e.Bounds.Width - offset - 2, boxSize));
e.Graphics.DrawString(e.Node.Text, font, Brushes.Black, bounds);
}

Related

Creating vertical lines inside panel in WinForm

I am trying to create vertical lines inside a panel in my winform application. I am able to draw the lines but they are not what I am expecting to be. My requirements are:
The lines must be drawn from the middle of the panel vertically.
The lines must be drawn on both the sides with equal height.
The problem is when I am trying to draw the lines they are drawn from top of the panel and are upside down.
My target is to get something like:
This is how I am trying to do it:
public void DrawLines(System.Drawing.Graphics g, float height)
{
Pen thePen = new Pen(Color.Red, 1.0F);
PointF[] points1 =
{
new PointF(5,5),
new PointF(5, 50)
};
PointF[] points2 =
{
new PointF(7,5),
new PointF(7, 60)
};
PointF[] points3 =
{
new PointF(9,5),
new PointF(9, 55)
};
//Tried this as well
//PointF[] points1 =
// {
// new PointF(5,50),
// new PointF(5, 5)
// };
//PointF[] points2 =
// {
// new PointF(7,60),
// new PointF(7, 5)
// };
//PointF[] points3 =
// {
// new PointF(9,55),
// new PointF(9, 5)
// };
g.DrawLines(thePen, points1);
g.DrawLines(thePen, points2);
g.DrawLines(thePen, points3);
}
Right now I am calling this function on button click.
DrawLines(panel1.CreateGraphics(), 20.0F);
In real time this will be called inside a loop and line height will be passed as a parameter.
As already commented, Y coordinates are flipped when drawing on the Panel. You can test this by simply displaying mouse coordinates.
To draw the Lines you want to get the Middle of the panel and work from there. In your example you had an unused height variable, so i added funtionality to that. Here is a working example.
public MyForm()
{
InitializeComponent();
_myPen = new Pen(Color.Red, 1.0F);
}
private Pen _myPen;
private void DrawLines(Graphics g, int width = 0, int height = 0)
{
// Get the middle of the panel
int panelMiddle = panel.Height / 2;
// Lines going up from the mittle
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 5, height + panelMiddle -5),
new PointF(width + 5, height + panelMiddle - 50)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 7, height + panelMiddle-5),
new PointF(width + 7, height + panelMiddle - 60)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 9, height + panelMiddle-5),
new PointF(width + 9, height + panelMiddle - 55)
});
// Lines going down from the middle
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 5, height + panelMiddle +5),
new PointF(width + 5, height + panelMiddle + 50)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 7, height + panelMiddle+5),
new PointF(width + 7, height + panelMiddle + 60)
});
g.DrawLines(_myPen,
new PointF[]
{
new PointF(width + 9, height + panelMiddle+5),
new PointF(width + 9, height + panelMiddle + 55)
});
}
private void panel_Paint(object sender, PaintEventArgs e)
{
DrawLines(e.Graphics);
DrawLines(e.Graphics,panel.Width - 14);
}

Xna menu items transparent

Trying to create a game in Xna but i have stumbled upon a problem that i cannot seem to figure out.
What i'm trying to do is to draw a menu at the top of the screen, and it shows up. But I'm having a weird problem.
All of the menu items are alpha even though the only place i specify something to be alpha is the background to the menu, is there something obvious that i'm missing here?
public static void draw(SpriteBatch sb,SpriteFont font,GraphicsDevice gd)
{
foreach (string item in menuItems)
{
MouseState ms = Mouse.GetState();
rect.drawRectangle(gd, sb, new Rectangle(0, 0, gd.Viewport.Width, 35), new Color(0.25f, 0.25f, 0.25f, 0.6f));
if((ms.X > startPos && ms.X < startPos + (int)font.MeasureString(item).X) && (ms.Y > 10 && ms.Y < 30))
{
if(ms.LeftButton != ButtonState.Pressed)
{
sb.DrawString(font, item, new Vector2(startPos, 10), Color.Black);
sb.DrawString(font, item, new Vector2(startPos + 1, 11), Color.Gray);
}else
{
sb.DrawString(font, item, new Vector2(startPos, 10), Color.Black);
sb.DrawString(font, item, new Vector2(startPos + 1, 11), Color.DarkGray);
}
}
else
{
sb.DrawString(font, item, new Vector2(startPos, 10), Color.Black);
sb.DrawString(font, item, new Vector2(startPos + 1, 11), Color.White);
}
startPos += (10 + (int)font.MeasureString(item).X);
}
startPos = 10;
}
rect class:
public static void drawRectangle(GraphicsDevice graphics,SpriteBatch sb,Rectangle rect,Color color)
{
Texture2D pixel = new Texture2D(graphics, 1, 1);
Color[] colorData = {color};
pixel.SetData<Color>(colorData);
sb.Draw(pixel, rect, color);
}
I have tried to create a new color with no alpha, but i get the same results.
I figured it out!
Had to move
rect.drawRectangle(gd, sb, new Rectangle(0, 0, gd.Viewport.Width, 35), new Color(0.25f, 0.25f, 0.25f,0.6f));
Outside the loop.

C# DrawNode actualize

I have a problem with Treeview. I just put only color square into node text, so I overwrite function "treeView1_DrawNode".
I have a lot of nodes, about 100 and I actualize text of them every 5 seconds.
Problem is with actualization. When I actualize one node function "DrawNode" is working for entire nodes. It take a lot of time and it make artefacts on the screen.
Function is really simple.
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
Rectangle tempRect = new Rectangle(e.Bounds.X + 1, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
if (e.Node.IsSelected)
{
e.Graphics.FillRectangle(Brushes.White, tempRect);
}
SolidBrush redBrush = new SolidBrush(e.Node.BackColor);
e.Graphics.FillRectangle(redBrush, e.Bounds.X + 2, e.Bounds.Y + 2, 12, 12);
e.Graphics.DrawRectangle(Pens.Aqua, e.Bounds.X + 2, e.Bounds.Y + 2, 12, 12);
tempRect = new Rectangle(e.Bounds.X + 12, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height);
TextRenderer.DrawText(e.Graphics,
e.Node.Text,
e.Node.TreeView.Font,
tempRect,
e.Node.ForeColor);
}

How to create a form in shape of rhomb?

How to create a form in shape of rhomb?
I managed to create a shape in form of ellipse with the help of this:
private void Form1_Load(object sender, EventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath();
myPath.AddEllipse(45, 60, 200, 200);
Region myRegion = new Region(myPath);
this.Region = myRegion;
}
How can I do it but making rhomb?
Use myPath.AddLines instead of the myPath.AddEllipse:
private void Form1_Load(object sender, EventArgs e)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(0, Height / 2),
new Point(Width / 2, 0),
new Point(Width, Height / 2),
new Point(Width / 2, Height)
});
Region = new Region(myPath);
}
}
Above answer by #Dmitry helped me a lot. However, it does not draw a complete rhombus, as claimed. The last segment is not drawn due to absent final point, which must coincide with the starting point. Line array should contain five points, not four.
I have made some corrections and come up with this function, which draws a rhombus withing a given rectangle:
private void DrawRhombus(Graphics graphics, Rectangle rectangle)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y),
new Point(rectangle.X + rectangle.Width, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y + rectangle.Height),
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2))
});
using (Pen pen = new Pen(Color.Black, 1))
graphics.DrawPath(pen, myPath);
}
}

Animated bar in progress bar winform

I'm writing an extended progress bar control at present, 100% open source and I've created some basic styles with gradients and solid colours.
One of the options I wanted to add was animation to the bar, prety much like the windows 7 and vista green progress bar. So I need to add a moving "Glow" to the % bar, however my attempt at this looks terrible.
My method is to draw an ellipse with set size and move it's x position until it reaches the end were the animation starts again.
First of does anyone have nay links or code to help me achieve the current windows 7 glow effect using GDI or some similar method?
I have several other animations that will also be added the the bar hence the GDI.
private void renderAnimation(PaintEventArgs e)
{
if (this.AnimType == animoptions.Halo)
{
Rectangle rec = e.ClipRectangle;
Rectangle glow = new Rectangle();
//SolidBrush brush = new SolidBrush(Color.FromArgb(100, Color.White));
//int offset = (int)(rec.Width * ((double)Value / Maximum)) - 4;
int offset = (int)(rec.Width / Maximum) * Value;
if (this.animxoffset > offset)
{
this.animxoffset = 0;
}
glow.Height = rec.Height - 4;
if (this.animxoffset + glow.X > offset)
{
glow.Width = offset - (this.animxoffset + 50);
}
else
{
glow.Width = 50;
}
glow.X = this.animxoffset;
LinearGradientBrush brush = new LinearGradientBrush(glow, Color.FromArgb(0, Color.White), Color.FromArgb(100, Color.White), LinearGradientMode.Horizontal);
e.Graphics.FillEllipse(brush, this.animxoffset, 2, glow.Width, glow.Height);
brush.Dispose();
string temp = offset.ToString();
e.Graphics.DrawString(temp + " : " + glow.X.ToString(), DefaultFont, Brushes.Black, 2, 2);
animTimer = new System.Timers.Timer();
animTimer.Interval = 10;
animTimer.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
animTimer.Start();
}
}
void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.animTimer.Stop();
this.animxoffset += 2;
Invalidate();
}
This is just an example glow iterating through a pen array.
You could also use a transparent image (although it could have a performance impact).
Pen[] gradient = { new Pen(Color.FromArgb(255, 200, 200, 255)), new Pen(Color.FromArgb(150, 200, 200, 255)), new Pen(Color.FromArgb(100, 200, 200, 255)) };
int x = 20;
int y = 20;
int sizex = 200;
int sizey = 10;
int value = 25;
//draw progress bar basic outline (position - 1 to compensate for the outline)
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(x-1, y-1, sizex, sizey));
//draw the percentage done
e.Graphics.FillRectangle(Brushes.AliceBlue, new Rectangle(x, y, (sizex/100)*value, sizey));
//to add the glow effect just add lines around the area you want to glow.
for (int i = 0; i < gradient.Length; i++)
{
e.Graphics.DrawRectangle(gradient[i], new Rectangle(x - (i + 1), y - (i + 1), (sizex / 100) * value + (2 * i), sizey + (2 * i)));
}

Categories

Resources