Changing a ToolTip's cursor - c#

How can I set the default cursor shown when hovering over a ToolTip? I've already created a custom ToolTip class to adjust the color/font, so if necessary I can make changes there.
The ToolTip is shown from a panel in a windows form. The panel's cursor property is set to Cursors.Hand and I would like the ToolTip to match. I've tried changing the form-level cursor in the panel's MouseEnter event, but it's only semi-functional. It quickly alternates between Cursors.Default and Cursors.Hand when I move the cursor around over the ToolTip (as if the tip is forcing the default cursor).
Any help would be greatly appreciated.
On iconPanel's MouseEnter:
Cursor = Cursors.Hand;
if(!showingTip) {
showingTip = true;
changeIconTip.Show("Choose image...", iconPanel, 2, 2, 4000);
}
On iconPanel's MouseLeave:
Rectangle iconPanelArea = new Rectangle(iconPanel.PointToScreen(new Point(0, 0)), iconPanel.Size);
Point c = Cursor.Position;
if(!iconPanelArea.Contains(c)) {
showingTip = false;
changeIconTip.Hide(iconPanel);
Cursor = Cursors.Default;
}
Note: On MouseLeave when the cursor hovers over the ToolTip, technically it 'leaves' the iconPanel (even though it's still inside of the panel's bounds). The Contains check only sets the cursor back to the default if it visually leaves the panel.

I'm not able to reproduce the cursor alternating. On Windows 8.1, the cursor stays the hand when the mouse is over the tooltip. Try this code:
public class Form3 : Form {
Panel iconPanel = new Panel() { BackColor = Color.RosyBrown, Size = new Size(200, 200) };
ToolTip changeIconTip = new ToolTip();
bool showingTip = false;
public Form3() {
Controls.Add(iconPanel);
iconPanel.MouseEnter += iconPanel_MouseEnter;
iconPanel.MouseLeave += iconPanel_MouseLeave;
}
void iconPanel_MouseLeave(object sender, EventArgs e) {
Rectangle iconPanelArea = new Rectangle(iconPanel.PointToScreen(new Point(0, 0)), iconPanel.Size);
Point c = Cursor.Position;
if (!iconPanelArea.Contains(c)) {
showingTip = false;
changeIconTip.Hide(iconPanel);
Cursor = Cursors.Default;
}
}
void iconPanel_MouseEnter(object sender, EventArgs e) {
Cursor = Cursors.Hand;
if (!showingTip) {
showingTip = true;
changeIconTip.Show("Choose image...", iconPanel, 2, 2, 4000);
}
}
}

Related

How to remove the black border from the disabled button?

I created a changing_button with a background image. The FlatAppearance.BorderSize property of this button is zero, so normally it displays without a border. But if I make changing_button disabled, it will have a black border:
How can I remove this border?
I guess that the border appears because changing_button is in focus then I change its Enable property. For that reason, I tried to remove focus from the button and set changing_button.TabStop = false, but it didn't help.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace winforms_test_1
{
public partial class Form1 : Form
{
Button changing_button;
private readonly Image enable_img = Image.FromFile("D://images//enable_img.png");
private readonly Image disable_img = Image.FromFile("D://images//disable_img.png");
public Form1()
{
InitializeComponent();
TableLayoutPanel main_panel = new TableLayoutPanel
{
BackColor = Color.White,
Dock = DockStyle.Fill
};
CreateButton();
Controls.Add(changing_button);
}
private void CreateButton()
{
changing_button = new Button
{
BackgroundImage = enable_img,
BackgroundImageLayout = ImageLayout.Center,
TabIndex = 1,
TabStop = false,
FlatStyle = FlatStyle.Flat,
Margin = new Padding(10, 10, 0, 0),
Location = new Point(40, 40),
};
changing_button.FlatAppearance.BorderSize = 0;
changing_button.Size = new Size(80, 50);
changing_button.Click += new System.EventHandler(this.Button_Click);
}
void Button_Click(object sender, EventArgs e)
{
changing_button.BackgroundImage = disable_img;
changing_button.Enabled = false;
changing_button.TabStop = false;
}
}
}
enable_img.png:
disable_img.png:
To workaround this, I set the border size to 1.
Then set the border color to be the same color of BackColor. Just change on the click event to match the current state.

Programmatically made button cannot change hover color c# winforms

I cannot find a way to change the hover color when delopying it programmatically in c# winforms.
I hope someone can help me!
Code:
Button btn = new Button
{
Name = "btn1",
Width = 250,
Height = 250,
Location = new Point(0, 15),
BackColor = Color.Transparent,
FlatStyle = FlatStyle.Flat,
BackgroundImage = img,
BackgroundImageLayout = ImageLayout.Stretch,
};
You can specify the hover color outside of the initialization block:
// We create button
Button btn = new Button
{
...
}
// And then specify hovering behaviour
// Blue while hovering
btn.FlatAppearance.MouseOverBackColor = Color.Blue;
// Red when pressing (uncomment if you want)
// btn.FlatAppearance.MouseDownBackColor = Color.Red;
use MouseEnter and MouseLeave for change background color in button
Button btn = new Button
{
Name = "btn1",
Width = 250,
Height = 250,
Location = new Point(0, 15),
BackColor = Color.Transparent,
FlatStyle = FlatStyle.Flat,
BackgroundImage = img,
BackgroundImageLayout = ImageLayout.Stretch,
};
btn.MouseEnter += OnMouseEnter;
btn.MouseLeave += OnMouseLeave;
private void OnMouseEnter(object sender, EventArgs e)
{
button1.BackColor = Color.Red;
}
private void OnMouseLeave(object sender, EventArgs e)
{
button1.BackColor = Color.Transparent;
}

Select / deselect, change color of multiple panels created dynamically

I use a list of objects as an input for my application and the number of objects in the list changes. For each object in the list I dynamically create a Panel and add them to the controls of other panel
private void addPanel(string name, int positionFromLeft, Panel mainPanel)
{
Panel panel = new System.Windows.Forms.Panel();
panel.Name = name;
panel.Location = new System.Drawing.Point(50 + positionFromLeft, 160);
panel.BackColor = System.Drawing.Color.SteelBlue;
panel.Size = new System.Drawing.Size(120, 40);
panel.Click += new EventHandler(this.pClick);
mainPanel.Controls.Add(panel);
}
To each panel I add a click event handler which changes the color of the panel:
private void pClick(object sender, EventArgs e)
{
Panel panel= (sender as Panel);
panel.BackColor = Color.Green;
}
How can I change a color to a different one (red etc.) of each panel when it's clicked second time? And change it back (to green etc.) when clicked again. Basically, with every click to change color of a panel from green to red and vice versa. It has to work with every panel, so that I can change color of, for example, 10 panels to green and 10 panels to red, and vice versa during the run time.
If I got it right, you want to toggle the clicked panel.
private void pClick(object sender, EventArgs e)
{
Panel panel = (sender as Panel);
if (panel.BackColor == Color.Green) {
panel.BackColor = Color.Red;
} else if (panel.BackColor == Color.Red) {
panel.BackColor = Color.Green;
}
}

Flickering Tab Control with MouseMove Determining What To Draw

I have been researching this all day, (Go ahead and laugh lol) and I don't see any solutions to the age old Forms problem of flickering controls. My control is a TabControl and I am using DrawMode OwnerDrawFixed. I am hooking the following events. In short I am creating a TabControl with closable "X" buttons that are 12x12 png resources. The close buttons are all gray but if I mouse over one it should use a different image (a red X).
MouseDown: Loops all TabPages and checks if I have clicked on a rectangle where I am drawing my close button image.
MouseLeave: I need to Invalidate when I leave the TabControl to ensure everything is drawn correctly
MouseMove: Loops all TabPages and checks if I have moused over a rectangle where I am drawing my close button image. If I am mousing over then I save the tab page index so my paint can change the image used for the close button.
DrawItem: Here I simply draw the image
Things I have tested but no luck...
Making my own TabControl class which inherits TabControl and in the constructor I SetStyles for OptimizedDoubleBuffering To true (I set the other suggested flags to true)
I tried overriding CreateParams so I could or this value... createParams.ExStyle |= 0x00000020; (I have no idea what this does but read a user suggested to do this.
Setting the form DoubleBuffered (does nothing)
Anyways, I can't think what to do and I have read about this for awhile.
Here is my code for all events. I just want to have close buttons on my tabs that get highlighted when I mouse over them. Thanks.
private int mousedOver = -1;//indicates which close button is moused over
private void tabControl_DrawItem(object sender, DrawItemEventArgs e)
{
e.Graphics.DrawImage(e.Index == mousedOver ? Resources.redX : Resources.grayX, e.Bounds.Right - 15, e.Bounds.Top + 4);
}
private void tabControl_MouseDown(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc.TabCount == 1) return;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
TabPage tp = tc.TabPages[i];
tc.TabPages.Remove(tp);
tp.Dispose();
break;
}
}
}
private void tabControl_MouseMove(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
mousedOver = i;
tc.Invalidate();
return;
}
}
mousedOver = -1;
tc.Invalidate();
}
private void tabControl_MouseLeave(object sender, EventArgs e)
{
TabControl tc = sender as TabControl;
mousedOver = -1;
tc.Invalidate();
}
It does look like you are invalidating too often. Try filtering it so that you only invalidate it when the control needs to be re-painted:
private void tabControl_MouseMove(object sender, MouseEventArgs e) {
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++) {
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location)) {
if (mousedOver != i) {
mousedOver = i;
tc.Invalidate(r);
}
} else if (mousedOver == i) {
int oldMouse = mousedOver;
mousedOver = -1;
tc.Invalidate(tc.GetTabRect(oldMouse));
}
}
}
I would keep the CreateParams override, but as a native windows control, you can probably never totally eliminate some flicker.
You could also try setting the DoubleBuffered property of the control, by doing
Control.DoubleBuffered = true;
I know that this works with DataGridViews, ListViews, Forms and Panels.
Documentation can be found on MSDN.

AutoScroll mode doesn't hide scrollbar properly

I have one Panel and when I click on add Button I add one Control under other added controls. When I click on another Button I remove Control which was added as last.
This works fine. On that panel I have AutoScroll setting set to True and when I add more controls it properly appears and I can use it. When I remove some controls Panel properly hides ScrollBar ONLY if the "animation" on that ScrollBar doesn't run at that time.
If no animation is running on that ScrollBar it disapears properly - doesn't matter if you have mouse over it or not.
If you have mouse over the ScrollBar and quickly move over the remove Button and click before ScrollBars animation is finished the Control is removed, but the inactive ScrollBar is still there. In Buttons click handler I tried to call Invalidate, Update and Refresh methods over the Panel but nothing works.
I tested this only on Windows 7.
If you don't know what I mean please try to look at this short video (20s without sound): http://youtu.be/-0EfRXrGbuc
You forgot to post mcve. So here is one (add panel and two buttons):
private void button1_Click(object sender, EventArgs e)
{
panel1.Controls.Add(new Button() { Top = panel1.Controls.Count * 30 });
}
private void button2_Click(object sender, EventArgs e)
{
if (panel1.Controls.Count > 0)
panel1.Controls.RemoveAt(panel1.Controls.Count - 1);
panel1.Refresh();
}
I am able to reproduce the problem
it's winforms, baby (c).
Possible workaround is to call Refresh() by using e.g. Timer or some of mouse events (it will not prevent issue, but use will easily fix it by e.g. moving mouse inside panel1) or you can postpone the possibility of deleting buttons itself for a short time after panel1.MouseLeave. All this kind of workarounds.
I hoped that there is some better way, but now I don't see any, so based on answer from Sinatr I decided to use Timer and cobined it with checking pixel Color to determine if the ScrollBar is still visible.
private Timer _timer = new Timer {Interval = 500};
public Form1()
{
InitializeComponent();
_timer.Tick += TimerOnTick;
}
private void button2_Click(object sender, EventArgs e)
{
if (panel1.Controls.Count > 0)
{
var wasVisible = panel1.VerticalScroll.Visible;
panel1.Controls.RemoveAt(panel1.Controls.Count - 1);
buttons.RemoveAt(buttons.Count - 1);
if (wasVisible != panel1.VerticalScroll.Visible)
{
_timer.Start();
}
}
}
private bool IsBackgroundColor()
{
var point = panel1.Location;
point.Offset(panel1.Width - 9, panel1.Height - 11);
point = PointToScreen(point);
Image imgScreen = new Bitmap(1, 1);
using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb))
using (Graphics g = Graphics.FromImage(bmp))
using (Graphics gr = Graphics.FromImage(imgScreen))
{
g.CopyFromScreen(point, new Point(0, 0), new Size(1, 1));
gr.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
gr.DrawImage(bmp, new Rectangle(0, 0, 1, 1));
var color = bmp.GetPixel(0, 0);
return color.R == panel1.BackColor.R && color.G == panel1.BackColor.G && color.B == panel1.BackColor.B;
}
}
private void TimerOnTick(object sender, EventArgs eventArgs)
{
if (!IsBackgroundColor() && !panel1.VerticalScroll.Visible)
{
panel1.Refresh();
}
else
{
_timer.Stop();
}
}
I was not able to use Panel.DrawToBitmap because it doesn't draw ScrollBars. I also start the Timer only when the ScrollBar was visible and now it shouldn't be.
It is important to mention that the pixel Color checking is possible only if you know the Color which should be there if the ScrollBar is hidden. It is not necessary have to be Panel.BackColor.

Categories