Thread: onHover & onClick methods for a image class

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    29

    onHover & onClick methods for a image class

    Lets say we have a working window and HWND with:
    WS_CAPTION | WS_SYSMENU as dwStyles.
    and 500, 435 as nWidth, nHeight.

    Now we draw an image (bitmap or some format) on the window with some graphics libirary ( I'm using Gdi+).
    Lets have this in a class called MenuImage.

    How do we know when the mouse is indide bounds of the image's rect (onHover).

    And how dow we know when the user has clicked inside the bounds of the image's rect (onClick)

    I could do this processing WM_MOUSEMOVE and WM_LMOUSEDOWN
    but it seems so unindependent.

  2. #2
    Registered User Dante Shamest's Avatar
    Join Date
    Apr 2003
    Posts
    970
    These functions come to mind.

  3. #3
    Registered User
    Join Date
    Oct 2005
    Posts
    29
    Hum, I don't even need the 2 last functions.
    just a GetCursorPos([...]) call and a check with if.

    but it is dependent and its not good OOP to do so.
    How could you do this in a more modularized way ?

    This makes me think of collision handling with sprites, how do they do that with good OOP...

  4. #4
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    For click, you should handle the WM_LBUTTONUP message. For hover, have a look at the TrackMouseEvent function and WM_MOUSEHOVER message.

    >> but it seems so unindependent. <<

    I'm not sure what this means.

  5. #5
    Registered User Dante Shamest's Avatar
    Join Date
    Apr 2003
    Posts
    970
    The reason why I listed MapWindowPoints was because GetCursorPos returns the cursor position in screen coordinates. MapWindowPoints helps you change them to client coordinates for your window.

    I find PtInRect useful as I don't have to write my own routine.

    Anyway they're the functions I have been using of an application I've been developing. In my application, my image classes don't know anything about their position. I just call them to draw stuff at a specified location (x,y). My sprite classes on the other hand know their position.

    I never stored any graphics specific API commands in my sprite classes. This made it easier for me when I switched graphics libraries. E.g. SDL to Win32 + OpenGL.

  6. #6
    Registered User
    Join Date
    Oct 2005
    Posts
    29
    What i am trying to do is to get the same effect that a PictureBox has in C++.Net

    where i write:
    this->pictureBox1->Click += new System::EventHandler(this, pictureBox1_Click);
    this->pictureBox1->Hover += new System::EventHandler(this, pictureBox1_Click);
    this->pictureBox1->Leave += new System::EventHandler(this, pictureBox1_Leave);

    I don't want to know when the whole HWND has been hovered but i want to know when the "PictureBox" has been hovered / clicked / left.

    the best i've done so far is this:
    Code:
    			switch(_message)
    			{
    			case WM_LBUTTONUP:
    			{
    				int xPos = GET_X_LPARAM(_lParam);
    				int yPos = GET_Y_LPARAM(_lParam);
    
    				if( ((xPos >= 5) && (xPos <= 5 + 50)) && ((yPos >= 0) && (yPos <= 50)) && this->m_clickedItem != 1)
    				{
    					if(this->m_hoveredItem == 1)
    						this->m_hoveredItem = 0;
    
    					if(this->m_clickedItem)
    					{
    						switch(this->m_clickedItem)
    						{
    						case 2:
    							this->leave2();
    							break;
    						}
    					}
    					this->click1();
    				}
    				else if( ((xPos >= 60) && (xPos <= 60 + 50)) && ((yPos >= 0) && (yPos <= 50)) && this->m_clickedItem != 2)
    				{
    					if(this->m_hoveredItem == 2)
    						this->m_hoveredItem = 0;
    
    					if(this->m_clickedItem)
    					{
    						switch(this->m_clickedItem)
    						{
    						case 1:
    							this->leave1();
    							break;
    						}
    					}
    					this->click2();
    				}
    				break;
    			}
    			case WM_MOUSELEAVE:
    			{
    				t("t");
    				if(this->m_hoveredItem != 0)
    				{
    					switch(this->m_hoveredItem)
    					{
    					case 1:
    						if(this->m_clickedItem != 1)
    							this->leave1();
    						break;
    					case 2:
    						if(this->m_clickedItem != 2)
    						this->leave2();
    						break;
    					}
    					this->m_hoveredItem = 0;
    				}
    				break;
    			}
    			case WM_MOUSEMOVE:
    			{
    				int xPos = GET_X_LPARAM(_lParam);
    				int yPos = GET_Y_LPARAM(_lParam);
    				if( ((xPos >= 5) && (xPos <= 5 + 50)) && ((yPos >= 0) && (yPos <= 50)) )
    				{
    					if(this->m_hoveredItem == 0 && this->m_clickedItem != 1)
    						this->hover1();
    				}
    				else if( ((xPos >= 60) && (xPos <= 60 + 50)) && ((yPos >= 0) && (yPos <= 50)) )
    				{
    					if(this->m_hoveredItem == 0 && this->m_clickedItem != 2)
    						this->hover2();
    				}
    				else
    				{
    					if(this->m_hoveredItem)
    					{
    						switch(this->m_hoveredItem)
    						{
    						case 1:
    							if(this->m_clickedItem != 1)
    								this->leave1();
    							break;
    						case 2:
    							if(this->m_clickedItem != 2)
    							this->leave2();
    							break;
    						}
    
    						this->m_hoveredItem = 0;
    					}
    				}
    				break;
    			}
    for simplicity i have used filled rectagles now instead of picts...

    I'm creating a mainmenu like the one in the Firefox Options Window.
    (check the attachment for the firefox thinge)

    There should be some better way to do it since firefox expands the options menu if you install plugs...

  7. #7
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    If you're creating a toolbar, then what you probably want is to use hot-tracking. Check out the bottom of this page.
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

  8. #8
    Registered User
    Join Date
    Oct 2005
    Posts
    29
    I'd rather not use a toolbar.

    The previous works exept for that it doesn't receive WM_MOUSELEAVE
    and i've tried using TrackMouseEvent but it only says that
    the function, the struct and my struct instance doesn't exist (i have <windows.h> included as MSDN says)

    And my sulution is almost 100% procedural, infact the only thing that would stop me from thinking that this was C is the "this" pointers
    I'd need some class instead that is reusable...
    Firefox does it ( and even reads it in RTTI )... If it can we should be able to...
    I've checked the FF source code but I can't even find the correct file...

  9. #9
    Registered User
    Join Date
    Oct 2005
    Posts
    29
    this was the best i could do:
    The strange thing is that if you have more than one "imagemenuitem" only the first can be left/clicked/hovered.
    And if i hover the first and then take the mouse away to another "imagemenuitem" the previous won't be left.

    Code:
    #ifndef _IMAGEMENU_HPP // Inclution guard
    #define _IMAGEMENU_HPP
    
    #ifdef WIN32
    #include <vector>
    #include "ImageMenuItem.hpp"
    
    namespace Win
    {
    	class ImageMenu
    	{
    	private:
    		std::vector<ImageMenuItem> m_items;
    		int m_indexOfClickedItem, m_indexOfHoveredItem;
    
    		int m_xStart, m_yStart;
    		int m_nWidth, m_nHeight;
    		int m_offset;
    		int m_perImage;
    
    		Color m_bgColor, m_clickColor, m_hoverColor;
    
    	public:
    		ImageMenu(void)
    		{
    		}
    
    		ImageMenu(int _xStart, int _yStart, int _nWidth, int _nHeight, int _perImage, int _offset, Color _bgColor, Color _clickColor, Color _hoverColor)
    		{
    			this->m_xStart = _xStart;
    			this->m_yStart = _yStart;
    			this->m_nWidth = _nWidth;
    			this->m_nHeight = _nHeight;
    			this->m_offset = _offset;
    			this->m_perImage = _perImage;
    
    			this->m_bgColor = _bgColor;
    			this->m_clickColor = _clickColor;
    			this->m_hoverColor = _hoverColor;
    
    			this->m_indexOfClickedItem = this->m_indexOfHoveredItem = -1;
    		}
    
    		bool initiate()
    		{
    			return true;
    		}
    
    		void insert()
    		{
    			int _xStart;
    			if(!this->m_items.empty())
    				_xStart = this->m_items.back().m_xStart + this->m_items.back().m_nWidth + this->m_offset;
    			else
    				_xStart = this->m_offset;
    
    			ImageMenuItem _item(_xStart, this->m_yStart, this->m_perImage, this->m_nHeight);
    			this->m_items.push_back(_item);
    		}
    
    		void paint(Win::Window _window)
    		{
    			HDC _dc = GetDC(_window.receiveHWND());
    
    
    			ReleaseDC(_window.receiveHWND(), _dc);
    		}
    
    		bool isInBounds(int xPos, int yPos)
    		{
    			if(this->m_items.empty())
    				return false;
    
    			if( ((xPos >= this->m_xStart) && (xPos <= this->m_nWidth)) && ((yPos >= this->m_yStart) && (yPos <= this->m_nHeight)) )
    				return true;
    
    			return false;
    		}
    
    		void routeClick(Win::Window _window, int xPos, int yPos)
    		{
    			if((!this->m_items.empty()) && (yPos >= this->m_yStart) && (yPos <= this->m_nHeight))
    			{
    				for(int _index = 0; _index < (int)this->m_items.size(); _index++)
    				{
    					ImageMenuItem _item = this->m_items.at(_index);
    					if(!((xPos >= _item.m_xStart) && (xPos <= _item.m_nWidth)))
    						continue;
    					else if(this->m_indexOfClickedItem == _index)
    						continue;
    
    					_item.onClick(_window, this->m_clickColor);
    					this->m_indexOfClickedItem = _index;
    					break;
    				}
    			}
    		}
    
    		void routeHover(Win::Window _window, int xPos, int yPos)
    		{
    			if((!this->m_items.empty()) && (yPos >= this->m_yStart) && (yPos <= this->m_nHeight))
    			{
    				for(int _index = 0; _index < (int)this->m_items.size(); _index++)
    				{
    					ImageMenuItem _item = this->m_items.at(_index);
    					if(((xPos < _item.m_xStart) || (xPos > _item.m_nWidth)))
    					{
    						continue;
    					}
    					else if(this->m_indexOfClickedItem == _index || this->m_indexOfHoveredItem == _index)
    					{
    						continue;
    					}
    
    					//	char buffer[33];
    					//	::itoa(xPos, buffer, 10);
    					//	t(buffer);
    					_item.onHover(_window, this->m_hoverColor);
    					this->m_indexOfHoveredItem = _index;
    				}
    			}
    		}
    
    		bool isLeft(int xPos, int yPos)
    		{
    			if(this->m_items.empty())
    				return false;
    
    			if(this->m_indexOfHoveredItem == -1 || this->m_indexOfClickedItem == this->m_indexOfHoveredItem)
    				return false;
    
    			ImageMenuItem _item(this->m_items.at(this->m_indexOfHoveredItem));
    			if( ((xPos >= _item.m_xStart) && (xPos <= _item.m_nWidth)) && ((yPos >= _item.m_yStart) && (yPos <= _item.m_nHeight)) )
    				return false;
    
    			return true;
    		}
    
    		void routeLeave(Win::Window _window)
    		{
    			if((this->m_indexOfHoveredItem != -1) && (!this->m_items.empty()) )
    			{
    				this->m_items.at(this->m_indexOfHoveredItem).onLeave(_window, this->m_bgColor);
    				this->m_indexOfHoveredItem = -1;
    			}
    		}
    
    		~ImageMenu(void)
    		{
    		}
    	};
    }
    #endif
    #endif
    Code:
    #ifndef _IMAGEMENUITEM_HPP // Inclution guard
    #define _IMAGEMENUITEM_HPP
    
    #ifdef WIN32
    class ImageMenuItem
    {
    public:
    	int m_xStart, m_yStart;
    	int m_nWidth, m_nHeight;
    
    	ImageMenuItem(int _xStart, int _yStart, int _nWidth, int _nHeight)
    	{
    		this->m_xStart = _xStart;
    		this->m_yStart = _yStart;
    		this->m_nWidth = _nWidth;
    		this->m_nHeight = _nHeight;
    	}
    
    	ImageMenuItem(const ImageMenuItem &_imageMenuItem)
    	{
    		this->m_xStart = _imageMenuItem.m_xStart;
    		this->m_yStart = _imageMenuItem.m_yStart;
    		this->m_nWidth = _imageMenuItem.m_nWidth;
    		this->m_nHeight = _imageMenuItem.m_nHeight;
    	}
    
    	void onClick(Win::Window _window, Color _color)
    	{
    		HDC _dc = GetDC(_window.receiveHWND());
    		Graphics graphics(_dc);
    
    		SolidBrush _brush(_color);
    		graphics.FillRectangle(&_brush, this->m_xStart, this->m_yStart, this->m_nWidth, this->m_nHeight);
    
    		ReleaseDC(_window.receiveHWND(), _dc);
    	}
    
    	void onHover(Win::Window _window, Color _color)
    	{
    		HDC _dc = GetDC(_window.receiveHWND());
    		Graphics graphics(_dc);
    
    		SolidBrush _brush(_color);
    		graphics.FillRectangle(&_brush, this->m_xStart, this->m_yStart, this->m_nWidth, this->m_nHeight);
    
    		ReleaseDC(_window.receiveHWND(), _dc);
    	}
    
    	void onLeave(Win::Window _window, Color _color)
    	{
    		HDC _dc = GetDC(_window.receiveHWND());
    		Graphics graphics(_dc);
    
    		SolidBrush _brush(_color);
    		graphics.FillRectangle(&_brush, this->m_xStart, this->m_yStart, this->m_nWidth, this->m_nHeight);
    
    		ReleaseDC(_window.receiveHWND(), _dc);
    	}
    
    	~ImageMenuItem(void)
    	{
    	}
    };
    #endif
    #endif

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Defining derivated class problem
    By mikahell in forum C++ Programming
    Replies: 9
    Last Post: 08-22-2007, 02:46 PM
  2. Replies: 8
    Last Post: 10-02-2005, 12:27 AM
  3. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM
  4. gcc problem
    By bjdea1 in forum Linux Programming
    Replies: 13
    Last Post: 04-29-2002, 06:51 PM
  5. Difficulty superclassing EDIT window class
    By cDir in forum Windows Programming
    Replies: 7
    Last Post: 02-21-2002, 05:06 PM