2

I created a custom form to show it as a ToolTip but to show data on it, the show will be display when the user hovers on a Button and disappear on mouse leave, everything works perfectly but how can I prevent the Form from display outside the screen area??

Here is the code I used to show the Form:

Info_Form tooltip = new Info_Form();
private void Button131_MouseHover(object sender, EventArgs e)
{
    Button b = (Button)sender;

    tooltip = new Info_Form();
    tooltip.Height = tooltip.Height + 30;
    tooltip.Location = new Point(
    b.Right,
    b.Top);

    tooltip.Show();
}

private void Button131_MouseLeave(object sender, EventArgs e)
{
    tooltip.Close();
}

enter image description here

Jimi
  • 29,621
  • 8
  • 43
  • 61
Rabeea qabaha
  • 526
  • 8
  • 23
  • 1
    Get the current screen using `Screen s = Screen.FromControl(c);` and then use `Rectangle r = s.WorkingArea;` to reposition your tool tip form if it doesn't fully intersect. – Loathing May 17 '21 at 01:50
  • @Loathing, after I get the `Rectangle` how can I apply this to the location of the shwon form ? – Rabeea qabaha May 18 '21 at 00:00

1 Answers1

2

I suggest to:

  • declare your ToolTip Form in Program.cs
  • add static Methods to show and hide it

Of course you can use a dedicated class that exposes static methods to handle your ToolTip Form

You can then reach your ToolTip Form from anywhere in your application, just call ShowToolTip() and HideToolTip() when the Mouse pointer enters or leaves a specific Control: the bounds of this Control, translated to Screen coordinates, are used as reference to position the ToolTip.

Here, I'm using a simplified method to determine whether the ToolTip should be shown to the right or left and to the top or bottom of the reference Control:

  • if the reference Control is positioned to the left half of the screen, then the left potion of the Form is: ToolTip.Left = [ref Control].Left
  • otherwise, ToolTip.Left = [ref Control].Right - ToolTip-Width
  • the same logic applies to the top position of the ToolTip

Adjust this simple calculation to position your ToolTip Form using a different logic, if needed.

▶ There's no need to dispose of the ToolTip Form: it's automatically disposed of when the Form instance passed to Application.Run() is closed.

Note: If the Application is not DpiAware and the Screen where the Application's Windows are shown is scaled, any measure relative to either the Screen or the Windows/Forms may be virtualized, so you receive wrong results and any calculation will be off.

See the notes here:
Using SetWindowPos with multiple monitors

using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;

public static frmToolTip tooltip = null;

[STAThread]
static void Main() {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    tooltip = new frmToolTip();
    Application.Run(new SomeForm());
}

public async static Task ShowToolTip(Control control, string title) {
    await Task.Delay(400);
    if (tooltip.Visible) return;

    Rectangle refBounds = control.RectangleToScreen(control.ClientRectangle);
    if (!refBounds.Contains(Cursor.Position)) {
        HideToolTip();
    }
    else {
        var screen = Screen.GetBounds(control);
        var leftPos = refBounds.Left <= screen.Width / 2 ? refBounds.Left : refBounds.Right - tooltip.Width;
        var topPos = refBounds.Top <= screen.Height / 2 ? refBounds.Bottom + 2: refBounds.Top - tooltip.Height - 2;
        tooltip.Location = new Point(leftPos, topPos);
        tooltip.Text = title;
        tooltip.Show(control.FindForm());
    }
}
public static void HideToolTip() => tooltip.Hide();

In any Form, use a Control's MouseEnter and MouseLeave events to show/hide your ToolTip.

Note: I'm using Task.Delay() to delay the presentation of the ToolTip, so it doesn't show up if you briefly move the Mouse Pointer over the Control that shows it.
It also verifies whether the Form ToolTip is already shown (you cannot show a Form twice) or the Mouse Pointer has moved outside the bounds of the reference Control in the meanwhile (the ToolTip is not shown in this case).

Change this behavior as required.

  • In ShowToolTip(), I'm passing a string, meant to be used as the Title of the ToolTip. It's just an example, to show that you may pass any other parameter to this method (a class object, maybe) to setup the ToolTip Form in a custom way, different based on the caller requirements.
using System.Threading.Tasks;

public partial class SomeForm : Form
{
   // [...]

    private async void SomeControl_MouseEnter(object sender, EventArgs e)
    {
        await Program.ShowToolTip(sender as Control, "Some Title Text");
    }

    private void SomeControl_MouseLeave(object sender, EventArgs e)
    {
        Program.HideToolTip();
    }
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Thank you, this a lot better way than what I did, but now I have the same problem with the Top and Bottom of the screen. – Rabeea qabaha May 18 '21 at 15:56
  • Ah, sure. Well, it's the same logic: if the Control that shows the ToolTip is located in the middle/top area of the screen, show the Form below it, otherwise... above it (besides)? Where do you want to show the tooltip? -- Of course you can make the calculation slightly more complex and always consider the ToolTip size. In case the ToolTip size can change, otherwise it's useless. – Jimi May 18 '21 at 15:59
  • Correct, I used this code to accomplish that `var TopPos = refBounds.Bottom <= screen.Height / 2 ? refBounds.Bottom : refBounds.Top - frm_info.Height;` – Rabeea qabaha May 18 '21 at 16:06
  • 1
    Thank you very much for the detailed answer, you made my day :) – Rabeea qabaha May 18 '21 at 16:09