使用JNI摆动透明度

时间:2008-11-05 16:01:47

标签: java java-native-interface transparency

我正在尝试创建一个显示包含JButton的框架的简单Java应用程序。我正在使用JNI为窗口添加透明度。窗口是透明的,但按钮不是。此外,当我移动窗口时,按钮不随窗口移动。 JLabel也会发生同样的事情。如果我使用Button而不是JButton它可以正常工作。

原生代码:

#include <windows.h>
#include <jawt_md.h>
#include <jawt.h>
#include <jni.h>

// Don't mangle names for the JVM
extern "C" {

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

/**
 * Gets the window handle for the Java window.
 * Procedure for obtaining the handle:
 *   1. Get the structure (JAWT) that contains the native methods. 
 *   2. Get the drawing surface (JAWT_DrawingSurface).
 *   3. Using the drawing surface, get the drawing surface info (JAWT_DrawingSurfaceInfo).
 *   4. Get the drawing info that's specific to Win32 (JAWT_Win32DrawingSurfaceInfo).
 *   5. Using the drawing surface info, get the hwnd.
 */
/*
 * Class:     test_Transparency
 * Method:    getWindowHandle
 * Signature: (Ljava/awt/Component;)J
 */
JNIEXPORT jlong JNICALL Java_test_Transparency_getWindowHandle
  (JNIEnv * env, jclass cls, jobject component)
{
   JAWT awt;
   JAWT_DrawingSurface* ds;
   JAWT_DrawingSurfaceInfo* dsi;
   JAWT_Win32DrawingSurfaceInfo* dsi_win;
   jint dsLock;
   jboolean result = JNI_FALSE;

   // Get the AWT
   awt.version = JAWT_VERSION_1_4;
   result = JAWT_GetAWT(env, &awt);


   if ( result == JNI_FALSE )
   {
      printf( "%s:%i -  JAWT_GetAWT() failed.\n", __FILE__, __LINE__ );
      return 0;
   }

   // Get the drawing surface
   ds = awt.GetDrawingSurface(env, component);

   if ( ds == NULL )
   {
      printf( "%s:%i -  GetDrawingSurface() failed.\n", __FILE__, __LINE__ );
      return 0;
   }

   dsLock = ds->Lock(ds);

   // Get the drawing surface info
   dsi = ds->GetDrawingSurfaceInfo(ds);


   // Get the platform-specific drawing info
   dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;


   HWND handle = dsi_win->hwnd;

   ds->FreeDrawingSurfaceInfo(dsi);
   ds->Unlock(ds);
   awt.FreeDrawingSurface(ds);

   return (jlong)handle;
}

void printLastError()
{
    LPTSTR pszMessage;
    DWORD dwLastError = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dwLastError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&pszMessage,
        0, NULL );

    // Display the error message
    wprintf(L"failed with error %d: %s\n", dwLastError, pszMessage);

    LocalFree(pszMessage);

}

/*
 * Class:     test_Transparency
 * Method:    setTransparency
 * Signature: (JF)V
 */
JNIEXPORT void JNICALL Java_test_Transparency_setTransparency
  (JNIEnv * env, jclass cls, jlong windowHandle, jfloat alpha)
{

   HWND hwnd = (HWND)windowHandle;

   // Get the current window style
   LONG currentStyle = GetWindowLong(hwnd, GWL_EXSTYLE);


   if ( currentStyle == 0 )
   {
      printf( "Error calling GetWindowLong() ");
      printLastError();

   }

   if ( alpha == 0 )
   {
      // No transparency.
      // Remove WS_EX_LAYERED from this window style
      SetWindowLong(hwnd, GWL_EXSTYLE, currentStyle & ~WS_EX_LAYERED);
   }
   else
   {
      // Calculate the transparency value. Should be in the range 0-255
      unsigned char transparency = (unsigned char)(255 * alpha);

      // Set window style to WS_EX_LAYERED. This is required for windows to be transparent.
      SetWindowLong(hwnd, GWL_EXSTYLE, currentStyle | WS_EX_LAYERED );

      // set the transparency level
      SetLayeredWindowAttributes(hwnd, 0, transparency, LWA_ALPHA);
   }
}


} // extern "C"

MyFrame.java

package test;

import javax.swing.*;
import javax.swing.SwingUtilities;
import java.awt.event.*;

public class MyFrame implements ActionListener
{
   private JFrame frame;
   private Transparency trans; // = new Transparency();
   private float t = 1.0f;

   public MyFrame()
   {
      frame = new JFrame("My transparent window");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setBounds( 10, 10, 200, 200 );

      JButton button = new JButton("My button");
      button.setBounds( 20, 20, 50, 10 );
      button.addActionListener( this );

      JPanel panel = new JPanel();
      panel.add( button );

      frame.setContentPane( panel );

      //Display the window.
      frame.setVisible(true);

      trans = new Transparency();
   }


   /**
    * @param args
    */
   public static void main( String[] args )
   {
      MyFrame f = new MyFrame();
   }

   public void actionPerformed(ActionEvent e)
   {
      t -= 0.05f;
      trans.setWindowOpacity( frame, t );
   }

}

Transparency.java

package test;

import java.awt.Window;
import java.awt.Component;

public class Transparency
{
   static boolean libLoaded = false;
   /**
    * Sets the transparency for a window.
    * @param hwnd Handle for the window.
    * @param opacity Transparency level, from 0.0 to 1.0.
    * 1.0 is completely transparent. 0.0 is completely opaque.
    */
   private static native void setTransparency( long hwnd, float opacity );

   /**
    * Get the window handle for the component.
    * @param component
    * @return HWND value obtained from the OS.
    */
   private static native long getWindowHandle( Component component );

   static
   {
      try
      {
         System.loadLibrary("transJNI");
         libLoaded = true;
      }
      catch ( Exception e )
      {
         e.printStackTrace();
         libLoaded = false;
      }
   }

   /**
    * @param window The window whose opacity will be adjusted.
    * @param opacity The opacity level, from 0.0 (opaque) to 1.0 (completely transparent).
    */
   public void setWindowOpacity(Window window, float opacity)
   {
      if ( !libLoaded )
      {
         return;
      }

      if ( !window.isVisible() )
      {
         return;
      }
      long hwnd = getWindowHandle( window );
      setTransparency(hwnd, opacity);

   }

}

4 个答案:

答案 0 :(得分:2)

6u10通过非官方API支持transparent windows。 6u10可通过java.com下载,之前的JDK版本将更新或稍后更新。

答案 1 :(得分:0)

JNA可能会取得更大成功,尤其是Window utils

答案 2 :(得分:0)

Team Dev's Winpack.

试一试。看起来很有趣。

答案 3 :(得分:0)

SwingX有许多透明的功能,我不是100%确定它会满足您的需求,但试一试! swinglabs.org