5,663,486 members and growing! (14,033 online)
Email Password   helpLost your password?
Desktop Development » Menus » Menus and Toolbars     Beginner License: The Code Project Open License (CPOL)

FishEye Menu in Winforms

By Matias Szulman

Brief How-To on a FishEye Menu
C# 2.0, C#Windows, .NET, .NET 2.0, WinXPVS2005, Visual Studio, Dev

Posted: 12 Mar 2007
Updated: 12 Mar 2007
Views: 34,583
Bookmarked: 40 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
38 votes for this Article.
Popularity: 6.62 Rating: 4.19 out of 5
3 votes, 7.9%
1
3 votes, 7.9%
2
2 votes, 5.3%
3
7 votes, 18.4%
4
23 votes, 60.5%
5
Screenshot - fisheye.jpg

Introduction

This is my first article, in which I try to present a basic way to make a fish eye menu control, in which the item the mouse is over is enlarged, and the surrounding items increase and decrease their size when you move the mouse.

Background

There was a post on the forums that linked to a Web site with several alternative menus that are coming in the future. I wanted to know how hard it would be to implement something like the fish eye menu, and although the code is very basic, it serves as a starting point for improving and making it better.

Using the Code

As a first version of the code, stuff is very messy. First of all, there are class and attribute names in both Spanish and English, as I wasn't thinking of posting this article. In the course of this week, I'll correct it and upload the new version.

There is a class called Item, which represents each of the different menu items. This class has very basic attributes, such as:

private string _valor;
private float _inicio;
private float _fin;
private bool _over; 

_valor is the value of the item, which in this case is just a string, but it can be any supported type. _inicio and _fin are the y axis limits in which the item is displayed. _over indicates if the mouse is currently over the specified item.

The control, which in this case is the form itself, has three other attributes:

private int? _indexOver;
private Item _itemOver;
private List<Item> _items;

_indexOver is the variable that holds the index of the item the mouse is over. Since it can be null, the variable is nullable. _itemOver corresponds to the specified item, and it can also be null. _items contains the item list, which in this case is loaded in the Form_Load event.

Constructor

In order to reduce the flickering and enhance the visual experience and responsiveness, there are some calls to the SetStyle method of the control in its constructor:

this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.CacheText, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.UserPaint, true);

What this basically does is configure the control so that I (the developer) am responsible for its drawing, and sets it to use double buffer and to cache text so it renders faster.

In the Form_Load method I just use a for to fill the _items collection, but this could be done by getting info from a datasource, receiving it as a parameter, or even setting it as a property from an external object.

The two main methods are Form1_MouseMove and OnPaint (which is overridden in this class). I will not copy the code, as it is available in the source code, but instead I will give you some insight into what it does.

OnPaint

This method is in charge of drawing the menu. It is called every time the form has to be redrawn, and it overrides the method of the base class (but it doesn't call it, so the whole painting is done in this method).

First of all, this method calculates the height of the regular items (where the mouse is not over nor near), using a basic (and not accurate) calculation of the form height over item count, just to get an average height (this calculation will be corrected in the second version of the article).

Then, what it basically does is go through the list of items in the _items collection, and check the item over property. If the property is true, then it draws the item with bigger letters and in another color. If not, it checks the index of the current item to that of the item the mouse is over at. If the index is +/- 1, or +/- 2 then it draws the item in color and gives it a bigger size. If not, it draws the item in black and with the regular size. Every time an item is drawn, the current y position (currently that variable is named x but it will be corrected) is used as the starting point of the next item. So, if the item's height is greater because the mouse is over it or it's over an item close to it, then the next item will be redrawn correctly.

Form1_MouseMove

This method controls the mouse movement. First of all, it clears the _itemOver and _indexOver class attributes. Then it goes through the _items collection and for each item it calls the Esta(float y) method. This public method of the Item class receives a y position and returns whether it is between the item's _inicio and _fin attributes (beginning and end). If it's true, then the mouse is over the item, so it sets the item's Over property to true and updates the _itemOver and _indexOver class attributes. If it's false, then it sets the Over property to false. After going through the collection, if the mouse is over an item (checking either the _itemOver or the _indexOver for nulls), it sets the mouse cursor to Cursors.Hand. Otherwise, it sets it to Cursors.Default.

Finally, it calls the this.Invalidate() method that forces a redraw, and with it, a call to the OnPaint method, which redraws the menu.

Form1_MouseClick

This last method only shows the current item, if any is selected. It could be used to call a delegate, to return a value, or anything anyone would want from a menu.

Points of Interest

What I learnt from doing this is that it's really easy to create your own controls, with your own functionality and extend the .NET Framework functionality.

What's Next?

In the next update, which I'll plan to do by the end of this week, I will:

  • Update the code to add comments
  • Rewrite the code in a better class structure
  • Change all the Spanish names for easier, English names
  • Make it a user control instead of a form
  • Read your suggestions to try and improve this menu

History

  • 03/12/2007 - First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Matias Szulman



Occupation: Web Developer
Location: Argentina Argentina

Other popular Menus articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 18 of 18 (Total in Forum: 18) (Refresh)FirstPrevNext
GeneralNice jobmemberC#.Net3.019:10 22 Mar '07  
GeneralHi therememberksomi23:59 21 Mar '07  
GeneralNice!memberMuammar©23:10 19 Mar '07  
GeneralRe: Nice!memberMuammar©7:45 22 Mar '07  
GeneralRe: Nice!memberC#.Net3.019:09 22 Mar '07  
GeneralRe: Nice!memberMuammar©12:11 23 Mar '07  
GeneralGreat Job And A BugmemberBassam Abdul-Baki10:36 12 Mar '07  
GeneralRe: Great Job And A BugmemberMatias Szulman10:40 12 Mar '07  
GeneralInteresting Conceptmembernorm .net10:22 12 Mar '07  
GeneralGood Article!mvpDave Kreskowiak9:15 12 Mar '07  
GeneralPointer Selection...supportercode-frog8:38 12 Mar '07  
GeneralGood job!supporterJohn Cardinal8:23 12 Mar '07  
GeneralNot badsupporterMarc Clifton7:16 12 Mar '07  
GeneralRe: Not badmemberMatias Szulman8:29 12 Mar '07  
GeneralRe: Not badsupporterDavid Stone9:30 12 Mar '07  
GeneralRe: Not badsupporterMarc Clifton9:58 12 Mar '07  
GeneralRe: Not badmemberJazzJackRabbit8:55 12 Mar '07  
GeneralRe: Not badmemberMatias Szulman10:00 12 Mar '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 12 Mar 2007
Editor: Deeksha Shenoy
Copyright 2007 by Matias Szulman
Everything else Copyright © CodeProject, 1999-2008
Web18 | Advertise on the Code Project