Эффект перехода JFrame - при вызове setState(Frame.ICONIFIED) он просто переходит на панель задач без анимации

У меня сейчас проблема - когда я звоню frame.setState(Frame.ICONIFIED) с моей пользовательской кнопкой (я не использую стандартную кнопку свертывания JFrame - JFrame установлен в setUndecorated(true)), JFrame просто переходит на панель задач без какой-либо анимации. В обычной ситуации он должен постепенно переходить на панель задач, минимизируя себя. Но если я нажимаю иконку JFrame на панели задач, она восстанавливается с анимацией до нормального размера. Ситуация на Windows XP, не тестировалась на других системах, но я полагаю, что она будет вести себя так же.

3 ответа

Решение

Если то, что вы говорите, верно, и ваши неокрашенные окна действительно анимируются при нажатии значков на панели задач. Затем вы можете запустить то же действие в своем коде, используя JNA.

Чтобы это решение работало, вам нужно включить jna.jar и jna-platform.jar в ваш путь к классам.

Это не учебник JNA, их много. Это просто код, который использует JNA для вызова функций user32.dll CloseWindow и OpenIcon; Это те функции, которые Windows вызывает, когда вы щелкаете значок на панели задач приложения (правда, я не уверен, что это реальные функции, но они реагируют одинаково).

import java.awt.Component;
import java.awt.Window;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.HWND;

public class IconifyUtilityClass
{
    public static void minimize(Window window)
    {
        HWND hWnd = getHWND(window);
        User32dll.INSTANCE.CloseWindow(hWnd); //call CloseWindow with this windows handle
    }

    public static void restore(Window window)
    {
        HWND hWnd = getHWND(window);
        User32dll.INSTANCE.OpenIcon(hWnd); //call OpenIcon with this windows handle
    }

    private interface User32dll extends Library
    {
        User32dll INSTANCE = (User32dll) Native.loadLibrary("user32.dll", User32dll.class);
        boolean OpenIcon(HWND hWnd);
        boolean CloseWindow(HWND hWnd);
    }

    private static HWND getHWND(Component comp)
    {
        return new HWND(Native.getComponentPointer(comp));
    }
}

Чтобы вызвать код, просто введите свой фрейм или диалог

JFrame frame = new JFrame();
...
IconifyUtilityClass.minimize(frame); //minimize your frame
...
IconifyUtilityClass.restore(frame); //restore your frame

Стоит отметить, что в Windows 7 недекорированные кадры вообще не анимируются (даже с помощью функции user32.dll AnimateWindow). Так что, если ваша цель состоит в том, чтобы анимировать ваши кадры в любом месте, вы правы, вам придется сделать это самостоятельно. JavaFx имеет несколько действительно хороших анимационных вещей, которые помогут с этим.

Поскольку вы хотите, чтобы он был независимым от платформы, другой мой ответ не сработает для вас. Кроме того, каждая платформа будет реагировать по-разному, когда вы минимизируете или скрываете окно. Вы упомянули, что было бы неплохо увидеть фрагмент кода Java, который даст вам последовательную анимацию. Вот код для вас.

import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;

public class FadeUtilityClass
{
    private static final int TIME = 200;
    private static final int MILLIS_PER_FRAME = 33;
    private static final float DELTA = MILLIS_PER_FRAME / (float)TIME; //how much the opacity will change on each tick

    /**
     * @param frame the frame to fade in or out
     * @param in true if you are fading in, false if you're fading out
     */
    public static void fade(final JFrame frame, final boolean in)
    {
        frame.setOpacity(in ? 0f : 1f); //if we're fading in, make sure our opacity is 0, and 1 if we're fading out
        if (in) //set the state back to normal because we might have been minimized
            frame.setState(JFrame.NORMAL); 
        final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask()
        {
            float opacity = in ? 0f : 1f;
            float delta = in ? DELTA : -DELTA;

            @Override
            public void run()
            {
                opacity += delta; //tweak the opacity
                if (opacity < 0) //we're invisible now
                {
                    frame.setState(JFrame.ICONIFIED); //hide frame
                    frame.setOpacity(1f); //then make it opaque again, so it'll reappear properly if they click the taskbar 
                    timer.cancel(); //stop the timer
                }
                else if (opacity > 1) //we're fully visible now
                {
                    frame.setOpacity(1f); //make the opacity an even 1.0f
                    timer.cancel(); //stop the timer
                }
                else
                    frame.setOpacity(opacity);
            }
        };
        timer.scheduleAtFixedRate(timerTask, MILLIS_PER_FRAME, MILLIS_PER_FRAME);
    }
}

Это служебный класс, который заставит вашу неокрашенную рамку исчезать или исчезать. Поскольку расположение панели задач и свернутого окна меняется в зависимости от платформы, и вам нужно будет использовать API-интерфейсы для конкретной платформы, чтобы найти это, я просто заставил анимацию затухать в окне, не уменьшая его до уровня панели задач.

Надеюсь это поможет!

Позвонив

myJFrame.setUndecorated( true )

Вы отключаете любые рамки для вашего JFrame. Это включает в себя анимацию по максимизации и минимизации вашего JFrame.

Если вы пропустите этот вызов или измените его на

myJFrame.setUndecorated( false )

тогда анимации снова будут видны, даже если свернуть кадр с вызовом

myJFrame.setState( Frame.ICONIFIED );

AFAIK, нет способа оживить неокрашенную рамку.:(

Пожалуйста, найдите мой полный пример кода здесь:

    JFrame frame = new JFrame();
    frame.setSize( 800, 600 );
    frame.setUndecorated( false );  // will enable animations
    frame.setVisible( true );
    try { Thread.sleep( 3000 ); } catch ( Throwable t ) {}
    frame.setState( Frame.ICONIFIED );

Привет

Кристофер

Другие вопросы по тегам