0

I'm having a rather irritating problem with images on buttons in .NET. They don't behave as you would expect an image on a button to behave.

In the properties of a button you can set Image. So I select an image and the image shows up on the button! So far so good. When a button is clicked, or in a pressed state, the text of the button will move down and right one pixel to create a depth. But not the image! It will stay in the same position, and it will look weird. There is also the BackgroundImage property, but that's even worse! Because if I set BackgroundImageLayout to None instead of Center, the image will move up and left when pressed, the complete opposite direction of the text! What's up with that?

Anyway, what I want to achieve is a button image that moves just like the text would move when the button is in a pressed state. Is there a way to do this?

Labbed
  • 31
  • 2

1 Answers1

0

Just make a new image and paste the original one at an offset. Then set that as the Button's Image.

Example:

private void button1_MouseDown(object sender, MouseEventArgs e)
{
    // replace "button_image.png" with the filename of the image you are using
    Image normalImage = Image.FromFile("button_image.png");
    Image mouseDownImage = new Bitmap(normalImage.Width + 1, normalImage.Height + 1);
    Graphics g = Graphics.FromImage(mouseDownImage);
    // this will draw the normal image at an offset on mouseDownImage
    g.DrawImage(normalImage, 1, 1); // offset is one pixel each for x and y
    // clean up
    g.Dispose();
    button1.Image = mouseDownImage;
}

private void button1_MouseUp(object sender, MouseEventArgs e)
{
    // reset image to the normal one
    button1.Image = Image.FromFile("button_image.png");
}

EDIT: The following function fixes a problem where the image would not 'pop' back up when the cursor leaves the button area while the mouse button is still pressed (see Labor's comment below):

private void button1_MouseMove(object sender, MouseEventArgs e)
{
    Point relMousePos = e.Location;
    bool mouseOverButton = true;
    mouseOverButton &= relMousePos.X > 0;
    mouseOverButton &= relMousePos.X < button1.Width;
    mouseOverButton &= relMousePos.Y > 0;
    mouseOverButton &= relMousePos.Y < button1.Height;
    if (mouseOverButton != MouseButtons.None)
    {
        button1_MouseDown(sender, e);
    }
    else
    {
        button1_MouseUp(sender, e);
    }
}
Timo
  • 263
  • 3
  • 8
  • That works nicely until you move the cursor outside the button while the button is pressed. The button will pop up again, as will the text, but not the image. Also, some graphic layouts doesn't have the text move down/right, so it would be great to have some way to determine the position of the text, or something, so the image always has the same offset as the text. – Labbed Jul 07 '13 at 20:27
  • @Labbed: I'm not sure about getting the text offset, you'd probably need to draw the button to a bitmap (there's a function for that: `button1.DrawToBitmap`) and look for black pixels. I'll edit my answer to fix the problem when the cursor leaves the button area, though. – Timo Jul 07 '13 at 21:00
  • Thanks, but now it will trigger MouseDown as soon as I hover the button. Looking for black pixels is not a good idea either, since you can change the color of text and most systems today use ClearType for control text, so you can't look for the System Color either. I'm actually not even using text on the button, I just want the image to move like in other programs with images on buttons. I don't understand why .NET has this weird behavior by default. – Labbed Jul 07 '13 at 21:44
  • @Labbed: Change the `if (mouseOverButton) { ... }` to `if (mouseOverButton && e.Button != MouseButtons.None) { ... }` (I edited my answer above). If the movement of the text is a problem, you could make a button yourself, of course (perhaps a user control with an empty `Button` as the background and a `Label` and `PictureBox` in the foreground. – Timo Jul 08 '13 at 14:13
  • Now it acts weird if I right-click. I don't think this is the right approach. Is there really no way to get the text offset? I want the image to move just like text would move, and manually moving the image one pixel down-right isn't a solid solution, since you can change border width of system controls which would make text move more than one pixel, and some graphic layouts doesn't even move the text at all. Thanks for your help so far, by the way. I appreciate it. – Labbed Jul 08 '13 at 16:43
  • @Labbed: I'm afraid you cannot really get the text offset (by the way, what OS/platform are you using?). Perhaps you should make a small UserControl to control the movement of the text and image yourself. – Timo Jul 14 '13 at 13:14
  • I'm using Windows XP. – Labbed Jul 14 '13 at 19:16
  • @Labbed: I can't reproduce the problem with text moving in different directions because I'm using Windows 8. What does the text direction depend on? Maybe you could check for that. – Timo Jul 15 '13 at 19:00
  • The text will always move down-right on my settings. The image moves up-left (?!) if it's a BackgroundImage with BackgroundImageLayout set to None, or it will stay exactly where it is with any other setting, which makes you think you didn't really click the button since it didn't move like it's supposed to. – Labbed Jul 15 '13 at 21:28
  • If you only use settings where the text moves towards the bottom-right this code might be enough. If you know where the text moves under which circumstances, you might be able to adapt the code to your needs. – Timo Jul 15 '13 at 21:37
  • I'm not the only user of my application, and if I make it always move down-right it might look strange for other people with other graphic settings where buttons behave differently. If I knew of a system or button property that gives my program information on how buttons behave when clicked, I'd use that. – Labbed Jul 16 '13 at 04:17
  • @Labbed: I'm sorry, I can't help you with figuring out the text offset. If buttons always behave the same on all XP systems, you could use `System.Environment.OSVersion` to determine the Windows version and only display the moving image on XP and other systems with similar behavior. This might help with that: http://stackoverflow.com/questions/545666/how-to-translate-ms-windows-os-version-numbers-into-product-names-in-net – Timo Jul 16 '13 at 15:27