Click here to Skip to main content
6,630,289 members and growing! (20,533 online)
Email Password   helpLost your password?
Languages » Java » General     Advanced

Add Mouse Wheel support to Swing Widgets

By Davanum Srinivas

This article shows how to add support for Mouse Wheel for Java Swing Widgets
Java, Java, Dev
Posted:9 Jun 2000
Updated:2 Jul 2000
Views:119,438
Bookmarked:17 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
61 votes for this article.
Popularity: 7.73 Rating: 4.33 out of 5
2 votes, 15.4%
1
1 vote, 7.7%
2
1 vote, 7.7%
3
3 votes, 23.1%
4
6 votes, 46.2%
5
  • Download source files - 14 Kb

    Introduction

    There are at least five Request for Enhancement's (RFE) in the JavaSoft bug database related to Mouse Wheel support in Java. One of the RFE's BugID #4202656 has 281 votes from developers requesting Sun for a fix. Sun has finally agreed to support this feature in JDK 1.4 codenamed Merlin accroding to the BugID #4289845 in its bug database.

    This article is intended for those who don't want to wait till then or cannot move to a new JDK whenever Sun releases them. It shows how you can add support for Mouse Wheel with a little JNI code.

    Searching for a solution

    The first step was to develop a sample where this functionality can be tested. A sample from http://java.sun.com/docs/books/tutorial/uiswing/components/scrollpane.html#update looked ideal with a few modifications. The screenshot of this sample is shown below.

    Sample Image - mousewheel.gif

    The next step was to use Spy++ to find out which window was actually getting WM_MOUSEWHEEL message and see if the message can be trapped. Spy++ showed only one Heavy weight window as all the Swing controls are light-weight implementations that share the DC of the parent frame. Also the Messages window confirmed that mouse wheel messages on any child Swing control was sent to this parent frame window. See the screen show which shows the window hierarchy and the messages.

    Sample Image - spy.gif

    Game Plan

    Given the information above, implementation was kind of straight forward. To enable mouse wheel scrolling in a Swing widget, the WM_MOUSEWHEEL messages have to intercepted in the parent frame and somehow posted to the widget. Here's a simple plan to do this.

    • Step 1: Get the HWND of the parent JFrameEx.
    • Step 2: Subclass the HWND using SetWindowLong(hwnd, GWL_WNDPROC,(LONG)FrameWindowProc);
    • Step 3: When FrameWindowProc is called with a WM_MOUSEWHEEL, notify the java JFrameEx object.
    • Step 4: In the JFrameEx's notifyMouseWheel function, figure out which scrollpane should receive the message and call the setValue of it's vertical scrollbar
    Step 1: This was easy using an FAQ on jguru. Here's the code snippet from JFrameEx.java
        // Returns the HWND for canvas. 
    
    	// This is undocumented, but works on JDK1.1.8, JDK1.2.2 and JDK1.3 
    
        public int getHWND() 
        {
            DrawingSurfaceInfo drawingSurfaceInfo;
            Win32DrawingSurface win32DrawingSurface;
            int hwnd = 0;
         
            // Get the drawing surface 
    
            drawingSurfaceInfo =
                ((DrawingSurface)(getPeer())).getDrawingSurfaceInfo();
            
            if (null != drawingSurfaceInfo) {
                drawingSurfaceInfo.lock();
                // Get the Win32 specific information 
    
                win32DrawingSurface = 
                     (Win32DrawingSurface)drawingSurfaceInfo.getSurface();
                hwnd = win32DrawingSurface.getHWnd();
                drawingSurfaceInfo.unlock();
            }
            return hwnd;
        }
    

    Step 2: Create a native entry point (using JNI) where we can call SetWindowLong. Here's the code snippet from MouseWheel.CPP.

    // JNI native entry point for subclassing the window
    
    JNIEXPORT void JNICALL Java_JFrameEx_setHook
      (JNIEnv *pEnv, jobject f, jint hwnd)
    {
    	// ensure that the java object can be called from any thread.
    
    	jobject frame = pEnv->NewGlobalRef(f);
    
    	WNDPROC oldProc = (WNDPROC)::SetWindowLong((HWND)hwnd, GWL_WNDPROC, (LONG)FrameWindowProc);
    
    	// store the java object
    
    	setFrame((HWND)hwnd, frame);
    	// store the old window proc
    
    	setProc ((HWND)hwnd, oldProc);
    }
    

    Step 3: Here's the code snippet from MouseWheel.CPP which deals with the WM_MOUSEWHEEL message.

    // Window Proc for subclassing.
    
    LRESULT CALLBACK FrameWindowProc(
      HWND hwnd,      // handle to window
    
      UINT uMsg,      // message identifier
    
      WPARAM wParam,  // first message parameter
    
      LPARAM lParam   // second message parameter
    
    )
    {
    	// Get the WindowProc for this window.
    
    	WNDPROC oldProc = getProc((HWND)hwnd);
    
    	// When we get a mouse wheel message
    
    	if(uMsg == WM_MOUSEWHEEL)
    	{
    		MSG *pMsg = new MSG;
    		pMsg->hwnd = hwnd;
    		pMsg->message = uMsg;
    		pMsg->wParam = wParam;
    		pMsg->lParam = lParam;
    
    		// send it to the java code from a new thread.
    
    		_beginthread(StartNotifyThread, 0, pMsg);
    		return 0;
    	}
    	return ::CallWindowProc(oldProc, hwnd, uMsg, wParam, lParam);
    }
    
    // Helper Thread for notification.
    
    void WINAPIV StartNotifyThread(LPVOID lpVoid)
    {
    	MSG *pMsg = (MSG *)lpVoid;
    
    	// This is the java object that needs to be notified.
    
    	jobject frame = getFrame(pMsg->hwnd);
    
    	// extract info from the wparam and lparam.
    
    	WPARAM fwKeys = LOWORD(pMsg->wParam);
    	short zDelta  = HIWORD(pMsg->wParam);
    
    	LPARAM xPos = GET_X_LPARAM(pMsg->lParam); 
    	LPARAM yPos = GET_Y_LPARAM(pMsg->lParam); 
    
    	// call the helper function.
    
    	notifyMouseWheel(frame,fwKeys,zDelta,xPos,yPos);
    
    	delete pMsg;
    }
    
    // This helper is the one that actually invokes the java JFrameEx's notifyMouseWheel method
    
    void notifyMouseWheel(jobject frame,short fwKeys,short zDelta,long xPos, long yPos)
    {
    	HMODULE hMod	= NULL;
    	JavaVM *vmBuf	= NULL;
    	JNIEnv *pEnv	= NULL;
    	jsize bufLen	= 1;
    	jint nVMs		= 0;
    
    	// Get the Java VM.
    
    	pJNI_GetCreatedJavaVMs pFunc = getJavaVM();
    	jint nRet = (*pFunc)(&vmBuf,bufLen,&nVMs);
    
    	// Attach this thread.
    
    	vmBuf->AttachCurrentThread((void **)&pEnv,NULL);
    
    	// Inform the java object that the child has been created.
    
    	jclass cls = pEnv->GetObjectClass(frame);
    	jmethodID mid = pEnv->GetMethodID(cls, "notifyMouseWheel", "(SSJJ)V");
    	if (mid == 0)
    		return;
    	pEnv->CallVoidMethod(frame, mid, (jshort)fwKeys, (jshort)zDelta, (jlong)xPos, (jlong)yPos);
    
    	// Detach this thread.
    
    	vmBuf->DetachCurrentThread();
    }
    

    Step 4: Here's the code snippet from JFrameEx.java which is called from the previous step. The only trick here is that we need to get the scrollpane of the widget. From the documentation of JScrollPane we see that we have to call widget.getParent().getParent() to get the widget's scrollpane.

    // this is the function which serves as a call back when 
    
    	// a mouse wheel movement is detected.
    
    	public void notifyMouseWheel(short fwKeys,short zDelta,long xPos, long yPos)
    	{
    		// Convert screen coordinates to component specific offsets.
    
    		Point p = new Point((int)xPos,(int)yPos);
    		SwingUtilities.convertPointFromScreen(p,this);
    
    		// Find the embedded Swing component which should receive the scroll messages
    
    		Component c = SwingUtilities.getDeepestComponentAt(this, p.x, p.y);
    		try
    		{
    			// Get the scroll pane for the widget.
    
    			JScrollPane scrollPane = (JScrollPane) c.getParent().getParent();
    
    			// Get the vertical scrollbar for the scroll pane.
    
    			JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
    
    			// Get the current value and set the new value depending on 
    
    			// the direction of the mouse wheel.
    
    			int nValue = scrollBar.getValue();
    			nValue = nValue + ((zDelta > 0) ? 5 : -5);
    			scrollBar.setValue(nValue);
    		} catch (Exception e){
    			// Ignore exceptions.
    
    		}
    	}
    

    That's it folks.

    Notes

    • There is a Build.bat in the zip file which can be use to build the sources. please edit this file to set the location of your VC++ and JDK 1.2.2 directories
    • To run the code use "java ScrollDemo2"
  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    About the Author

    Davanum Srinivas


    Member

    Location: United States United States

    Other popular Java articles:

    Article Top
    You must Sign In to use this message board.
    FAQ FAQ 
     
    Noise Tolerance  Layout  Per page   
     Msgs 1 to 15 of 15 (Total in Forum: 15) (Refresh)FirstPrevNext
    GeneralDrawingSurfaceInfo error Pinmembernereidahoxhaj6:16 27 Feb '04  
    GeneralRe: DrawingSurfaceInfo error PinmemberDeepakRamaswamy7:02 29 Mar '04  
    GeneralRe: DrawingSurfaceInfo error Pinmembersabit5:46 4 May '04  
    GeneralMouse Wheel (middle button) on Linux/Unix PinmemberAnup Engineer4:07 20 Feb '02  
    Generalcs1.keyboard lib. in java Pinmembervi8:15 25 Nov '01  
    GeneralRe: cs1.keyboard lib. in java PinsussAnonymous13:22 7 Jun '04  
    GeneralRe: cs1.keyboard lib. in java PinsussAnonymous14:31 19 Oct '05  
    Generaljava swing Pinmemberadmie4:46 17 Aug '01  
    GeneralRe: java swing PinmemberAnonymous13:25 8 Nov '01  
    GeneralRe: java swing PinmemberAnonymous4:36 3 Apr '02  
    GeneralCode Maintained on SourceForge PinmemberAnonymous2:07 10 Aug '01  
    GeneralGL problems Pinmembersoqw0:27 9 Jan '01  
    GeneralLinux & Wheel Mouse PinmemberAnonymous6:37 16 Dec '00  
    GeneralJava Applets & Mouse Wheel Pinsussbike8:55 14 Jun '00  
    GeneralRe: Java Applets & Mouse Wheel PinmemberAnonymous6:50 13 Jul '01  

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

    PermaLink | Privacy | Terms of Use
    Last Updated: 2 Jul 2000
    Editor: Chris Maunder
    Copyright 2000 by Davanum Srinivas
    Everything else Copyright © CodeProject, 1999-2009
    Web22 | Advertise on the Code Project