Is it possible to change ToolStripMenuItem tooltip font? - c#

I have a dynamically filled ContextMenuStrip where each ToolStripMenuItem has a formatted text for the tooltip. And, in order for this text to make sense to the user, I must use a monospaced font, such as "Courier New". The default font is a regular, non Monospaced font.
I couldn't find any getter for the ToolTip object nor a way to override its Draw event nor a way to set its style.
So, is it even possible to change ToolStripMenuItem's tooltip font?
Implementing CustomToolTip that inherits from ToolTip doesn't solve the issue, which is passing the new tooltip to ToolStripMenuItem.

OK, thanks to Tony Abrams and William Andrus, the solution is as follows:
A static instance of ToolTip which initialized.
toolTip = new ToolTip();
toolTip.OwnerDraw = true;
toolTip.Draw += new DrawToolTipEventHandler(tooltip_Draw);
toolTip.Popup += new PopupEventHandler(tooltip_Popup);
toolTip.UseAnimation = true;
toolTip.AutoPopDelay = 500;
toolTip.AutomaticDelay = 500;
ToolTip's Popup event to set its size.
void tooltip_Popup(object sender, PopupEventArgs e)
{
e.ToolTipSize = TextRenderer.MeasureText(toolTipText, new Font("Courier New", 10.0f, FontStyle.Bold));
e.ToolTipSize = new Size(e.ToolTipSize.Width + TOOLTIP_XOFFSET, e.ToolTipSize.Height + TOOLTIP_YOFFSET);
}
ToolTip's Draw event for actual drawing.
void tooltip_Draw(object sender, DrawToolTipEventArgs e)
{
Rectangle bounds = e.Bounds;
bounds.Offset(TOOLTIP_XOFFSET, TOOLTIP_YOFFSET);
DrawToolTipEventArgs newArgs = new DrawToolTipEventArgs(e.Graphics, e.AssociatedWindow, e.AssociatedControl, bounds, e.ToolTipText, toolTip.BackColor, toolTip.ForeColor, new Font("Courier New", 10.0f, FontStyle.Bold));
newArgs.DrawBackground();
newArgs.DrawBorder();
newArgs.DrawText(TextFormatFlags.TextBoxControl);
}
ToolStripMenuItem's MouseEnter event to show the tooltip.
System.Windows.Forms.ToolStripMenuItem item = (sender as System.Windows.Forms.ToolStripMenuItem);
toolTip.SetToolTip(item.Owner, "ToolTipText");

You could create a custom ToolTip class (CustomToolTip) that inherits from ToolTip. Then you would have to handle the OnDraw event. Inside that event you can change the font.
Look here for an example (there is a vb and c# example).
EDIT
You would have to handle the rendering of the custom tooltip on your own (IE: OnMouseOver, OnMouseLeave events of the toolstripmenuitem). You might be able to create a customtoolstripmenuitem that uses a custom tooltip, but I'm not sure that toolstripmenuitem exposes a tooltip propety/object.

I know I'm a little late to the party on this one but you can use reflection to set the instance of ToolTip that is used for rendering the tooltips. After doing that you can just use the Draw method as you normally would.
public void SetToolTipInstance(ToolStrip ts, ToolTip tt)
{
Type type = ts.GetType.BaseType;
int propToolTip = Convert.ToInt32(type.GetField("PropToolTip", BindingFlags.NonPublic | BindingFlags.Static).GetValue(ts));
dynamic ps = type.BaseType.GetProperty("Properties", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(ts);
ps.GetType.GetMethod("SetObject", BindingFlags.Instance | BindingFlags.Public).Invoke(ps, {propToolTip,tt});
}

Related

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;
}

How to position a borderless form under buttons

I have created 4 buttons dynamically and placed them horizontally using c# win forms.Now i want show a custom tooltip(actually its a borderless form) under each of the 4 buttons on mouse hover event.But how do i position my tooltip form under the buttons??
I have tried the code below but it does not work the desired way.
tooltip.Location = new System.Drawing.Point(b.Left, b.Top);
Where 'tooltip' is tooltip form object & 'b' is the dynamic button.Please advise with some code snippet.
private void B_MouseHover(object sender, EventArgs e)
{
var b = sender as Button;
//MessageBox.Show(Cursor.Position.ToString());
if(b!= null)
{
if (tooltip == null)
{
tooltip = new frmSecQStatToolTipDlg();
}
tooltip.Location = new System.Drawing.Point(b.Left, b.Bottom);
tooltip.data(b.Tag.ToString());
tooltip.Show();
}
}
The way you named it is a bit misleading. As I understand, what you call a tooltip is just a Form. You need to consider 2 things
(1) Form.StartPosition must be set to FormStartPosition.Manual
(2) Form.Location must be in screen coordinates. Note that the Button.Location you are trying to use is in button's parent client coordinates. Control.PointToScreen has to be used for conversion.
In your case, it should be something like this
tooltip.StartPosition = FormStartPosition.Manual;
var topLeft = b.PointToScreen(new Point(0, 0));
tooltip.Location = new Point(topLeft.X, topLeft.Y + b.Height);
When you show the tooltip you can control its location, check show method overloads: https://msdn.microsoft.com/en-us/library/system.windows.forms.tooltip.show.aspx

C# Resize textbox to fit content

I'm writing a program where the user should be able to write text in a TextBox. I'd like the TextBox to resize itself, so it fits to the content.
I've tried the following:
private void textBoxTitle_TextChanged(object sender, TextChangedEventArgs e)
{
System.Drawing.Font myFont = new System.Drawing.Font("Verdana", 8);
System.Drawing.SizeF mySize = e.Graphics.MeasureString("This is a test", myFont);
this.textBoxTitle.Width = (int)Math.Round(mySize.Width, 0);
}
I get an error saying that Graphics doesn't work for TextChangedEventArgs. Is there another way I can resize the TextBox?
You should try a code something like below. It has worked for me well.
private void textBox1_TextChanged(object sender, EventArgs e)
{
Size size = TextRenderer.MeasureText(textBox1.Text, textBox1.Font);
textBox1.Width = size.Width;
textBox1.Height = size.Height;
}
For more information refer to TextRenderer.MeasureText()
I am adding this answer as I do not see the fixed width aspect of a textbox being discussed in any of the other. If you have a fixed width for your textbox, and you want to adjust only its height you can do something like the following:
Something like this gives the height of the text as how it is drawn in the multiline wordwrapped textbox itself:
SizeF MessageSize = MyTextBoxControl.CreateGraphics()
.MeasureString(MyTextBoxControl.Text,
MyTextBoxControl.Font,
MyTextBoxControl.Width,
new StringFormat(0));
I am not sure what StringFormat should be but the values StringFormatFlags do not seem to apply to a default TextBox make up.
Now with MessageSize.Height you know the height of the text in the textbox.
I had the same problem and I solved it in a simpler way.
I used the AutoSize property of a Label control.. I added an invisible label to my form, set its AutoSize property True. When the I need to change the size of my TextBox I use this code:
MyLabel.Text = MyTextBox.Text;
MyTextBox.Size = MyLabel.Size;
I set the Maximum and Minimum Size of the label for better results.
Have Fun
Your binding to the wrong event, and you cannot use the graphics object in the TextChangedEventArgs object.
Try using the TextChanged event. The following snippet is working:
public Form1()
{
InitializeComponent();
this.textBox1.TextChanged += new EventHandler(textBox1_TextChanged);
}
void textBox1_TextChanged(object sender, EventArgs e)
{
System.Drawing.SizeF mySize = new System.Drawing.SizeF();
// Use the textbox font
System.Drawing.Font myFont = textBox1.Font;
using (Graphics g = this.CreateGraphics())
{
// Get the size given the string and the font
mySize = g.MeasureString(textBox1.Text, myFont);
}
// Resize the textbox
this.textBox1.Width = (int)Math.Round(mySize.Width, 0);
}
}
first, create method to Make the TextBox fit its contents.
private void AutoSizeTextBox(TextBox txt)
{
const int x_margin = 0;
const int y_margin = 2;
Size size = TextRenderer.MeasureText(txt.Text, txt.Font);
txt.ClientSize =
new Size(size.Width + x_margin, size.Height + y_margin);
}
then with the TextChanged event handler calls AutoSizeTextBox() function to make the TextBox fit its text when the text changes.
private void txtContents_TextChanged(object sender, EventArgs e)
{
AutoSizeTextBox(sender as TextBox);
}
That’s all, for more info:
resize-a-textbox-to-fit-its-text
You will need to use the CreateGraphics() method of the form to create the Graphics instance to measure the string on.
The TextChangedEventArgs class does not have a Graphics property, that is a property of the PaintEventArgs class passed in to the Paint event handler
Try this:
using System.Drawing;
...
private void textBoxTitle_TextChanged(object sender, TextChangedEventArgs e)
{
// Determine the correct size for the text box based on its text length
// get the current text box safely
TextBox tb = sender as TextBox;
if (tb == null) return;
SizeF stringSize;
// create a graphics object for this form
using(Graphics gfx = this.CreateGraphics())
{
// Get the size given the string and the font
stringSize = gfx.MeasureString(tb.Text, tb.Font);
}
// Resize the textbox
tb.Width = (int)Math.Round(stringSize.Width, 0);
}
Essentially you create your own Graphics object for the form, then measure it based on the text and font of the TextBox. The using will properly dispose the Graphics object - your previous code would have leaked horribly!
Whatever the aim is.
If the size of the textbox should be dynamically set up based on the string, which should be the text inside this box, there is no nice option.
Reasons : MeasureString uses usual string formatters as delimiters for its own width and height.
Means, carriage return and line feed are parsed, too. Resulting in a sizeF.Width and sizeF.Height.
Depending on the string( and its font and number of lines ) these both variables can carry values, which are sometimes useless to be used as width/height values of a textbox ( because they can be bigger than the parentform's values and this would resize the textbox to a size, with left and bottom borders beyond those of the parent form).
Some solutions are still available, depending on the aim, one would like to achieve.
One idea would be :
Create a textbox in designer, size = 100 X 100. enable word-wrapping.
In the OnTextChanged event handler of the textbox, we just resize the textbox's width to a value, defined by ourself (e.g. parentform.Width or another hard value ).
This would cause the word wrap to recalculate the string in the textbox and this would rearrange all the characters inside the textbox, because word wrap is enabled.
The height of the textbox could can be set hard to parentform.Height, for example.
BUT,
better : set the height dynamically,based on the Y value of the ReturnValue (Point) of the method texbox.GetPositionFromCharIndex(textbox.TextLength -1 ).
Then, with Math.Min() determine, which is smaller ( either parentform.Height or Point.Y ) , and reset the textbox size to new Size(previousDeterminedWidth, nowDeterminedHeight).
Please keep in mind ( if scrollbars are enabled ) to add about 17 pixs to Your width calculation.
Best regards
Did you try to set yourTextBox.AutoSize = true;?
This property may be hidden in the GUI designer, but you can set it in the form constructor right after InitializeComponent(); call.
Graphics.Measure string you can do o PaintEventArgs, not on TextChangedEventArgs
What I think you want is this
System.Drawing.Font myFont = new System.Drawing.Font("Verdana", 8);
Graphics graphics = this.CreateGraphics();
SizeF textSize = graphics.MeasureString("This is a test", myFont);
The problem is that you just cannot create a Graphics object by simply allocating it since it has no public constructor, so you should better go and use TextRenderer.MeasureText, as done in http://msdn.microsoft.com/en-us/library/y4xdbe66.aspx
TextRenderer is less accurate because it uses GDI and Graphics uses GDI+, so maybe you should leave a little margin on the value you get from the Width property.
Hope this helps

tab control, vertically aligned tabs with vertically aligned text

I want to use a tab control and have the tabs displayed on the left, as opposed to at the top. I have set the alignment to the left and the tabs are displayed there. However, how do I get the text to be displayed on the tab, vertically? I have looked at the msdn and it gives an example of a left aligned tab control but the tab label is still displayed horisontally!
The other thing, does anybody know how to use the tab control with left aligned tabs with the default layout so that it looks better?
Please no third party apps unless they are free, and yes I have looked at code project already.
Thanks, R.
It is an age-old bug in the visual styles renderer for the native Windows tab control. It only supports tabs at the top, the Microsoft programmer that worked on it was run over by a bus before she could finish the job, I guess.
The only thing you can do about it is selectively turn off visual styles for the control. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing the original.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class FixedTabControl : TabControl {
[DllImportAttribute("uxtheme.dll")]
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);
protected override void OnHandleCreated(EventArgs e) {
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}
}
If you create your own DrawItem event, you can manually write the tab headers. You could use this process:
1) Set the following properties of the TabControl:
Property | Value
----------|----------------
Alignment | Right (or left, depending on what you want)
SizeMode | Fixed
DrawMode | OwnerDrawFixed
2) Set the ItemSize.Width property to 25 and the ItemSize.Height property to 100. Adjust these values as you want, but remember that basically, the width is the height and vice versa.
3) Add an event handler for the DrawItem event and add the following code:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _TextBrush;
// Get the item from the collection.
TabPage _TabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _TabBounds = tabControl1.GetTabRect(e.Index);
if(e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_TextBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.Gray, e.Bounds);
}
else
{
_TextBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font. Because we CAN.
Font _TabFont = new Font("Arial", 10, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _StringFlags = new StringFormat();
_StringFlags.Alignment = StringAlignment.Center;
_StringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_TabPage.Text, _TabFont, _TextBrush,
_TabBounds, new StringFormat(_StringFlags));
}
4) Profit!
(original source: http://en.csharp-online.net/TabControl)

Temperature TextBox In C#

I need some code to convert standard C# TextBox to temperature TextBox which means adding "°C" to end of the text in the textbox with another color than the default color.
To get the degree symbol you can use character code 176 e.g.
Char degree = (Char)176
You can then append this to your textbox content or I would just add a label to the right of the textbox with the degree symbol if you want to control the forecolor easily.
TextBox is a plain text editor. To get different colours you would have to muck around with a rich text box. Why not put the "°C" in a label positioned to the right of the text box? That would also make your parsing and rendering code much easier.
You could probably create your own control which inherits from TextBox and then override Text property to automaticaly add °C though other color inside the same TextBox could be problem.
Why you want to have °C in TextBox ?
Can't it just be label right after TextBox ?
You can set static text and color to what you want.
The other solutions proposed here are probably sufficient for your application; however, if you had the need to implement this with re-usability in mind, here is a custom control solution which you may extend to better suit your application:
public class TemperatureTextBox : ContainerControl
{
private const int BORDER_SIZE = 1;
// Exposes text property of text box,
// expose other text box properties as needed:
public override string Text
{
get { return textBox.Text; }
set { textBox.Text = value; }
}
private TextBox textBox = new TextBox()
{
Text = string.Empty,
BorderStyle = BorderStyle.None,
Dock = DockStyle.Fill
};
private Label label = new Label()
{
Text = "°C",
TextAlign = ContentAlignment.MiddleCenter,
Size = new Size()
{
Width = 32
},
BackColor = SystemColors.Window,
Dock = DockStyle.Right
};
public TemperatureTextBox()
{
this.BackColor = SystemColors.Window;
this.Padding = new Padding(BORDER_SIZE);
this.Controls.Add(label);
this.Controls.Add(textBox);
this.PerformLayout();
}
// Constrain control size to textbox height plus top and bottom border:
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Height = (textBox.Height + (BORDER_SIZE * 2));
}
// Render a border around the control:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawRectangle(
SystemPens.ControlDarkDark,
new Rectangle()
{
Width = (this.Width - BORDER_SIZE),
Height = (this.Height - BORDER_SIZE)
});
}
}
Simply create a new class and drop this code in and rebuild you solution. It will create a new TemperatureTextBox control in the toolbox which can be dropped onto a new form and visually designed.
This example exposes the Text property of the underlying text box by overriding the custom control's text property. You may want to expose other properties, and events depending on what your application needs to accomplish.

Categories

Resources