elnigno
elnigno

Reputation: 1821

How to put an image beside the text of a ToolStripMenuItem (or similar control)?

I know that it's possible to add an image to a ToolStripMenuItem, like in the "Close All Documents" item in the image below:

Menu with some ToolStripMenuItems

However, what I would like to achieve is something like this:

enter image description here

That is to place the image to the side of the item's text, but without overlapping the check space. I have searched a bit but couldn't find a Winforms control that can do this. Can you point me to any? Or do I have to implement my own? Thank you.

EDIT: thanks everyone for the answers! I will accept one after the weekend.

Upvotes: 4

Views: 2308

Answers (4)

King King
King King

Reputation: 63317

You have to use some custom painting. There are some ways to implement this, however I would like to introduce to using some custom ToolStripRenderer. The following is just a demo code, you can improve it yourself. I save each inner Image in the corresponding Item's Tag for convenience:

public class CustomRenderer : ToolStripProfessionalRenderer
{
    int innerImagePadding = 2;
    protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) {
        Image img = e.Item.Tag as Image;
        if(img == null) base.OnRenderItemText(e);
        else {
          e.Graphics.DrawImage(img, e.Item.ContentRectangle.Left + e.Item.Bounds.Height + innerImagePadding,
                               e.Item.ContentRectangle.Top + innerImagePadding, 
                               Math.Max(1, e.Item.ContentRectangle.Height - innerImagePadding*2), 
                               Math.Max(1, e.Item.ContentRectangle.Height - innerImagePadding*2));              
          Rectangle textRect = new Rectangle(e.Item.ContentRectangle.Left + e.Item.Bounds.Height*2, 
                               e.Item.ContentRectangle.Top +1, 
                               e.TextRectangle.Width, 
                               e.TextRectangle.Height);
          e.Graphics.DrawString(e.Text, e.TextFont, new SolidBrush(e.TextColor), textRect);
       }
    }
}

//Usage
ContextMenuStrip cm = new ContextMenuStrip();
cm.Items.Add(new ToolStripMenuItem("Clear all", myImage) {Tag = myImage});
cm.Items.Add(new ToolStripMenuItem("Remove all", myImage){Tag = myImage});
this.ContextMenuStrip = cm; //set the ContextMenuStrip for the form
//set the custom Renderer
cm.Renderer = new CustomRenderer();

enter image description here

Upvotes: 4

LarsTech
LarsTech

Reputation: 81610

You can't do it from the designer, but you can show the extra margins by casting the parent DropDown property to a ToolStripDownDownMenu item to access the Show properties:

public Form1() {
  InitializeComponent();
  ((ToolStripDropDownMenu)FileMenuItem.DropDown).ShowCheckMargin = true;
  ((ToolStripDropDownMenu)FileMenuItem.DropDown).ShowImageMargin = true;
}

Result:

enter image description here

Upvotes: 3

Alex Walker
Alex Walker

Reputation: 2356

There isn't a control in the standard .NET API that has this functionality, and therefore you have to write it yourself as a new feature.

However, depending on how often you want to use this "new" feature, there could be efficient ways of implementing it. One solution I believe could work neatly is to make use of the fact that these images have a fixed size, and indent the text accordingly.

Consider an approach such as the following:

using System.Drawing;

const string MENU_TEXT_INDENT = "           ";

private void MenuItemWithImage_Paint(Object sender, PaintEventArgs e) {
    ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
    if (!menuItem.Text.StartsWith(MENU_TEXT_INDENT)) {
        menuItem.Text = menuItem.Text.Insert(0, MENU_TEXT_INDENT);
    }
    Image img = menuItem.Image;
    e.Graphics.DrawImage(img, new Point(0, 0));
    menuItem.Refresh(); // May be needed to reflect changes - try without though!
}

If you then attach this event handler to the Paint event of each menu item with an image to render in this way, this should work. (You may need more or less spaces - I haven't tested it myself)

Upvotes: 0

Hossain Muctadir
Hossain Muctadir

Reputation: 3626

You can paint anything anywhere of the control with paint event. For example -

void myToolStripMenuItem1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawImage(Image.FromFile("open_icon.jpg"), 0, 0);
}

This puts the image at (0,0) position. you can put it anywhere you want.

Upvotes: 1

Related Questions