How to make a checkbox button flash? - c#

I have a checkbox shown as button. I want to make it flash when it is checked. From what Ive found, i think the simplest way is to use a timer to rotate the background color of the button.
Where I am stuck is finding the back color of the checked button. Can someone tell me what the back color is changed to by default (via designer) when the button is checked? Without that I cannot get the timer to begin the oscillation.
What I have is a Mute Button. When the mute is active i want the button to flash until it is pressed again to turn the mute off.
In case I'm wrong and the back color actually does not change, what changes about the button to make it appear pressed?
code:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
instructorTimer.Enabled = true;
}
private void instructorTimer_Tick(object sender, EventArgs e)
{
// interval is 2000
if (checkBox1.BackColor == System.Drawing.SystemColors.Control)
checkBox1.BackColor = System.Drawing.SystemColors.ControlDark;
else
checkBox1.BackColor = System.Drawing.SystemColors.Control;
}

Maybe SystemColors.Control is what you are looking for.
Make sure you have the tick event hooked up. It looks suspect:
private void Form1_Load(object sender, EventArgs e) {
timer1.Tick += instructorTimer_Tick;
}
I would also change the color immediately, for instant feedback:
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox1.BackColor = SystemColors.ControlDark;
timer1.Enabled = true;
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox1.BackColor = Color.Green;
Application.DoEvents();
TimeSpan ts = new TimeSpan();
do
{
}
while (ts.Milliseconds == 2000);
checkBox1.BackColor = SystemColors.Control;
}

If you're willing to use a UserControl instead of trying to repurpose Button - the following should work great and you can extend it if something doesn't work like you like:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace FlashyButton
{
public partial class FlashyButton : UserControl
{
private CheckState _Checked = CheckState.Unchecked;
[Browsable(true)]
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
lblText.Text = value;
Invalidate();
}
}
public FlashyButton()
{
this.CausesValidation = true;
InitializeComponent();
lblText.MouseClick += (sender, e) => { OnMouseClick(null); };
}
public void SetFont(Font WhichFont)
{
this.Font = WhichFont;
}
public CheckState GetCheckedState()
{
return this._Checked;
}
public void SetCheckedState(CheckState NewCheckState)
{
this._Checked = NewCheckState;
}
protected override void OnMouseClick(MouseEventArgs e)
{
this._Checked = (this._Checked == CheckState.Checked) ? CheckState.Unchecked : CheckState.Checked;
this.BorderStyle = (this._Checked == CheckState.Checked) ? System.Windows.Forms.BorderStyle.Fixed3D : System.Windows.Forms.BorderStyle.FixedSingle;
tmrRedraw.Enabled = (this._Checked == CheckState.Checked);
if (this._Checked == CheckState.Unchecked)
{
this.BackColor = SystemColors.Control;
}
this.Invalidate(); //Force redraw
base.OnMouseClick(e);
}
private float Percent = 100;
private void tmrRedraw_Tick(object sender, EventArgs e)
{
Percent -= 2;
if (Percent < -100) Percent = 100;
this.BackColor = Color.FromArgb(
255,
Lerp(255, SystemColors.Control.R, (int)Math.Abs(Percent)),
Lerp(0, SystemColors.Control.G, (int)Math.Abs(Percent)),
Lerp(0, SystemColors.Control.B, (int)Math.Abs(Percent))
);
}
private int Lerp(int Start, int End, int Percent)
{
return ((int) ((float)(End - Start) * ((float)Percent / 100f)) + Start);
}
}
}
And here is the .Designer code as well (just replace what you already have when you make a new control by this name)
namespace FlashyButton
{
partial class FlashyButton
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.lblText = new System.Windows.Forms.Label();
this.tmrRedraw = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// lblText
//
this.lblText.AutoSize = true;
this.lblText.Location = new System.Drawing.Point(4, 4);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(55, 17);
this.lblText.TabIndex = 0;
this.lblText.Text = "Sample";
//
// tmrRedraw
//
this.tmrRedraw.Interval = 10;
this.tmrRedraw.Tick += new System.EventHandler(this.tmrRedraw_Tick);
//
// FlashyButton
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoSize = true;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Controls.Add(this.lblText);
this.Name = "FlashyButton";
this.Size = new System.Drawing.Size(148, 148);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lblText;
private System.Windows.Forms.Timer tmrRedraw;
}
}

This worked for me when I had a CheckBox with Appearance = Button and FlatStyle = Flat and wanted it flashing when checked:
private void timer_Flashing_Tick(object sender, EventArgs e)
{
if (checkBox_Refresh.Checked)
{
if (checkBox_Refresh.FlatAppearance.CheckedBackColor == Color.Red)
{
checkBox_Refresh.FlatAppearance.CheckedBackColor = Color.Transparent;
}
else
{
checkBox_Refresh.FlatAppearance.CheckedBackColor = Color.Red;
}
}
}

Related

Windows forms button parameters

Background Info:
For school, I need to make a crossword puzzle project in Windows Forms using OOP and the project needs to have a list build in it.
Problem:
For the functions in Form1.cs, I need to pass parameters (Object sender, Eventargs e) coming from the classes for the Form. The Project is OOP based.
Question:
error: There is no argument given that corresponds to the required formal parameter 'sender'
The errors are coming from:
menuOptions.aboutToolStripMenuItem_Click();
menuOptions.openPuzzleToolStripMenuItem_Click();
menuOptions.exitToolStripMenuItem_Click();
boardCells.Board_CellPainting();
boardCells.Board_CellValueChanged();
boardCells.formatCell();
My question is what do I need to do to solve the error?
Form1.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.IO;
namespace CrossWordPuzzle
{
public partial class Form1 : Form
{
//Object instances from classes
Clues clue_window = new Clues();
Cell boardCells = new Cell();
Menu menuOptions = new Menu();
Board board = new Board();
public Form1()
{
InitializeComponent();
//Board functions
board.buildWordList();
board.InitializeBoard();
//Menu functions
menuOptions.aboutToolStripMenuItem_Click();
menuOptions.openPuzzleToolStripMenuItem_Click();
menuOptions.exitToolStripMenuItem_Click();
menuOptions.InitializeComponent();
//Cell functions
boardCells.Board_CellPainting();
boardCells.Board_CellValueChanged();
boardCells.formatCell();
boardCells.InitializeComponent();
}
//Function loads form with window properties
public void Form1_Load(object sender, EventArgs e)
{
board.InitializeBoard();
clue_window.SetDesktopLocation(this.Location.X + this.Width + 1, this.Location.Y);
clue_window.StartPosition = FormStartPosition.Manual;
clue_window.Show();
clue_window.clueTable.AutoResizeColumns();
}
//Function location form window
public void Form1_LocationChanged(object sender, EventArgs e)
{
clue_window.SetDesktopLocation(this.Location.X + this.Width + 1, this.Location.Y);
}
}
}
(menuOptions) Menu Class
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace CrossWordPuzzle
{
class Menu : Form
{
//Object instances from classes
public DataGridView datagridview = new DataGridView();
public Form1 form = new Form1();
public string puzzle_file = Application.StartupPath + "\\Puzzles\\Puzzle1.pzl";
Clues clue_window = new Clues();
public List<id_cells> idc = new List<id_cells>();
Board board = new Board();
//Opens puzzle selector
public void openPuzzleToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Puzzle Files|*.pzl";
if (ofd.ShowDialog().Equals(DialogResult.OK))
{
puzzle_file = ofd.FileName;
datagridview.Rows.Clear();
clue_window.clueTable.Rows.Clear();
idc.Clear();
board.buildWordList();
board.InitializeBoard();
}
}
//Exit application function
public void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
//About menu function
public void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("CrossWordPuzzle made in C# Windows Forms", "CrossWordPuzzle");
return;
}
//Initialize Menu component
public void InitializeComponent()
{
this.SuspendLayout();
//
// Menu
//
this.ClientSize = new System.Drawing.Size(284, 261);
this.Name = "Menu";
this.Load += new System.EventHandler(this.Menu_Load);
this.ResumeLayout(false);
}
//Load Menu
private void Menu_Load(object sender, EventArgs e)
{
}
}
}
(boardCells) Cell class
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace CrossWordPuzzle
{
class Cell : Form
{
//Object instances from classes
public DataGridView datagridview = new DataGridView();
public List<id_cells> idc = new List<id_cells>();
public Form1 form = new Form1();
//Cell painting
public void Board_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
//Every time a cell gets drawn on the board, it comes with a rectangle that has the number of the word.
String number = "";
if (idc.Any(c => (number = c.number) != "" && c.X == e.ColumnIndex && c.Y == e.RowIndex))
{
Rectangle r = new Rectangle(e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width, e.CellBounds.Height);
e.Graphics.FillRectangle(Brushes.White, r);
Font f = new Font(e.CellStyle.Font.FontFamily, 7);
e.Graphics.DrawString(number, f, Brushes.Black, r);
e.PaintContent(e.ClipBounds);
e.Handled = true;
}
}
//Function for BoardCell design
public void Board_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
//make letter uppercase
try
{
form.Board[e.ColumnIndex, e.RowIndex].Value = form.Board[e.ColumnIndex, e.RowIndex].Value.ToString().ToUpper();
}
catch (Exception)
{
}
//Only 1 letter per cell
try
{
if (form.Board[e.ColumnIndex, e.RowIndex].Value.ToString().Length > 1)
{
form.Board[e.ColumnIndex, e.RowIndex].Value = form.Board[e.ColumnIndex, e.RowIndex].Value.ToString().Substring(0, 1);
}
}
catch (Exception)
{
}
//Change color if correct
try
{
if (form.Board[e.ColumnIndex, e.RowIndex].Value.ToString().ToUpper().Equals(form.Board[e.ColumnIndex, e.RowIndex].Tag.ToString().ToUpper()))
{
form.Board[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.DarkGreen;
}
else
{
form.Board[e.ColumnIndex, e.RowIndex].Style.ForeColor = Color.Red;
}
}
catch (Exception)
{
}
}
//Function for formatting Cell design on Board
public void formatCell(int row, int col, String letter)
{
DataGridViewCell c = form.Board[col, row];
c.Style.BackColor = Color.White;
c.ReadOnly = false;
c.Style.SelectionBackColor = Color.Cyan;
c.Tag = letter;
}
//Initialize Cell component
public void InitializeComponent()
{
this.SuspendLayout();
//
// Cell
//
this.ClientSize = new System.Drawing.Size(284, 261);
this.Name = "Cell";
this.Load += new System.EventHandler(this.Cell_Load);
this.ResumeLayout(false);
}
//Load Cell
private void Cell_Load(object sender, EventArgs e)
{
}
}
//Class for Cell id's
public class id_cells
{
public int X;
public int Y;
public String direction;
public String number;
public String word;
public String clue;
public id_cells(int x, int y, String d, String n, String w, String c)
{
this.X = x;
this.Y = y;
this.direction = d;
this.number = n;
this.word = w;
this.clue = c;
}
} //end of class
}
You are trying to call menuOptions.aboutToolStripMenuItem_Click(); but the function requires 2 parameters (object sender, EventArgs e);
You need to supply those parameters.
This is done automatically by the framework when you wire up events:
this.Load += new System.EventHandler(this.Cell_Load);
private void Cell_Load(object sender, EventArgs e)
{
}
When the Load event is triggered by the framework when a form is loaded, it will automatically pass in the sender and event args.
If you are trying to call those functions manually (i.e. in YOUR code), then you must supply those parameters.
You can fake it by using:
CellLoad(this, EventArgs.Empty);
What is confusing is why you have decided to call these functions during initialisation.
menuOptions.aboutToolStripMenuItem_Click();
menuOptions.openPuzzleToolStripMenuItem_Click();
menuOptions.exitToolStripMenuItem_Click();
Why do you want to press the exit button during startup?

Return empty string when placeholder is shown [duplicate]

This question already has answers here:
Watermark TextBox in WinForms
(11 answers)
Closed 5 years ago.
I have a custom text box with placeholder effect. If the textbox is empty, the placeholder is shown.
When I pass the value of the textbox (when the textbox is empty and the placeholder is shown instead) to a function , it passes the placeholder value, but I want it to just pass an empty string.
I thought about overriding the Text property and do an internal check. Something like
public string Text
{
get
{
if (this.Text == this.Placeholder)
{
return "";
}
return this.Text;
}
set
{
this.Text = value;
}
}
but I don't know if this is possible. This would create an infinite loop, I think. How do I make this work?
I know I can use a custom property (e.g., ActualText instead of Text) to do this, but if it's possible, I'd like to use Text. If not, I'll use a custom property.
using System;
using System.Drawing;
using System.Windows.Forms;
using CustomExtensions;
namespace CustomControls
{
public class CustomTextBox : TextBox
{
private string _placeholder;
public string Placeholder
{
get
{
return this._placeholder;
}
set
{
this._placeholder = value;
if (value.IsEmpty(true))
{
this._placeholder = "";
}
else
{
this._placeholder = value;
}
}
}
public CustomTextBox()
{
Initialize();
}
private void Initialize()
{
this.Enter += new EventHandler(this.Placeholder_Hide);
this.Leave += new EventHandler(this.Placeholder_Show);
}
// called from MainForm_Load
public void InitPH()
{
if (!this.Placeholder.IsEmpty(true) && this.Text.IsEmpty())
{
this.Text = this.Placeholder;
this.ForeColor = Color.Gray;
this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
}
}
private void Placeholder_Hide(object sender, EventArgs e)
{
if (this.Text == this._placeholder)
{
this.Text = "";
this.ForeColor = Color.Black;
this.Font = new Font("Segoe UI", 10.2F, FontStyle.Regular);
}
}
private void Placeholder_Show(object sender, EventArgs e)
{
if (this.IsEmpty())
{
this.Text = this._placeholder;
this.ForeColor = Color.Gray;
this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
}
}
public bool IsEmpty()
{
return this.Text.IsEmpty(true, this.Placeholder);
}
}
}
It would be best not to do if (this.Text == this._placeholder), because what if somebody actually entered the same text as the placeholder? It may be unlikely, but you don't want to leave in the possibility of unintended behavior.
One possible alternative is the following:
Add a field to your class, _valueIsSet, of type bool. Then, modify your event handlers to set it accordingly.
private void _valueIsSet = false;
private void Placeholder_Hide(object sender, EventArgs e)
{
if (!this._valueIsSet)
{
this.Text = "";
this.ForeColor = Color.Black;
this.Font = new Font("Segoe UI", 10.2F, FontStyle.Regular);
}
}
private void Placeholder_Show(object sender, EventArgs e)
{
if (this.IsEmpty())
{
this._valueIsSet = false;
this.Text = this._placeholder;
this.ForeColor = Color.Gray;
this.Font = new Font("Segoe UI", 10.2F, FontStyle.Italic);
}
}
Then, add an event handler for your text box's KeyDown event:
private void customTextBox_KeyDown(object sender, KeyEventArgs e)
{
this._valueIsSet = true;
}
Finally, create a property, myText:
public string myText
{
get
{
return this._valueIsSet ? this.Text : null;
}
}
You can set a cue text on the TextBox that won't affect the Text property. See EM_SETCUEBANNER for more information.
Define the following on your Form
private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);
Then in your Form Load
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "http://example.com");
}

Changing the color of the elements of a UserControl

i have a problem whit an userControl.
When I try to hover it to change the color of all the components , the function "ChangeColor" isn't fire correctly.
If I hover on the label or picturebox of the usercontrol, it is evoked the event mouseLeave
This is my userControl
public partial class infoUser : UserControl
{
public infoUser()
{
InitializeComponent();
}
public void SetNome(string nome)
{
labelUserLogged.Text = nome;
}
public void ChangeColor(System.Drawing.Color color)
{
labelUserLogged.BackColor = color;
pictureBoxUser.BackColor = color;
}
private void infoUser_MouseHover(object sender, EventArgs e)
{
ChangeColor(Color.CadetBlue);
}
private void infoUser_MouseLeave(object sender, EventArgs e)
{
ChangeColor(Color.WhiteSmoke);
}
}
Code of designer
private void InitializeComponent()
{
this.labelUserLogged = new System.Windows.Forms.Label();
this.pictureBoxUser = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxUser)).BeginInit();
this.SuspendLayout();
//
// labelUserLogged
//
this.labelUserLogged.BackColor = System.Drawing.SystemColors.Control;
this.labelUserLogged.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.labelUserLogged.Cursor = System.Windows.Forms.Cursors.Hand;
this.labelUserLogged.Location = new System.Drawing.Point(0, 0);
this.labelUserLogged.Name = "labelUserLogged";
this.labelUserLogged.Size = new System.Drawing.Size(167, 27);
this.labelUserLogged.TabIndex = 3;
this.labelUserLogged.Text = "Non loggato";
this.labelUserLogged.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// pictureBoxUser
//
this.pictureBoxUser.BackColor = System.Drawing.Color.Transparent;
this.pictureBoxUser.Cursor = System.Windows.Forms.Cursors.Hand;
this.pictureBoxUser.Image = global::Castor.Gestionale.Properties.Resources.user_icon;
this.pictureBoxUser.Location = new System.Drawing.Point(5, 6);
this.pictureBoxUser.Name = "pictureBoxUser";
this.pictureBoxUser.Size = new System.Drawing.Size(18, 15);
this.pictureBoxUser.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.pictureBoxUser.TabIndex = 4;
this.pictureBoxUser.TabStop = false;
//
// infoUser
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.pictureBoxUser);
this.Controls.Add(this.labelUserLogged);
this.Name = "infoUser";
this.Size = new System.Drawing.Size(171, 30);
this.MouseLeave += new System.EventHandler(this.infoUser_MouseLeave);
this.MouseHover += new System.EventHandler(this.infoUser_MouseHover);
((System.ComponentModel.ISupportInitialize)(this.pictureBoxUser)).EndInit();
this.ResumeLayout(false);
}
Child controls of your UserControl are receive the mouse-input when cursor is within it's bounds. So, when your mouse "enter" into the label/picturebox it "leave" the UserControl and etc.
To make the specific child control "transparent" for mouse events you can use the following trick:
const int WM_NCHITTEST = 0x84, HTTRANSPARENT = (-1);
class HitTestTransparentPictureBox : PictureBox {
protected override void WndProc(ref Message m) {
if(m.Msg == WM_NCHITTEST) {
m.Result = new IntPtr(HTTRANSPARENT);
return;
}
base.WndProc(ref m);
}
}
class HitTestTransparentLabel : Label {
protected override void WndProc(ref Message m) {
if(m.Msg == WM_NCHITTEST) {
m.Result = new IntPtr(HTTRANSPARENT);
return;
}
base.WndProc(ref m);
}
}
Then you can replace the specific controls in your UserControl with their "mouse-transparent" analogs:
this.labelUserLogged = new HitTestTransparentLabel();
this.pictureBoxUser = new HitTestTransparentPictureBox();
After that you can use the following approach to create hover-effect on UserControl:
public infoUser() {
InitializeComponent();
MouseEnter += infoUser_MouseEnter;
MouseLeave += infoUser_MouseLeave;
}
void infoUser_MouseLeave(object sender, EventArgs e) {
Hover = false;
}
void infoUser_MouseEnter(object sender, EventArgs e) {
Hover = true;
}
bool hoverCore;
protected bool Hover {
get { return hoverCore; }
set {
if(hoverCore == value) return;
hoverCore = value;
OnHoverChanged();
}
}
void OnHoverChanged() {
ChangeColor(Hover ? Color.CadetBlue : Color.WhiteSmoke);
}

Paint on next frame on Windows's graphics?

I need to draw some things on the screen for only 1 frame.
Things such as a line of text.
I tried to achieve this with moving windows, but I failed. I cannot get them to show for only 1 frame (8-16 msec), either by showing/hiding or moving in and out of place.
Is there any way to do this?
(Urgh, for the curious, I'm doing this for someone else, so rationalizing over the reason why this needs to be done is useless.)
Edit: Last thing I tried:
public partial class Form2 : Form
{
static Random rand = new Random();
public void ShowString(string s)
{
this.label1.Text = s; // Has .AutoSize = true
this.Size = this.label1.Size;
var bnds = Screen.PrimaryScreen.WorkingArea;
bnds.Size -= this.Size;
this.Location = new Point(rand.Next(bnds.X, bnds.Right), rand.Next(bnds.Y, bnds.Bottom));
}
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (Location.X != -10000 && Location.Y != -10000)
{
Location = new Point(-10000, -10000);
timer1.Interval = Program.interval; // How long to wait before showing two things.
}
else
{
timer1.Interval = Program.delay; // For how long to show.
ShowString("just something to test");
}
}
}
And before that:
public partial class Form2 : Form
{
static Random rand = new Random();
public void ShowString(string s)
{
this.label1.Text = s; // Has .AutoSize = true
this.Size = this.label1.Size;
var bnds = Screen.PrimaryScreen.WorkingArea;
bnds.Size -= this.Size;
this.Location = new Point(rand.Next(bnds.X, bnds.Right), rand.Next(bnds.Y, bnds.Bottom));
}
public Form2()
{
InitializeComponent();
timer1.Interval = Program.interval;
}
private void Form2_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void Form2_Move(object sender, EventArgs e)
{
if (Location.X != -10000 && Location.Y != -10000)
{
Thread.Sleep(Program.delay); // Dirty cheat, but I was just trying.
this.Location = new Point(-10000, -10000);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
ShowString("just something to test");
}
}

Creating a tooltip from a system-tray only app

So I'm trying to create a tooltip at some point on the screen.
ToolTip tip = new ToolTip();
tip.Show("foobar", **IWin32Window window**, new Point(100, 100))
The problem is I don't know what to insert as the window parameter in the above. My app runs entirely out of the system tray, and has no other GUI elements. It's called notifyIcon1. That is created through Form1. Neither of these values work when plugged in to tip.Show().
How can I generate a tooltip anywhere on my screen using only the system tray?
Thanks.
The IWin32Window interface is a simple interface that only provides a IntPtr property named Handle. Feasibly something like this should work:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace SO_ToolTip
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
WindowWrapper windowWrapper = new WindowWrapper(GetDesktopWindow());
ToolTip toolTip = new ToolTip();
toolTip.Show("Blah blah... Blah blah... Blah blah...", windowWrapper, 1, 1, 10000);
}
}
public class WindowWrapper : IWin32Window
{
public WindowWrapper(IntPtr handle)
{
Handle = handle;
}
public IntPtr Handle { get; protected set; }
}
}
But it doesn't. It complains about a NullReferenceException and I haven't debugged further. This does work:
...
private void button1_Click(object sender, EventArgs e)
{
ToolTip toolTip = new ToolTip();
toolTip.Show("Blah blah... Blah blah... Blah blah...", this, 1, 1, 10000);
}
...
Although the position is relative to the current form. Maybe that will get you going in the right direction.
Edit: Even this doesn't work so I'm not sure if it's an issue with WindowWrapper (how?) or what:
...
private void button1_Click(object sender, EventArgs e)
{
WindowWrapper windowWrapper = new WindowWrapper(this.Handle);
ToolTip toolTip = new ToolTip();
toolTip.Show("Blah blah... Blah blah... Blah blah...", windowWrapper, 1, 1, 10000);
}
...
Here you go, use a transparent, maximized form that you BringToFront() before showing the ToolTip
Form1 Code:
using System;
using System.Windows.Forms;
namespace SO_ToolTip
{
public partial class Form1 : Form
{
Random _Random = new Random();
ToolTip _ToolTip = new ToolTip();
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
BringToFront();
_ToolTip.Show("Blah blah... Blah blah... Blah blah...", this, _Random.Next(0, Width), _Random.Next(0, Height), 10000);
}
}
}
Form1 Designer Code: So you can see the forms properties:
namespace SO_ToolTip
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 264);
this.ControlBox = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.Opacity = 0;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timer1;
}
}
Joining late to the party:
In case you prefer/need to have WPF window:
private class ToolTipWPFWindow : Window
{
private readonly TextBlock m_txtToDisplay = new TextBlock();
private readonly DispatcherTimer m_timer = new DispatcherTimer();
public ToolTipWindow(string p_strStringToDisplay, int p_intXOnScreen = 0, int p_intYOnScreen = 0, double p_dblDurationInMilliSeconds = 1500)
{
if (p_intXOnScreen == 0 && p_intYOnScreen == 0)
{
p_intXOnScreen = System.Windows.Forms.Cursor.Position.X;
p_intYOnScreen = System.Windows.Forms.Cursor.Position.Y;
}
m_txtToDisplay.Text = p_strStringToDisplay;
m_txtToDisplay.Margin = new Thickness(3);
Background = new SolidColorBrush(Colors.LightGoldenrodYellow);
ShowInTaskbar = false;
ResizeMode = System.Windows.ResizeMode.NoResize;
Topmost = true;
// Location on screen - As Set
WindowStartupLocation = WindowStartupLocation.Manual;
Left = p_intXOnScreen;
Top = p_intYOnScreen;
WindowStyle = WindowStyle.None;
SizeToContent = SizeToContent.WidthAndHeight;
Content = m_txtToDisplay;
m_timer.Interval = TimeSpan.FromMilliseconds(p_dblDurationInMilliSeconds);
m_timer.Tick += timer_Tick;
m_timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
if (m_timer != null)
{
m_timer.Stop();
m_timer.Tick -= timer_Tick;
}
Close();
}
Usage:
// Display the ToolTip Window to the right of the Cursor
int intX = Cursor.Position.X + 20;
int intY = Cursor.Position.Y;
ToolTipWindow wpfWindow = new ToolTipWindow("Text To Display", intX, intY, 800);
wpfWindow.Show();
Result:
I didn't implement the Mouse leave event, since I've used short display duration.

Categories