如何防止JFrame在任务栏中弹出警报效果

3
我是一名Java SE开发人员,我们的程序仅在Windows操作系统上运行,该程序需要打开文件并在UI中显示文件内容,我们在JInternalFrame中显示文件内容,并且在文件打开时始终使用setselected(true)
最近,由于一个重大错误,我们将程序从JRE1.6.0_41更新到JRE1.8.0_144,并注意到在JRE1.8.0_144中,当我们的程序(JFrame)没有焦点并在JFrame中调用setselected(true)时,JFrame会在任务栏中闪烁,而在JRE1.6.0_41中则不会。一些客户认为这很烦人,因为他们经常需要打开文件。
所以问题是:
(1)我能关闭这个功能吗?
(2)如果不能关闭,是否有另一种方法可以避免闪烁效果,同时我仍然可以在JInternalFrame上使用setSelected()
如果我没有解释清楚,这里是演示警报效果的示例代码,请运行程序并切换到其他窗口,然后它应该会闪烁。我已经在Windows 7、Windows 8.1和Windows 10上进行了测试,它们都有相同的警报效果。
import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import java.awt.*;

/*
 * Copy and modified by Oracle sample code "InternalFrameDemo.java"
 */
public class Login extends JFrame {
    JDesktopPane desktop;
    private int m_iFrameCounter = 0;

    public Login() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        createFrame(); //create first "window"
        setContentPane(desktop);

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);

        // Add new frame every second
        Thread addFrameThread = new Thread() {

            @Override
            public void run() {
                while(true) {
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            createFrame();
                        }
                    });
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        addFrameThread.start();
    }

    //Create a new internal frame.
    protected void createFrame() {
        JInternalFrame frame = new JInternalFrame();
        frame.setTitle("" + m_iFrameCounter);
        frame.setSize(100, 100);
        frame.setLocation(0, 0);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);
        frame.moveToFront();
        try {
            frame.setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}
        m_iFrameCounter++;
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        Login frame = new Login();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

更新 01

这是更新代码,根据@camickr的建议添加了KeyboardFocusManagerWindowListener,只有在JFrame获得焦点或JFrame拥有焦点时才对JInternalFrame执行setselected(true),但如果您频繁切换窗口,则仍会出现警报。我认为这是因为在setselected(true)在JInternalFrame之前,JFrame失去了焦点。也许有一种方法可以改进代码?

import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyVetoException;

/*
 * Copy and modified by Oracle sample code "InternalFrameDemo.java"
 */
public class Login extends JFrame {
    JDesktopPane desktop;
    private int m_iFrameCounter = 0;
    private JInternalFrame m_InternalFrameWaitSelected = null;

    public Login() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        createFrame(); //create first "window"
        setContentPane(desktop);

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);

        /*********************************************  update codes *********************************************/ 
        //Add window listener to set last JInternalframe selected when JFrame activated
        this.addWindowListener(new WindowListener() {

            @Override
            public void windowOpened(WindowEvent e) {
            }

            @Override
            public void windowClosing(WindowEvent e) {
            }

            @Override
            public void windowClosed(WindowEvent e) {
            }

            @Override
            public void windowIconified(WindowEvent e) {
            }

            @Override
            public void windowDeiconified(WindowEvent e) {
            }

            @Override
            public void windowActivated(WindowEvent e) {
                if (m_InternalFrameWaitSelected != null) {
                    try {
                        m_InternalFrameWaitSelected.setSelected(true);
                    } catch (PropertyVetoException e1) {
                        e1.printStackTrace();
                    }
                    m_InternalFrameWaitSelected = null;
                }
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
            }

        });
        /*********************************************  update codes *********************************************/

        // Add new frame every 50 millisecond
        Thread addFrameThread = new Thread() {

            @Override
            public void run() {
                while(true) {
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            createFrame();
                        }
                    });
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        addFrameThread.start();
    }

    //Create a new internal frame.
    protected void createFrame() {
        JInternalFrame frame = new JInternalFrame();
        frame.setTitle("" + m_iFrameCounter);
        frame.setSize(100, 100);
        frame.setLocation(0, 0);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);
        frame.moveToFront();
        /*********************************************  update codes *********************************************/
        // Only setselect(true) when JFrame is focus owner
        if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != null &&
                SwingUtilities.isDescendingFrom(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(), this)) {
            try {
                frame.setSelected(true);
            } catch (java.beans.PropertyVetoException e) {}
        } else {
            m_InternalFrameWaitSelected = frame;
        }
        /*********************************************  update codes *********************************************/
        m_iFrameCounter++;
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        Login frame = new Login();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

更新02

尝试使用getGlobalActiveWindow()windowActivated/windowDeactivated,但如果频繁切换窗口,警报仍然会出现。以下是测试代码:

getGlobalActiveWindow()

import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyVetoException;

/*
 * Copy and modified by Oracle sample code "InternalFrameDemo.java"
 */
public class Login extends JFrame {
    JDesktopPane desktop;
    private int m_iFrameCounter = 0;
    private JInternalFrame m_InternalFrameWaitSelected = null;
    /*********************************************  update codes *********************************************/ 
    private MyDefaultKeyboardFocusManager m_MyKeyboardFocusManager = new MyDefaultKeyboardFocusManager();

    public class MyDefaultKeyboardFocusManager extends DefaultKeyboardFocusManager {

        //The method is protected, need to add public method to call it
        public Window myGetGlobalActiveWindow() {
            return this.getGlobalActiveWindow();
        }

    }
    /*********************************************  update codes *********************************************/ 

    public Login() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        setContentPane(desktop);

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);

        /*********************************************  update codes *********************************************/ 
        KeyboardFocusManager.setCurrentKeyboardFocusManager(m_MyKeyboardFocusManager);
        /*********************************************  update codes *********************************************/

        //Add window listener to set last JInternalframe selected when JFrame activated
        this.addWindowListener(new WindowListener() {

            @Override
            public void windowOpened(WindowEvent e) {
            }

            @Override
            public void windowClosing(WindowEvent e) {
            }

            @Override
            public void windowClosed(WindowEvent e) {
            }

            @Override
            public void windowIconified(WindowEvent e) {
            }

            @Override
            public void windowDeiconified(WindowEvent e) {
            }

            @Override
            public void windowActivated(WindowEvent e) {
                if (m_InternalFrameWaitSelected != null) {
                    try {
                        m_InternalFrameWaitSelected.setSelected(true);
                    } catch (PropertyVetoException e1) {
                        e1.printStackTrace();
                    }
                    m_InternalFrameWaitSelected = null;
                }
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
            }

        });

        // Add new frame every 50 millisecond
        Thread addFrameThread = new Thread() {

            @Override
            public void run() {
                while(true) {
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            createFrame();
                        }
                    });
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        addFrameThread.start();
    }

    //Create a new internal frame.
    protected void createFrame() {
        JInternalFrame frame = new JInternalFrame();
        frame.setTitle("" + m_iFrameCounter);
        frame.setSize(100, 100);
        frame.setLocation(0, 0);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);
        frame.moveToFront();
        /*********************************************  update codes *********************************************/
        // Only setselect(true) when JFrame is active
        if (m_MyKeyboardFocusManager.myGetGlobalActiveWindow() == this) {
            try {
                frame.setSelected(true);
            } catch (java.beans.PropertyVetoException e) {}
        } else {
            m_InternalFrameWaitSelected = frame;
        }
        /*********************************************  update codes *********************************************/
        m_iFrameCounter++;
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        Login frame = new Login();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

windowActivated/windowDeactivated

import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyVetoException;

/*
 * Copy and modified by Oracle sample code "InternalFrameDemo.java"
 */
public class Login extends JFrame {
    JDesktopPane desktop;
    private int m_iFrameCounter = 0;
    private JInternalFrame m_InternalFrameWaitSelected = null;
    /*********************************************  update codes *********************************************/ 
    private boolean m_bIsFrameActive = false;
    /*********************************************  update codes *********************************************/ 

    public Login() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        setContentPane(desktop);

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);

        /*********************************************  update codes *********************************************/ 
        //Add window listener to set last JInternalframe selected when JFrame activated
        this.addWindowListener(new WindowListener() {

            @Override
            public void windowOpened(WindowEvent e) {
            }

            @Override
            public void windowClosing(WindowEvent e) {
            }

            @Override
            public void windowClosed(WindowEvent e) {
            }

            @Override
            public void windowIconified(WindowEvent e) {
            }

            @Override
            public void windowDeiconified(WindowEvent e) {
            }

            @Override
            public void windowActivated(WindowEvent e) {
                m_bIsFrameActive = true;
                if (m_InternalFrameWaitSelected != null) {
                    try {
                        m_InternalFrameWaitSelected.setSelected(true);
                    } catch (PropertyVetoException e1) {
                        e1.printStackTrace();
                    }
                    m_InternalFrameWaitSelected = null;
                }
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                m_bIsFrameActive = false;
            }

        });
        /*********************************************  update codes *********************************************/

        // Add new frame every 50 millisecond
        Thread addFrameThread = new Thread() {

            @Override
            public void run() {
                while(true) {
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            createFrame();
                        }
                    });
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        addFrameThread.start();
    }

    //Create a new internal frame.
    protected void createFrame() {
        JInternalFrame frame = new JInternalFrame();
        frame.setTitle("" + m_iFrameCounter);
        frame.setSize(100, 100);
        frame.setLocation(0, 0);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);
        frame.moveToFront();
        /*********************************************  update codes *********************************************/
        // Only setselect(true) when JFrame is active
        if (m_bIsFrameActive) {
            try {
                frame.setSelected(true);
            } catch (java.beans.PropertyVetoException e) {}
        } else {
            m_InternalFrameWaitSelected = frame;
        }
        /*********************************************  update codes *********************************************/
        m_iFrameCounter++;
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        Login frame = new Login();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

欢迎来到SO。如果没有任务栏图标是一个选项,那么请使用JDialog而不是JFrame。(我在问题中添加了Swing标签,所以很可能你会从SO上的Swing大师那里获得更好的选项。) - c0der
我认为这是Windows提供的很酷的功能。每当窗口框架改变状态时,它会闪烁以通知用户。然而,一旦您打开了窗口,它就会停止闪烁。您为什么想关闭此功能? - Shahid
@Shahid 因为我们的一些客户需要同时打开很多文件,在打开文件时他们会做其他事情,这会导致我们的程序失去焦点,然后我们的程序会不停地闪烁,让我们的客户感到很烦。 - exister
2个回答

1
如果有人对答案感兴趣,我在追踪JInternalFrame的源代码后发现,当调用setSelected(true)时,闪烁效果是由requestFocus()引起的,因此我决定继承JInternalFrame并将requestFocus()替换为requestFocusInWindow(),现在闪烁效果已经消失。
以下是我解决问题的最终方案:
import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;

import sun.swing.SwingUtilities2;

import javax.swing.InternalFrameFocusTraversalPolicy;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyVetoException;

/*
 * Copy and modified by Oracle sample code "InternalFrameDemo.java"
 */
public class Login extends JFrame {
    JDesktopPane desktop;
    private int m_iFrameCounter = 0;

    /**
     * This class is created to handle problem that program would blink in taskbar 
     * when call setSelected(true) on JInternalFrame base on JRE1.8.0_144, the only different content is
     * use lastFocusOwner.requestFocusInWindow(); instead of lastFocusOwner.requestFocus(); 
     * in method restoreSubcomponentFocus() 
     *
     */
    public class MyInternalFrame extends JInternalFrame {

        private Component lastFocusOwner;
        private final String BASE_JRE_VERSION = "1.8.0_144";

        public MyInternalFrame() {
            _checkJavaVersion();
        }

        public MyInternalFrame(String title) {
            super(title);
            _checkJavaVersion();
        }

        public MyInternalFrame(String title, boolean resizable) {
            super(title, resizable);
            _checkJavaVersion();
        }

        public MyInternalFrame(String title, boolean resizable, boolean closable) {
            super(title, resizable, closable);
            _checkJavaVersion();
        }

        public MyInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable) {
            super(title, resizable, closable, maximizable);
            _checkJavaVersion();
        }

        public MyInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) {
            super(title, resizable, closable, maximizable, iconifiable);
            _checkJavaVersion();
        }

        private void _checkJavaVersion() {
            if (!BASE_JRE_VERSION.equals(System.getProperty("java.version")))
                System.err.println(String.format("%s is not compatible with current Java runtime version : %s ", this.getClass().toString(), System.getProperty("java.version")));
        }

        @Override
        public void restoreSubcomponentFocus() {
            if (isIcon()) {
                SwingUtilities2.compositeRequestFocus(getDesktopIcon());
            }
            else {
                Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
                if ((component == null) || !SwingUtilities.isDescendingFrom(component, this)) {
                    // FocusPropertyChangeListener will eventually update
                    // lastFocusOwner. As focus requests are asynchronous
                    // lastFocusOwner may be accessed before it has been correctly
                    // updated. To avoid any problems, lastFocusOwner is immediately
                    // set, assuming the request will succeed.
                    setLastFocusOwner(getMostRecentFocusOwner());
                    if (lastFocusOwner == null) {
                        // Make sure focus is restored somewhere, so that
                        // we don't leave a focused component in another frame while
                        // this frame is selected.
                        setLastFocusOwner(getContentPane());
                    }
                    lastFocusOwner.requestFocusInWindow();
                }
            }
        }

        private void setLastFocusOwner(Component component) {
            lastFocusOwner = component;
        }

        @Override
        public Component getMostRecentFocusOwner() {
            if (isSelected()) {
                return getFocusOwner();
            }

            if (lastFocusOwner != null) {
                return lastFocusOwner;
            }

            FocusTraversalPolicy policy = getFocusTraversalPolicy();
            if (policy instanceof InternalFrameFocusTraversalPolicy) {
                return ((InternalFrameFocusTraversalPolicy)policy).
                    getInitialComponent(this);
            }

            Component toFocus = policy.getDefaultComponent(this);
            if (toFocus != null) {
                return toFocus;
            }
            return getContentPane();
        }

        @Override
        public Component getFocusOwner() {
            if (isSelected()) {
                return lastFocusOwner;
            }
            return null;
        }
    }

    public Login() {
        super("InternalFrameDemo");

        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 50;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width  - inset*2,
                  screenSize.height - inset*2);

        //Set up the GUI.
        desktop = new JDesktopPane(); //a specialized layered pane
        setContentPane(desktop);

        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);

        // Add new frame every 50 millisecond
        Thread addFrameThread = new Thread() {

            @Override
            public void run() {
                while(true) {
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            createFrame();
                        }
                    });
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        addFrameThread.start();
    }

    //Create a new internal frame.
    protected void createFrame() {
        JInternalFrame frame = new MyInternalFrame();
        frame.setTitle("" + m_iFrameCounter);
        frame.setSize(100, 100);
        frame.setLocation(0, 0);
        frame.setVisible(true); //necessary as of 1.3
        desktop.add(frame);
        frame.moveToFront();
        try {
            frame.setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}
        m_iFrameCounter++;
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        Login frame = new Login();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

1
我们在JInternalFrame中显示文件内容,并且在打开文件时始终设置为selected(true)。不知道如何停止任务栏上的闪烁,但是您可以通过不自动调用setSelected()来更改行为。例如,您可以:1.仅在框架为活动窗口时调用setSelected()。您可以使用KeyboardFocusManager检查窗口是否聚焦。2.将WindowListener添加到框架中,并处理windowActivated事件以在最近打开的内部框架上调用setSelected()方法。
编辑:运行程序并将其最小化到任务栏,首先我想澄清的是,如果我将框架最小化到任务栏,则图标闪烁没有问题。只有当我单击另一个应用程序并且登录框架失去焦点而仍然处于打开状态时,图标才会闪烁。
引用:“如果您经常切换窗口,则警报仍会发生。”
我将您的代码更改为:
//if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != null &&
//    SwingUtilities.isDescendingFrom(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(), this)) {
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow() == this)
{
    try
    {
        System.out.println("active");
        frame.setSelected(true);
    }
    catch (java.beans.PropertyVetoException e) {}
}
else
{
    System.out.println("not");
//  frame = m_InternalFrameWaitSelected;
    m_InternalFrameWaitSelected = frame;
}

我注意到有时候即使在另一个窗口中玩游戏,“active”也会被显示出来。所以由于某种原因,KeyboardFocusManager返回了一个不正确的值(或者我不理解该方法应该如何工作?)
因此,也许您可以尝试使用getGlobalActiveWindow()方法,看看是否有任何区别。
如果没有,那么我的下一个建议是忘记KeyboardFocusManager,管理一个布尔变量,指示您的框架是否处于活动状态。因此,您会在windowActivated中将变量设置为true,在windowDeactivated中将其设置为false。然后在创建框架时测试此变量。
还请注意我如何更改以下代码:
//  frame = m_InternalFrameWaitSelected;
    m_InternalFrameWaitSelected = frame;

感谢您的建议,我已经将 KeyboardFocusManagerWindowListener 添加到我的代码中,请查看我的更新。 - exister
谢谢,frame = m_InternalFrameWaitSelected; 是一个愚蠢的错误,我已经纠正了它。我添加了 getGlobalActiveWindow()windowActivated/windowDeactivated 的测试代码,请查看我的更新。 - exister
@exister,我刚刚注意到,JFrame有一个isActive()方法。也许这比使用KeyboardFocusManager更好。如果仍然有问题,那我就无计可施了。我的建议中的关键概念是知道框架何时处于活动状态,何时不是。如果这里提供的方法或窗口侦听器不能为您提供Window的正确状态,那似乎是Java的问题,我不知道还能建议什么。 - camickr
尝试使用JFrame的isActive()方法,但仍然无法正常工作,不管怎样,很高兴有你的帮助,谢谢。 - exister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接