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);
}
Related
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);
}
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);
}
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);
}
}
hello I write code which gives the drive list, capacity and free size the drives. I want to draw pie graphics according to size of each drive, like this:
Here is the code I have so far - The size values are in the freeSize and fullSize variables
string[] drivers = new string[5];
int freeSize;
int fullSize;
private void Form1_Load(object sender, EventArgs e)
{
foreach (var item in System.IO.Directory.GetLogicalDrives())
{
int i = 0;
drivers[i] = item;
comboBox1.Items.Add(drivers[i]);
++i;
}
}
private void btnSorgula_Click(object sender, EventArgs e)
{
string a = comboBox1.Items[comboBox1.SelectedIndex].ToString();
System.IO.DriveInfo di = new System.IO.DriveInfo(a);
if (!di.IsReady)
{
MessageBox.Show("not ready");
return;
}
decimal freeByt= Convert.ToDecimal(di.TotalFreeSpace);
decimal freeGb = freeByt / (1024 * 1024*1024);
label1.Text = freeGb.ToString();
freeSize = Convert.ToInt32(freeGb);
decimal totalByt = Convert.ToDecimal(di.TotalSize);
decimal tottalGb = totalByt / (1024 * 1024 * 1024);
label2.Text = Convert.ToString(tottalGb);
fullSize = Convert.ToInt32(tottalGb);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rect = new Rectangle(10, 10, 100, 100);
g.FillPie(Brushes.Black, rect, fullSize, fullSize / freeSize);
g.FillPie(Brushes.RoyalBlue, rect, 140, 100);
}
How about this one:
private Image GetCake(int width, int height, double percentage)
{
var bitmap = new Bitmap(width, height);
using (var g = Graphics.FromImage(bitmap))
{
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.FillEllipse(Brushes.DarkMagenta, 1, 9, width - 2, height - 10);
g.DrawEllipse(Pens.Black, 1, 9, width - 2, height - 10);
g.FillPie(Brushes.DarkBlue, 1, 9, width - 2, height - 10, 0, (int)(360 * percentage));
g.DrawPie(Pens.Black, 1, 9, width - 2, height - 10, 0, (int)(360 * percentage));
g.FillEllipse(Brushes.Magenta, 1, 1, width - 2, height - 10);
g.DrawEllipse(Pens.Black, 1, 1, width - 2, height - 10);
g.FillPie(Brushes.Blue, 1, 1, width - 2, height - 10, 0, (int)(360 * percentage));
g.DrawPie(Pens.Black, 1, 1, width - 2, height - 10, 0, (int)(360 * percentage));
g.DrawArc(Pens.Blue, 1, 1, width - 2, height - 10, 0, (int)(360 * percentage));
}
return bitmap;
}
You could call it with:
myPictureBox.Image = GetCake(myPictureBox.Width, myPictureBox.Height, 0.4);
The 0.4 means 40%. So fill in any value between 0 and 1 to set the desired percentage.
The problem with your code is that Form1_Paint is called when ever the form is drawn, e.g. right after start up when it is first shown. At that point of time the button has not yet been clicked and freeSize therefore is 0.
To fix the problem, change the code so that it only paints when the button has been clicked at least once.
Having a bit of a drawing complication you would call it. My math is a bit rusty when it comes to Matrices and drawing rotations on shapes. Here is a bit of code:
private void Form1_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
DoRotation(e);
g.DrawRectangle(new Pen(Color.Black), r1);
g.DrawRectangle(new Pen(Color.Black), r2);
// draw a line (PEN, CenterOfObject(X, Y), endpoint(X,Y) )
g.DrawLine(new Pen(Color.Black), new Point((r1.X + 50), (r1.Y + 75)), new Point((/*r1.X + */50), (/*r1.Y - */25)));
this.lblPoint.Text = "X-pos: " + r1.X + " Y-pos: " + r1.Y;
//this.Invalidate();
}
public void DoRotation(PaintEventArgs e)
{
// move the rotation point to the center of object
e.Graphics.TranslateTransform((r1.X + 50), (r1.Y + 75));
//rotate
e.Graphics.RotateTransform((float)rotAngle);
//move back to the top left corner of the object
e.Graphics.TranslateTransform(-(r1.X + 50), -(r1.Y + 75));
}
public void Form1_KeyDown(object sender, KeyEventArgs e)
{
case Keys.T:
rotAngle += 1.0f;
}
when I rotate (what I think should be r1) both r1 and r2 rotate. I need to be able to rotate each shape individually as I add more shapes.
I would use a function similar to this:
public void RotateRectangle(Graphics g, Rectangle r, float angle) {
using (Matrix m = new Matrix()) {
m.RotateAt(angle, new PointF(r.Left + (r.Width / 2),
r.Top + (r.Height / 2)));
g.Transform = m;
g.DrawRectangle(Pens.Black, r);
g.ResetTransform();
}
}
It uses a matrix to perform the rotation at a certain point, which should be the middle of each rectangle.
Then in your paint method, use it to draw your rectangles:
g.SmoothingMode = SmoothingMode.HighQuality;
//g.DrawRectangle(new Pen(Color.Black), r1);
//DoRotation(e);
//g.DrawRectangle(new Pen(Color.Black), r2);
RotateRectangle(g, r1, 45);
RotateRectangle(g, r2, 65);
Also, here is the line to connect the two rectangles:
g.DrawLine(Pens.Black, new Point(r1.Left + r1.Width / 2, r1.Top + r1.Height / 2),
new Point(r2.Left + r2.Width / 2, r2.Top + r2.Height / 2));
Using these settings:
private Rectangle r1 = new Rectangle(100, 60, 32, 32);
private Rectangle r2 = new Rectangle(160, 100, 32, 32);
resulted in: