Я разработчик Java SE, и наша программа работает только на ОС Windows, программе нужно открывать файлы и отображать в пользовательском интерфейсе, мы отображаем содержимое файла в JInternalFrame и всегда setselected(true)
при открытии файла.
Недавно мы обновили нашу программу с JRE1.6.0_41
до JRE1.8.0_144
для серьезной ошибки и заметили, что в JRE1.8.0_144, когда наша программа (JFrame) не сфокусирована, и вызываем setselected(true)
для JInternalFrame в JFrame,JFrame будет мигать на панели задач, чего не будет JRE1.6.0_41.Некоторые клиенты думают, что это раздражает, потому что им приходится часто открывать файлы.
Итак, проблема в следующем:
(1) Можно ли отключить эту функцию?
(2) Если я не могу, есть ли альтернативный способ избежать эффекта мерцания, пока я все еще могу setSelected()
на JInternalFrame?
Если я не объяснил это хорошо, вот пример кода для демонстрацииэффект оповещения, пожалуйста, запустите программу и сверните ее на панели задач. переключитесь в другое окно, затем оно должно мигать.Я протестировал его в 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 добавить KeyboardFocusManager
и WindowListener
, только setselected(true)
на JInternalFrame, когда JFrame имеет фокус, или JFrame получает фокус, но предупреждение все равно возникает, если вы часто переключаете окна, я думаю, это потому, что JFrame потерял правильную фокусировкудо setselected(true)
на JInternalFrame.Может быть, есть способ улучшить код?
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();
}
});
}
}
windowAcactive / windowDeactivation
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();
}
});
}
}