views:

267

answers:

1

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.

+1  A: 

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;

    }
}
Cory Charlton
I don't think it's that complicated, I vaguely remember that you can get an IWin32Window from a form without implementing your own class.
John Knoeller
Correct, `Form` implements the `IWin32Window` interface, that's what happens when I pass `this` which is my Form1 object. The issue is that he wants to draw a tooltip anywhere on the screen (ie: to the desktop). Which by nature is just another window. I went the p/invoke route because I readily had a method to get the desktop handle.
Cory Charlton
Got it. carry on ;)
John Knoeller
Actually, this isn't quite correct. `BringToFront()` is bringing the the tooltip to the front, sure, but also taking the textbox I'm writing to out of focus. Not ideal.
cksubs
This just seems so much harder than it should be. I did a prototype of this program in autohotkey. AHK has a `tooltip("foo", 10, 10)` method that put the tooltip wherever you wanted it. It's kinda insane that it isn't that easy with the much more robust C#.
cksubs
http://www.codeproject.com/KB/dialog/CaretPosition.aspx - looking at this now.
cksubs