Writing text to the system tray instead of an icon
Asked Answered
M

1

23

I am trying to display 2-3 updatable characters in the system tray rather than display an .ico file - similar to what CoreTemp does when they display the temperature in the system try:

enter image description here

I am using a NotifyIcon in my WinForms application along with the following code:

Font fontToUse = new Font("Microsoft Sans Serif", 8, FontStyle.Regular, GraphicsUnit.Pixel);
Brush brushToUse = new SolidBrush(Color.White);
Bitmap bitmapText = new Bitmap(16, 16);
Graphics g = Drawing.Graphics.FromImage(bitmapText);

IntPtr hIcon;
public void CreateTextIcon(string str)
{
    g.Clear(Color.Transparent);
    g.DrawString(str, fontToUse, brushToUse, -2, 5);
    hIcon = (bitmapText.GetHicon);
    NotifyIcon1.Icon = Drawing.Icon.FromHandle(hIcon);
    DestroyIcon(hIcon.ToInt32);
}

Sadly this produces a poor result nothing like what CoreTemp gets:

enter image description here

You'd think the solution would be to increase the font size, but anything over size 8 doesn't fit inside the image. Increasing the bitmap from 16x16 to 32x32 does nothing either - it gets resized down.

Then there's the problem of me wanting to display "8.55" instead of just "55" - there's enough space around the icon but it appears unusable.

enter image description here

Is there a better way to do this? Why can windows do the following but I cannot?

enter image description here

Update:

Thanks for @NineBerry for a good solution. To add, I find Tahoma to be the best font to use.

Macdermot answered 2/4, 2016 at 22:43 Comment(1)
I would expect that other applications just use a set of in-built icons rather than try to generate them on-the-flySuggestive
K
28

This gives me a quite good looking display of a two digit string:

enter image description here

private void button1_Click(object sender, EventArgs e)
{
    CreateTextIcon("89");
}

public void CreateTextIcon(string str)
{
    Font fontToUse = new Font("Microsoft Sans Serif", 16, FontStyle.Regular, GraphicsUnit.Pixel);
    Brush brushToUse = new SolidBrush(Color.White);
    Bitmap bitmapText = new Bitmap(16, 16);
    Graphics g = System.Drawing.Graphics.FromImage(bitmapText);

    IntPtr hIcon;
    
    g.Clear(Color.Transparent);
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
    g.DrawString(str, fontToUse, brushToUse, -4, -2);
    hIcon = (bitmapText.GetHicon());
    notifyIcon1.Icon = System.Drawing.Icon.FromHandle(hIcon);
    DestroyIcon(hIcon.ToInt32);
}

What I changed:

  1. Use a larger font size, but move the x and y offset further to the left and top (-4, -2).

  2. Set TextRenderingHint on the Graphics object to disable anti-aliasing.

It seems impossible to draw more than 2 digits or characters. The icons have a square format. Any text longer than two characters would mean reducing the height of the text a lot.

The sample where you select the keyboard layout (ENG) is actually not a notification icon in the tray area but its very own shell toolbar.


The best I could achieve to display 8.55:

enter image description here

private void button1_Click(object sender, EventArgs e)
{
    CreateTextIcon("8'55");
}

public void CreateTextIcon(string str)
{
    Font fontToUse = new Font("Trebuchet MS", 10, FontStyle.Regular, GraphicsUnit.Pixel);
    Brush brushToUse = new SolidBrush(Color.White);
    Bitmap bitmapText = new Bitmap(16, 16);
    Graphics g = System.Drawing.Graphics.FromImage(bitmapText);

    IntPtr hIcon;
    
    g.Clear(Color.Transparent);
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
    g.DrawString(str, fontToUse, brushToUse, -2, 0);
    hIcon = (bitmapText.GetHicon());
    notifyIcon1.Icon = System.Drawing.Icon.FromHandle(hIcon);
    //DestroyIcon(hIcon.ToInt32);
}

with the following changes:

  1. Use Trebuchet MS which is a very narrow font.
  2. Use the single quote instead of the dot because it has less space at the sides.
  3. Use font size 10 and adapt the offsets adequately.
Keffer answered 2/4, 2016 at 23:45 Comment(3)
Also, just to say that I find "Tahoma" to be the best font to use here.Macdermot
You need the line: DestroyIcon(hIcon) to prevent the app from quitting after about 50 minutes due to a memory leak.Procarp
yes, Icon newIcon = Icon.FromHandle(hIcon); newIcon = newIcon.Clone() as Icon; DestroyIcon(hIcon); clone the created icon and it'll be managed by .NET, the one returned by GetHicon needs to be destroyed.Dalessandro

© 2022 - 2025 — McMap. All rights reserved.