Skip to main content

JNI Transparency - JFrame is transparent but compoments are not

No replies
jimig
Offline
Joined: 2008-11-04

I'm trying to use JNI to create a semi-transparent JFrame. The JFrame contains a JButton. The frame is transparent but the button is not. Also, when I drag the frame around, the button doesn't move with the frame. The same goes for JLabel. What's really confusing me is that is I use a Button instead of a JButton, it works fine. Before someone asks, let me say that I cannot use the translucent windows that were introduced in java 6u10.

Code:

package test;</p>
<p>import javax.swing.JFrame;<br />
import javax.swing.JButton;</p>
<p>public class MyFrame<br />
{</p>
<p>   /**<br />
    * @param args<br />
    */<br />
   public static void main( String[] args )<br />
   {<br />
      JFrame frame = new JFrame("My transparent window");<br />
      frame.setBounds( 10, 10, 200, 200 );</p>
<p>      JButton button = new JButton("My button");<br />
      button.setBounds( 20, 20, 50, 10 );<br />
      frame.add( button );</p>
<p>      //Display the window.<br />
      frame.setVisible(true);</p>
<p>      // Make the window partially transparent<br />
      Transparency trans = new Transparency();<br />
      trans.setWindowOpacity( frame, 0.5f );<br />
   }</p>
<p>}

package test;</p>
<p>import java.awt.Window;</p>
<p>public class Transparency<br />
{<br />
   static boolean libLoaded = false;<br />
   /**<br />
    * Sets the transparency of a component.<br />
    * @param opacity Transparency level, from 0.0 to 1.0.<br />
    * 1.0 is completely transparent. 0.0 is completely opaque.<br />
    * @return True if the transparency was set to the specified value.<br />
    *    False if an error occurred.<br />
    */<br />
   public static native boolean setTransparency( Window window, float opacity );</p>
<p>   static<br />
   {<br />
      try<br />
      {<br />
         System.loadLibrary("transJNI");<br />
         libLoaded = true;<br />
      }<br />
      catch ( Exception e )<br />
      {<br />
         e.printStackTrace();<br />
         libLoaded = false;<br />
      }<br />
   }</p>
<p>   /**<br />
    * @param window The window whose opacity will be adjusted.<br />
    * @param opacity The opacity level, from 0.0 (opaque) to 1.0 (completely transparent).<br />
    */<br />
   public void setWindowOpacity(Window window, float opacity)<br />
   {<br />
      if ( !libLoaded )<br />
      {<br />
         return;<br />
      }</p>
<p>      if ( !window.isVisible() )<br />
      {<br />
         return;<br />
      }</p>
<p>      setTransparency(window, opacity);</p>
<p>   }</p>
<p>}<br />

And here's the native code:

#include<br />
#include<br />
#include<br />
#include </p>
<p>// Don't mangle names for the JVM<br />
extern "C" {</p>
<p>BOOL APIENTRY DllMain( HMODULE hModule,<br />
                       DWORD  ul_reason_for_call,<br />
                       LPVOID lpReserved<br />
					 )<br />
{<br />
	switch (ul_reason_for_call)<br />
	{<br />
	case DLL_PROCESS_ATTACH:<br />
	case DLL_THREAD_ATTACH:<br />
	case DLL_THREAD_DETACH:<br />
	case DLL_PROCESS_DETACH:<br />
		break;<br />
	}<br />
    return TRUE;<br />
}</p>
<p>/**<br />
 * Gets the window handle for the Java window.<br />
 * Procedure for obtaining the handle:<br />
 *   1. Get the structure (JAWT) that contains the native methods.<br />
 *   2. Get the drawing surface (JAWT_DrawingSurface).<br />
 *   3. Using the drawing surface, get the drawing surface info (JAWT_DrawingSurfaceInfo).<br />
 *   4. Get the drawing info that's specific to Win32 (JAWT_Win32DrawingSurfaceInfo).<br />
 *   5. Using the drawing surface info, get the hwnd.<br />
 */<br />
HWND getHwnd( JNIEnv * env, jobject window )<br />
{<br />
   JAWT awt;<br />
   JAWT_DrawingSurface* ds;<br />
   JAWT_DrawingSurfaceInfo* dsi;<br />
   JAWT_Win32DrawingSurfaceInfo* dsi_win;<br />
   jint dsLock;<br />
   jboolean result = JNI_FALSE;</p>
<p>   // Get the AWT<br />
   awt.version = JAWT_VERSION_1_4;<br />
   result = JAWT_GetAWT(env, &awt);</p>
<p>   if ( result == JNI_FALSE )<br />
   {<br />
      printf( "%s:%i -  JAWT_GetAWT() failed.\n", __FILE__, __LINE__ );<br />
      return 0;<br />
   }</p>
<p>   // Get the drawing surface<br />
   ds = awt.GetDrawingSurface(env, window);</p>
<p>   if ( ds == NULL )<br />
   {<br />
      printf( "%s:%i -  GetDrawingSurface() failed.\n", __FILE__, __LINE__ );<br />
      return 0;<br />
   }</p>
<p>   dsLock = ds->Lock(ds);</p>
<p>   // Get the drawing surface info<br />
   dsi = ds->GetDrawingSurfaceInfo(ds);</p>
<p>   // Get the platform-specific drawing info<br />
   dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;</p>
<p>   HWND handle = dsi_win->hwnd;</p>
<p>   ds->FreeDrawingSurfaceInfo(dsi);<br />
   ds->Unlock(ds);<br />
   awt.FreeDrawingSurface(ds);</p>
<p>   return handle;<br />
}</p>
<p>void printLastError()<br />
{<br />
    LPTSTR pszMessage;<br />
    DWORD dwLastError = GetLastError(); </p>
<p>    FormatMessage(<br />
        FORMAT_MESSAGE_ALLOCATE_BUFFER |<br />
        FORMAT_MESSAGE_FROM_SYSTEM |<br />
        FORMAT_MESSAGE_IGNORE_INSERTS,<br />
        NULL,<br />
        dwLastError,<br />
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),<br />
        (LPTSTR)&pszMessage,<br />
        0, NULL );</p>
<p>    // Display the error message<br />
    wprintf(L"failed with error %d: %s\n", dwLastError, pszMessage);</p>
<p>    LocalFree(pszMessage);</p>
<p>}</p>
<p>/*<br />
 * Class:     test_Transparency<br />
 * Method:    setTransparency<br />
 * Signature: (Ljava/awt/Window;F)Z<br />
 */<br />
JNIEXPORT jboolean JNICALL Java_test_Transparency_setTransparency<br />
  (JNIEnv * env, jclass nothing, jobject window, jfloat alpha)<br />
{<br />
   jboolean success = JNI_FALSE;<br />
   HWND hwnd = getHwnd(env, window);</p>
<p>   if ( hwnd <= 0 )<br />
   {<br />
      printf("Error: Unable to get window handle.\n");<br />
      return JNI_FALSE;<br />
   }</p>
<p>   // Get the current window style<br />
   LONG currentStyle = GetWindowLong(hwnd, GWL_EXSTYLE);</p>
<p>   if ( currentStyle == 0 )<br />
   {<br />
      printf( "Error calling GetWindowLong() ");<br />
      printLastError();</p>
<p>   }</p>
<p>   if ( alpha == 0 )<br />
   {<br />
      // No transparency.<br />
      // Remove WS_EX_LAYERED from this window style<br />
      SetWindowLong(hwnd, GWL_EXSTYLE, currentStyle & ~WS_EX_LAYERED);<br />
   }<br />
   else<br />
   {<br />
      // Calculate the transparency value. Should be in the range 0-255<br />
      unsigned char transparency = (unsigned char)(255 * alpha);</p>
<p>      // Set window style to WS_EX_LAYERED. This is required for windows to be transparent.<br />
      SetWindowLong(hwnd, GWL_EXSTYLE, currentStyle | WS_EX_LAYERED );</p>
<p>      // set the transparency level<br />
      SetLayeredWindowAttributes(hwnd, 0, transparency, LWA_ALPHA);<br />
   }</p>
<p>   return JNI_TRUE;<br />
}

Thanks in advance!