I am currently implementing a tooltip which has at least two sentences worth inside of it, so I need to somehow create a large rectangle which would hold it.
My issue is the height of the rectangle.
Snip:
As you can see the green rectangle does not have the required size.
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Discounting.Module
{
public partial class Benefits : UserControl
{
public Benefits()
{
InitializeComponent();
}
private void ToolTip1_Draw(object sender, DrawToolTipEventArgs e)
{
var newEventArgs = new DrawToolTipEventArgs(
e.Graphics,
e.AssociatedWindow,
e.AssociatedControl,
e.Bounds, e.ToolTipText,
this.BackColor,
this.ForeColor,
Font);
DrawToolTip(e);
}
private void DrawToolTip(DrawToolTipEventArgs e)
{
using (var sf = new StringFormat())
{
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
using (var graphics = e.Graphics)
{
var linearGradientBrush = new LinearGradientBrush(new Rectangle(e.Bounds.X, e.Bounds.Y,
8000, 1000), Color.GreenYellow, Color.MintCream, 45f);
graphics.FillRectangle(linearGradientBrush, linearGradientBrush.Rectangle);
graphics.DrawString(e.ToolTipText, new Font("Aerial",12.0f, FontStyle.Bold), Brushes.Silver,
new PointF(linearGradientBrush.Rectangle.X + 6, linearGradientBrush.Rectangle.Y + 6)); // shadow layer
graphics.DrawString(e.ToolTipText, new Font("Aerial",12.0f, FontStyle.Bold), Brushes.Black,
new PointF(linearGradientBrush.Rectangle.X + 5, linearGradientBrush.Rectangle.Y + 5)); // top layer
linearGradientBrush.Dispose();
}
}
}
private void ToolTip2_Draw(object sender, DrawToolTipEventArgs e)
{
DrawToolTip(e);
}
private void ToolTip3_Draw(object sender, DrawToolTipEventArgs e)
{
DrawToolTip(e);
}
private void ToolTip4_Draw(object sender, DrawToolTipEventArgs e)
{
DrawToolTip(e);
}
}
}
If you require further details I would be happy to provide them.
Well, since there might be some quirks when mixing TextRenderer and the Graphics object, here's an example:
The ToolTip.PopUp event provides means to set the Size of the ToolTip rectangle. You just need to measure the Text and set its PopupEventArgs.ToolTipSize property to the measured Size.
This allows to use multi-line strings as well, using Environment.NewLine to separate the lines.
The PopupEventArgs object doesn't provide a Graphics object that can be use to measure the Text. We can use TextRenderer.MeasureText instead.
TextRenderer.MeasureText is very precise: it will give back the exact measure of the Text. Since you are using Graphics.DrawString to draw the Text, we better be generous and add some more space to the measured Width, to avoid text wrapping and also because the Text looks better if the container rectangle is not too tight.
In the Popup event, after measuring the Text, I'm adding 5 pixels to both the Width and Height (Size.Add([Measured Size], new Size(5, 5))). Modify as required
Note:
Here, the Font family and Size are hard-coded. Of course you may want to use a more dynamic Font object, possibly linked to a property of your UserControl. The Font can be changed at any time: the PopUp event will use it to measure the test bounds.
TextFormatFlags toolTipFlags = TextFormatFlags.VerticalCenter |
TextFormatFlags.LeftAndRightPadding | TextFormatFlags.HorizontalCenter | TextFormatFlags.NoClipping;
Font toolTipFont = new Font("Arial", 12.0f, FontStyle.Bold);
private void toolTip1_Popup(object sender, PopupEventArgs e)
{
string toolTipText = (sender as ToolTip).GetToolTip(e.AssociatedControl);
using (var g = e.AssociatedControl.CreateGraphics()) {
var textSize = Size.Add(TextRenderer.MeasureText(
g, toolTipText, toolTipFont, Size.Empty, flags), new Size(10, 5));
e.ToolTipSize = textSize;
}
}
private void toolTip1_Draw(object sender, DrawToolTipEventArgs e) => DrawToolTip(e);
private void DrawToolTip(DrawToolTipEventArgs e)
{
using (var linearGradientBrush = new LinearGradientBrush(e.Bounds, Color.GreenYellow, Color.MintCream, 45f)) {
e.Graphics.FillRectangle(linearGradientBrush, e.Bounds);
}
var shadowBounds = new Rectangle(new Point(e.Bounds.X + 1, e.Bounds.Y + 1), e.Bounds.Size);
TextRenderer.DrawText(e.Graphics, e.ToolTipText, toolTipFont, shadowBounds, Color.LightGray, toolTipFlags);
TextRenderer.DrawText(e.Graphics, e.ToolTipText, toolTipFont, e.Bounds, Color.Black, toolTipFlags);
}
Related
I changed in the properties OwnerDraw to true.
and added the Draw event.
private void toolTip1_Draw(object sender, DrawToolTipEventArgs e)
{
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
sf.FormatFlags = StringFormatFlags.NoWrap;
using (Font f = new Font("Tahoma", 12))
{
e.Graphics.DrawString(e.ToolTipText, f,
SystemBrushes.ActiveCaptionText, e.Bounds, sf);
}
}
}
First time i put the mouse over a control with a tooltip the text is bigger but then next on other controls the tooltip get black :
before using the Draw event it was working fine but i want to resize the text font size.
You need clear the graphics first.
e.Graphics.Clear(((Control)sender).BackColor);
Or just use the methods defined in DrawToolTipEventArgs
e.DrawBackground();
e.DrawBorder();
I've drawn on a Tool Tip control - The code is below.
private void toolTip1_Popup(object sender, PopupEventArgs e)
{
ToolTip tt = (sender as ToolTip);
string toolTipText = tt.GetToolTip(e.AssociatedControl);
e.ToolTipSize = TextRenderer.MeasureText(toolTipText, new Font("Arial", 16.0f));
}
private void toolTip1_Draw(object sender, DrawToolTipEventArgs e) => DrawToolTip(sender, e);
[System.Runtime.InteropServices.DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr h, int x, int y, int width, int height, bool redraw);
private void DrawToolTip(object sender, DrawToolTipEventArgs e)
{
ToolTip tt = (sender as ToolTip);
string toolTipText = tt.GetToolTip(e.AssociatedControl);
Font f = new Font("Arial", 16.0f);
e.DrawBackground();
e.DrawBorder();
toolTipText = e.ToolTipText;
e.Graphics.DrawString(e.ToolTipText, f, Brushes.Black, new PointF(2, 2));
}
And then to set the ToolTip text:
toolTip1.SetToolTip(btnLogin, "Some text.....");
Additionally, here is an image of what is happening.
It looks alright, but it has come to my attention that if the text is a certain length, the tooltip will go off-screen. Is there anyway to prevent that? I would rather not have to add Environment.NewLine(); or \n etc, since I would need to do that for MANY strings.
If I understand your question correctly, you are trying to combine the two solutions posted here and here to mainly resize the ToolTip window with the screen width, and move it to Point(2, 2), screen coordinates.
If that is what you need, you need to modify the source codes a bit to set the right e.ToolTipSize in the Popup event, and as the gentlemen commented above, draw the string in a rectangle, the e.Bounds property in the Draw event.
using System;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class Form1 : Form
{
TextFormatFlags flags = TextFormatFlags.VerticalCenter
| TextFormatFlags.Left
| TextFormatFlags.LeftAndRightPadding
| TextFormatFlags.NoClipping
| TextFormatFlags.WordBreak;
public Form1()
{
InitializeComponent();
}
private void toolTip1_Popup(object sender, PopupEventArgs e)
{
var tt = sender as ToolTip;
var toolTipText = tt.GetToolTip(e.AssociatedControl);
var screen = Screen.FromControl(e.AssociatedControl).WorkingArea;
using (var g = e.AssociatedControl.CreateGraphics())
using (var font = new Font("Arial", 16))
{
var sz = TextRenderer.MeasureText(
g, toolTipText, font, screen.Size, flags);
e.ToolTipSize = new Size(screen.Width - 2, sz.Height + 10);
}
}
private void toolTip1_Draw(object sender, DrawToolTipEventArgs e)
{
var t = sender as ToolTip;
var h = (IntPtr)t.GetType().GetProperty("Handle",
BindingFlags.NonPublic | BindingFlags.Instance).GetValue(t);
MoveWindow(h, 2, 2, e.Bounds.Width - 2, e.Bounds.Height, false);
e.DrawBackground();
e.DrawBorder();
using (var font = new Font("Arial", 16))
TextRenderer.DrawText(e.Graphics, e.ToolTipText, font,
e.Bounds, Color.Black, flags);
}
[DllImport("User32.dll")]
static extern bool MoveWindow(IntPtr h, int x, int y,
int width, int height, bool redraw);
}
I want to detect mouse click on my custom created region.
1) I ve tried this code with rectangle and it worked, but with string it doesnt
GraphicsPath gp = new GraphicsPath();
Region reg = new Region();
private void Form1_Load(object sender, EventArgs e)
{
gp.AddString("TEXT", new FontFamily("Arial"),0, 20.0f, new Point(300, 10), StringFormat.GenericDefault);
gp.Widen(Pens.AliceBlue);
reg = new Region(gp);
}
and here is the part2
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (reg.IsVisible(e.Location))
{
MessageBox.Show("aaaa");
}
}
It doesnt show the message box. :)
EDIT :here is my Paint event to see where my string is
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawString("TEXT", new Font("Arial", 20), Brushes.Yellow, 300,100 );
}
The most basic error is a typo: One time you draw at y = 10, the other time at y = 100.
But there is another issue which is not so obvious at all:
Add
e.Graphics.FillPath(Brushes.Firebrick, gp);
to the Paint event and you'll see it: The fonts have quite a different size.
That is because when adding text to a GraphicsPath it is using a different scale (called 'emSize') than Graphics.DrawString does, which uses 'Point'.
To adapt you can use this:
float fontsize = 20.0f;
using (Graphics g = panel1.CreateGraphics()) fontsize *= g.DpiY / 72f;
Now you can build the GraphicsPath, best with the correct coordinates..:
gp.AddString("TEXT", new FontFamily("Arial"), 0, fontsize,
new Point(300, 100), StringFormat.GenericDefault);
This is the class where I draw and color the items in a listBox. The function is ColorListBox. If I'm using font size 8 it looks ok but if I'm using font size 20 the items in the listBox overlap each other; no space between them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace GatherLinks
{
class ColorText
{
public static void Texts(RichTextBox box, string text, Color color)
{
box.SelectionStart = box.TextLength;
box.SelectionLength = 0;
box.SelectionColor = color;
box.AppendText(text);
box.SelectionColor = box.ForeColor;
}
public static void ColorListBox(List<string> data, DrawItemEventArgs e)
{
string strLeft = null;
string strMid = "---";
string strRight = null;
if (data[e.Index].Contains(strMid))
{
int index = data[e.Index].IndexOf(strMid);
strLeft = data[e.Index].Substring(0, index);
strRight = data[e.Index].Substring(index + strMid.Length);
}
using (Font f = new Font(FontFamily.GenericSansSerif, 20, FontStyle.Regular))
{
float startPos;
e.Graphics.DrawString(strLeft, f, Brushes.Red, e.Bounds.X, e.Bounds.Y);
startPos = e.Graphics.MeasureString(strLeft, f).Width;
e.Graphics.DrawString(strMid, f, Brushes.Black, e.Bounds.X + startPos, e.Bounds.Y);
startPos = e.Graphics.MeasureString(strLeft + strMid, f).Width;
e.Graphics.DrawString(strRight, f, Brushes.Green, e.Bounds.X + startPos, e.Bounds.Y);
}
}
}
}
This is an image of how it looks when it's size 20:
Try drawing the items in the ListBox yourself.
Set the DrawMode property of the ListBox to OwnerDrawVariable. Do this via Designer or via code:
myListBox.DrawMode = DrawMode.OwnerDrawVariable;
Set up the ListBox events for DrawItem and MeasureItem. Do this via Designer or via code:
myListBox.DrawItem += new DrawItemEventHandler(DrawItem);
myListBox.MeasureItem += new MeasureItemEventHandler(MeasureItem);
This will allow you to be notified whenever the DrawItem and MeasureItem event is fired for each item in the ListBox.
Add event handlers for the events you are listening to. These will be populated automatically if you added them through the designer.
private void DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
// You'll change the font size here. Notice the 20
e.Graphics.DrawString(data[e.Index],new Font(FontFamily.GenericSansSerif, 20, FontStyle.Bold), new SolidBrush(color[e.Index]),e.Bounds);
}
private void MeasureItem(object sender, MeasureItemEventArgs e)
{
// You may need to experiment with the ItemHeight here..
e.ItemHeight = 25;
}
Try,
listbox1.IntegralHeight=false; // where listbox1 is your listbox's ID
listbox1.Height=some_int_number;
I ran into the same issue.
What helped me is increasing ListBox.ItemHeight property after increasing the font size.
I want it to move when the mouse moves, and disappear when the pointer isn't over the label.
This doesn't work:
private void lblRevisionQuestion_MouseMove(object sender, MouseEventArgs e)
{
toolTip1.Show("test", this, PointToClient(MousePosition), Int32.MaxValue);
}
private void lblRevisionQuestion_MouseLeave(object sender, EventArgs e)
{
toolTip1.Hide(this);
}
As soon as the tooltip appears, it steals focus away from the form, evoking MouseLeave. Then the tooltip hides, and the pointer is once again over the label, invoking MouseMove. This results in a choppy, flashing tooltip.
Is there any way to do this?
toolTip1.Show(_toolTipText, this, new Point(lblRevisionQuestion.Left + e.X + 1, lblRevisionQuestion.Top + e.Y + 1), int.MaxValue);
Oddly enough, when I tried displaying it to some arbitrary coordinates eariler, it had the same problem as above. I don't know why this works and that didn't.
Since your are working with a list view, I would like to bring to your notice that the listview items have some tooltip specific properties like ToolTipText. This will make it easier to display the data when you hover over a item as shown below
toolTip1.ToolTipTitle = string.Format("Item: {0}",e.Item.Text);
toolTip1.Show(e.Item.ToolTipText,listView1);
toolTip1.ShowAlways = true;
This is how I did:
MyToolTip.cs :
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public class MyToolTip : ToolTip
{
public MyToolTip()
{
OwnerDraw = true;
Draw += MyToolTip_Draw;
}
private void MyToolTip_Draw(object sender, DrawToolTipEventArgs e)
{
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
sf.FormatFlags = StringFormatFlags.NoWrap;
using (Font f = new Font("Arial", 7.5F))
{
SizeF s = new SizeF();
s = e.Graphics.MeasureString(e.ToolTipText, f);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(225, 225, 245)), e.Bounds);
e.DrawBorder();
e.Graphics.DrawString(e.ToolTipText, f, SystemBrushes.ActiveCaptionText, e.Bounds, sf);
}
}
}
}
Using it somewhere in a class:
private MyToolTip ttp;
private int LastX;
private int LastY;
public string Caption { get; set; }
private void MyObjectWhichNeedsMovingToolTip_MouseLeave(object sender, EventArgs e)
{
ttp.Hide(this);
}
private void MyObjectWhichNeedsMovingToolTip_MouseMove(object sender, MouseEventArgs e)
{
// This is for stop flickering tooltip
if (e.X != this.lastX || e.Y != this.lastY)
{
// depending on parent of the object you must add or substract Left and Top information in next line
ttp.Show(Caption, this, new Point(MyObjectWhichNeedsMovingToolTip.Left + e.X + 10, MyObjectWhichNeedsMovingToolTip.Top + e.Y + 20), int.MaxValue);
this.lastX = e.X;
this.lastY = e.Y;
}
}
And the result is: