C# TreeView DrawNode : How to add the badge images in the TreeNodes? - c#

I want to add just the badge images in the right of the TreeNodes.
The expand/Collapse buttons, icons and texts shouldn't be changed.
I used the following code :
public void treeView_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
e.DrawDefault = true;
e.Graphics.DrawImage(image1, e.Bounds.Right - 30, e.Bounds.Y);
}
However, if the text of the treenode was long, it was over the image. The badge is invisible.
I think that e.DrawDefault = true; may affect after the function returns.
How can I show the badge images without redrawing the texts and icons?

Related

ListBox draw size does not change with change to larger font size

When I increase the font size in my ListBox, the larger text strings get vertically clipped because the item draw rectangle size (spacing) does not increase with the font size. Each lower line of text overlays the previous line of text so that only the tops of letters show in larger font sizes.
Everything works fine with DrawMode.OwnerDrawFixed if I don't change the font sizes. Smaller-than-normal fonts display properly. It's only the larger fonts that get clipped. I changed to DrawMode.OwnerDrawVariable and added a MeasureItem event handler to measure the larger font size explicitly, but that did not work either.
What am I missing? Thank you.
UPDATE: I provided working code below based on #Jimi's examples in the links he provided in his comments. I was missing the idea that the MeasureItem event runs only once (or when necessary) and not for each drawn item. Thus, you must manually trigger a new MeasureItem event when you change the font size in the ListBox. The trick to generating the event is to flip the DrawMode.OwnerDrawVariable to Normal and back.
listBox1.DrawMode = DrawMode.OwnerDrawVariable;
listBox1.DrawItem += DrawItemHandler;
listBox1.MeasureItem += MeasureItemHandler;
private void MeasureItemHandler(object sender, MeasureItemEventArgs e) {
// must measure the height to allow for user font size changes
var listBox = (ListBox) sender;
e.ItemHeight = listBox.Font.Height;
}
public void DrawItemHandler(object sender, DrawItemEventArgs e) {
// prepare text and colors for drawing here
//
using (var bgbrush = new SolidBrush(bgcolor)) {
using (var fgbrush = new SolidBrush(fgcolor)) {
e.Graphics.FillRectangle(bgbrush, e.Bounds);
e.Graphics.DrawString(logEntry.EntryText, e.Font, fgbrush, e.Bounds);
}
}
e.DrawFocusRectangle();
}
private void fontUpToolStripMenuItem_Click(object sender, EventArgs e) {
// To increase size alone, use the original font family
var size = listBox1.Font.Size;
if (size < 32) {
// set the new font size, register it with the list box, and then
// flip the draw mode back and forth to trigger a MeasureItem event.
// The measure event will recalculate the bounds for all items in the box.
listBox1.Font = new Font(listBox1.Font.FontFamily, size + 1);
listBox1.Height = listBox1.Font.Height;
listBox1.DrawMode = DrawMode.Normal;
listBox1.DrawMode = DrawMode.OwnerDrawVariable;
listBox1.Invalidate();
}
}

How to set the margins of text box red if error is present

I was just wondering if its was easily possible to set the margins of a textbox a particular color? Im using winforms and in my validating event handlers i have a series of error providers, which if return false I want to set just the margins red and if successful green. is this possible with out having a any controls hidden behind ? I know how to set the foreground and panel colour but it just seems so sloppy to have to have this all hidden behind it. this is my validating event handler.
private void txt_LndLine_Validating(object sender, CancelEventArgs e)
{
if (utility.isNum,(txt_LndLine.Text))
{
epLandline.SetError(txt_LndLine, "Please use unknown Entity!!!");
return;
}
else
{
epLandline.Clear();
_IsValid = true;
}
}
Just a query, as the event hadnler works fine just wouldn't mind a smarter way of presenting the errors rather than the icon
Here is an alternative solution, which won't add any extra controls. It paints the border onto the TextBoxes' Parent.
Set it up by hooking the routine into the Paint event of your TextBox's Parent once, maybe like this:
textBox1.Parent.Paint += DrawMargins;
Now you can set the Tag to hold the Brush you want to use:
textBox1.Tag = Brushes.Red;
textBox2.Tag = Brushes.Green;
After changing the Brush you need to trigger the routine, by Invalidating the Parent:
textBox1.Parent.Invalidate();
To take one TextBox out of the painting reset the Tag to null:
textBox1.Tag = null;
You can also un-hook the whole event of course:
textBox1.Parent.Paint -= DrawMargins;
Here is the drawing method:
private void DrawMargins(object sender, PaintEventArgs e)
{
Control parent = sender as Control;
foreach ( Control ctl in parent.Controls)
{
SolidBrush brush = ctl.Tag as SolidBrush;
if (brush == null) continue;
e.Graphics.FillRectangle(brush, ctl.Left - ctl.Margin.Left,
ctl.Top - ctl.Margin.Top,
ctl.Width + ctl.Margin.Horizontal,
ctl.Height + ctl.Margin.Vertical);
}
}
Note that this will work for any control which has a SolidBrush in the Tag and is a child of the same parent. If some controls as nested, say in a Panel or a GroupBox, I guees you should replace the loop over the parent.Controls collection by a List<Control> of the participating controls..
I have enlarged the left margin of the 1st TextBox, as you can see..
May be the answer in comments is a good one (#RudyTheHunter).
I have a simple way of doing.
Put a panel control right below the text box and change the border color of the panel.
I tried it and looks as shown in below image.
Code:
if (utility.isNum,(txt_LndLine.Text))
{
epLandline.SetError(txt_LndLine, "Please use unknown Entity!!!");
//PANEL COLOR
this.panel1.BackColor = System.Drawing.Color.Green;
this.panel1.Padding = new System.Windows.Forms.Padding(5);
return;
}
else
{
epLandline.Clear();
//PANEL COLOR
this.panel1.BackColor = System.Drawing.Color.Red;
this.panel1.Padding = new System.Windows.Forms.Padding(5);
_IsValid = true;
}

Click on image and show message box depending on the clicked place

I have this idea of this world map image and when I click a country on it, it shows information of that country in a MessageBox for example does anyone have an idea how to do that?
I have a rectangle and a button and when i click the button it shows the image in the rectangle but i thought if i use polygons to shape the country's but I'm a little stuck.
I would like to have every country apart and maybe that the borders light up when clicked
You can do this pretty easily using WPF:
Find a nice World Map in SVG format. I used this one from Wikipedia:
Download and install Inkscape then open the SVG you've just downloaded. Inkscape has a nice feature that makes it possible to save an SVG as a XAML.
Import the ViewBox from the XAML file into your WPF window/etc:
For each Path in the XAML you can add a MouseEnter/MouseLeave event handler or you can use the same one for all the Paths
Sample code:
private void CountryMouseEnter(object sender, MouseEventArgs e)
{
var path = sender as Path;
if (path != null)
{
path.Fill = new SolidColorBrush(Colors.Aqua);
}
}
private void Country_MouseLeave(object sender, MouseEventArgs e)
{
var path = sender as Path;
if (path != null)
{
path.Fill = new SolidColorBrush(Colors.Black);
}
}
Now it's just a matter of changing colors/showing MessageBoxes etc.
GitHub
My first thought: You could bind a command to the view that will be triggered by a click on a position. If you're using WPF you can bind command parameters to the command to get the x and y of your click...
After that you have to handle the content of your messagebox and the highlighting of the borders depending on the position xy.
have fun :D
Option 1
There is a project on Code Project that someone created that defines hotspots that are clickable with events. You could use that to overlay your map and define the hotspots where you need them.
C# Windows Forms ImageMap Control
Option 2
You could bind to the MouseUp Event on the Image and use the following to see if it is in a Rectangle
private void mapMouseUp(object sender, MouseEventArgs e) {
Rectangle rect1 = new Rectangle(0, 0, 100, 100);
Rectangle rect2 = new Rectangle(0, 100, 100, 100);
if (rect1.Contains(e.Location)) {
// Do your stuff
} else if (rect2.Contains(e.Location)) {
// Do your stuff
}
}

Paint event of panel not called when shrinking Form from right to left?

I have a Form which has got a parent panel and it had got a child panel where I am drawing items using the drawing mechanism it works good as expected, but when I shrink my form from right to left it doesn't call child panels paint event while if I shrink a little from left to right and again spread it then it calls the paint event, how should I fix it?
Below is my code.
private void canvas_Paint(object sender, PaintEventArgs e)
{
drawString(e);
this.Invalidate();
//this.Refresh();
//this.Update();
}
private void drawString(PaintEventArgs e)
{
System.Drawing.Drawing2D.LinearGradientBrush myBrush = new System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle, Color.Red, Color.Yellow, System.Drawing.Drawing2D.LinearGradientMode.Horizontal);
cBasketItemHelper objHelper = new cBasketItemHelper() { CanvasWidth = this.canvas.Width, CanvasHeight = this.canvas.Height, X = 3, Y = 3 };
objHelper.myBrush = myBrush;
objHelper.currOrder = Program.currOrder;
objHelper.g = e.Graphics;//this.canvas.();//this.canvas.Graphics;
objHelper.DrawBasketItems();
e.Dispose();
}
The Panel class was designed to be just a container for other controls, it is not expected to do any painting of its own beyond drawing the background. Somewhat heavy-handedly it optimizes the painting, a resize only paints the parts that were revealed, not the entire client area.
You however want OnPaint to always run when the size changes, even when you make it smaller. Derive your own class from Panel and set the ResizeRedraw property to true in the constructor:
class Canvas {
public Canvas() {
this.ResizeRedraw = true;
this.DoubleBuffered = true; // extra goodie
}
}
Build. Drop the new Canvas control from the top of the toolbox, replacing your existing panel control. If you don't need the scrolling support that Panel provides then using a PictureBox gets you both without needing to derive.

Stretch tab headers instead of tab pages in tab control when resizing

I am owner-drawing a left-oriented tabcontrol in winforms.
Each tabpage has a fixed size, so when the UI is stretched wide, I would like the ItemSize width of the tab headers to increase correspondingly.
private void tbcTests_Resize( object sender, EventArgs e )
{
tbcTests.ItemSize = new Size(
tbcTests.Width - tbcTests.TabPages[0].Controls[0].Width - tbcTests.Padding.X,
tbcTests.ItemSize.Height );
}
This code results in a stack overflow. I suspect this is because the resize is done using incorrect dimensions, forcing the control to continuously redraw. However, I am unsure how to fix it. Am I not accounting for excess space correctly?
How should I resize the tab headers and using what dimensions?
Changing the ItemSize property cause the Resize event to fire again. You'll need a helper variable to suppress the nested event. Like this:
private bool busySizing;
private void tbcTests_Resize( object sender, EventArgs e )
{
if (busySizing) return;
busySizing = true;
try {
tbcTests.ItemSize = new Size(
tbcTests.Width - tbcTests.TabPages[0].Controls[0].Width - tbcTests.Padding.X,
tbcTests.ItemSize.Height );
}
finally {
busySizing = false;
}
}

Categories

Resources