When running a Swing application on 8u161 or 8u162 and focus is in a JTextField and you switch to another application (like Chrome) and back to the application CPU usage grows to 15% on my 8 core Windows 10 PC (as if an entire core is busy processing events).
Just run the application and switch a couple of times.
If I click on the tab in the tabbed pane CPU usage drops to 0 as expected.
public class Test {
public static void main(String... args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame("Test");
JTabbedPane tp = new JTabbedPane();
tp.addTab("tab 1", new JTextField(20));
f.add(tp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
I have tried to look at the event queue to see what happens and it looks a lot like the last event gets processed again and again
If I add this to the above program I get a lot of java.awt.event.InvocationEvent[INVOCATION_DEFAULT,runnable=sun.awt.windows.WInputMethod ...
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue(){
#Override protected void dispatchEvent(AWTEvent event) {
System.out.println(event);
super.dispatchEvent(event);
}
});
Works OK on 8u151, 8u152 and 9.0.4
I have a lot of customers that are upgrading to 161 and get this problem so any suggestions for a workaround is much appreciated.
I have filed a bug with Oracle
JProfiler shows this:
Seems to work OK on 8u172 b02
According to openjdk this was introduced by 8184016 and fixed by 8183504
Are your customers using input methods? If you don't need input methods enabled, I suggest that you could disable it.
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Test");
JTabbedPane tp = new JTabbedPane();
JTextField tf = new JTextField();
tf.enableInputMethods(false); // disable IM
tp.addTab("tab 1", tf);
f.add(tp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
This is probably pretty ugly, but it's a workaround I created based on my observations on when the bug occurs. I'm sure it's possible to create a better workaround with better understanding of why exactly the bug occurs in the first place.
It basicially prevents any JTextComponent from being focused as the first thing after the window gets focused, transfers focus to another component (upFocusCycle(component) for me puts in on the frame/dialog) and then transfers it back the the JTextComponent. I don't know if this will work in every case or maybe even break something, but it seems to work for me. Use at your own risk obviously.
public class JTextFieldTest {
public static final void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// Install workaround, without this the bug occurs
installTextComponentFocusWorkaround();
JFrame window = new JFrame("Test");
window.setLocationByPlatform(true);
window.add(new JButton("Button"), BorderLayout.CENTER);
window.add(new JTextField(), BorderLayout.SOUTH);
window.pack();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setVisible(true);
});
}
public static void installTextComponentFocusWorkaround() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addVetoableChangeListener(new VetoableChangeListener() {
private boolean rejectNext = false;
private JComponent target;
#Override
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
if (evt.getNewValue() != null) {
if (evt.getPropertyName().equals("focusOwner")) {
if (evt.getNewValue() instanceof JTextComponent) {
if (rejectNext) {
JComponent component = (JComponent) evt.getNewValue();
KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle(component);
target = component;
System.out.println("Rejected JTextComponent focus");
throw new PropertyVetoException("Rejected JTextComponent focus", evt);
}
} else {
rejectNext = false;
if (target != null) {
System.out.println("Temp focus: " + evt.getNewValue());
target.requestFocus();
target = null;
}
}
} else if (evt.getPropertyName().equals("focusedWindow")) {
System.out.println("Window focused");
rejectNext = true;
}
}
}
});
}
}
I also tried things like clearing focus altogether or only throwing a PropertyVetoException, but only actually focusing someting else before the JTextComponent seemed to work.
I'm looking for JTextComponent because the bug occured for me with both JTextField and JTextArea, although I'm not sure if other classes are affected as well.
Related
I had a problem while calling two mouse events, one into the other. I wanted to show a second frame (frame2) when the user clicks on a component (component1) from the first frame (frame1), then returns to the previous frame (frame1) if the component2 is clicked on. All this using one file.
This is what I wrote:
component1.addMouseListener(this on);
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getSource() == component1)
{
frame1.dispose();
frame2.setVisible(true);
component2.addMouseListener(new MouseAdapter() {
public void mouseClicked() {
frame2.dispose();
frame1.setVisible(true);
}
});
}
}
The first event works, but not the second.
Thank you for answering.
Here is a fully functional example where there are 2 frames, each with a label that, when clicked, hides one frame and shows the other, done in Java 10. See if this works for you and explain how your code differs from this. Note that I only created 2 MouseListeners, one for each frame. I did not recreate the MouseListener in the other MouseListener's code. Also, I did not dispose the frame, which will likely cause problems. If I had disposed frame1, I would most likely have to create a new JFrame and assign it to the frame1 instance member.
Please note you have to click on the label itself, not somewhere else on the frame.
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TwoFrames {
public static void main(String[] args) {
TwoFrames twoFrames = new TwoFrames();
twoFrames.start();
}
private void start() {
setupFrames();
}
JFrame frame1 = new JFrame("Frame 1"),
frame2 = new JFrame("Frame 2");
JLabel component1 = new JLabel("Click me 1"),
component2 = new JLabel("Click me 2");
private void setupFrames() {
frame1.getContentPane().add(component1);
frame2.getContentPane().add(component2);
component1.setOpaque(true);
component2.setOpaque(true);
component1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame1.setVisible(false);
frame2.setVisible(true);
}
});
component2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame2.setVisible(false);
frame1.setVisible(true);
}
});
frame1.setSize(300, 300);
frame2.setSize(400, 400);
frame1.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(() -> frame1.setVisible(true));
}
}
The dispose() method actually destroys the window and so, frame1 should become null and you are most likely getting a null pointer exception.
Consider calling frame1.setVisible(false) and frame2.setVisible(false) instead of the dispose() method.
Also, you could consider using to separate mouse listener objects instead of adding a new mouse listener to component2 when component1 is clicked.
I used the NteBeans' GUI making tool.
It created a frame.
I want to close this frame using a button.
I know that I need to use "my_frame_name.dispose();" to close a frame.
But the problem is I cant find the name of the frame in the "Source" tab.
I think this is because, NetBeans created this frame and its code automatically.
Could anyone tell me how to close this frame using a code or a function, please?
Please don't tell me I have to recode everything, because I have multiple frames like tis one and don't have the luxury of time.
You can try this one also
Here program is using container.getParent() method to find out the top most JFrame.
public static void main(String[] a) {
JFrame frame = new JFrame();
JPanel p = new JPanel();
final JButton btn = new JButton("close");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Container parent = btn;
while ((parent = parent.getParent()) != null) {
System.out.println(parent.getClass().getName());
if (parent instanceof JFrame) {
((JFrame) parent).setVisible(false);
} else {
parent = parent.getParent();
}
}
}
});
p.add(btn);
frame.getContentPane().add(p);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
I'm fairly new to Swing, so I've been using windowbuilder to try and put together a basic GUI. The design screen works fine, but when I return to the code, it's written it in a way I'm unfamiliar with and I'm struggling to actually get it to run.
The code it generates is:
public class GUIControls extends JFrame{
public GUIControls() {
getContentPane().setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel();
getContentPane().add(panel, "name_36737116256884");
panel.setLayout(null);
JButton InsertionSortButton = new JButton("Insertion Sort");
InsertionSortButton.setBounds(32, 16, 101, 56);
panel.add(InsertionSortButton);
JPanel panel_1 = new JPanel();
getContentPane().add(panel_1, "name_36737137352442");
InsertionSortButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
CardLayout cardLayout = (CardLayout) getContentPane().getLayout();
cardLayout.show(getContentPane(), "name_36737137352442");
}
});
}
(With the action taken when the button is mouseclicked being written by me, I haven't tested it because I can't run the thing)
Normally I'd do:
public void runGUI(){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
}
});
}
With createGUI being the method I used to create a (completely horrible) GUI without windowbuilder, but I can't use GUIControls in this because it doesn't work with runnable (in fact, I'm not even sure what it is when something doesn't a return value, is it still a method?).
Does anyone know how I go about running it?
Thanks
You need to instantiate an instance of GUIControls and make it visible, for example...
public void runGUI(){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUIControls guiControls = new GUIControls();
guiControls.pack();
guiControls.setLocationRelativeTo(null);
guiControls.setVisible(true);
}
});
}
ps- I know Window Builder likes to make use of null layouts, but I would avoid them wherever possible - IMHO
Good evening ladies and gentlemen,
I have a problem with Java Swing that I cannot solve, maybe you can help me. Here it is:
I have one JFrame which uses BorderLayout, and many JPanels.
Every time I need to put up a new screen (i.e. from the Main Menu, when Search button is clicked, go to the Search Menu), I simply remove the component (JPanel) which is located in the center, and put the new screen (new JPanel) in the center instead.
This way, I don't call all my header and footer objects every time I want to put up a new screen.
Everything works fine with this system except this little problem: I want to trigger some methods everytime I put up a new JPanel or change back to an existing JPanel (generally speaking, everytime a JPanel appears).
In order to do that, I tried to implement ComponentListener's componentShown(ComponentEvent e) method, and added a ComponentListener to a JPanel which I put up in the center of my JFrame, and it did NOT work. After this, I did some research and found out that this componentShown (#ComponentListener) method only works when the visibilty of the JPanel is changed (from invisible to visible or the opposite). Unfortunately, I'm not changing the visibility of a JPanel, just replacing it with another one: removing the current one, and adding the new one. Below code illustrates how I replace the JPanels.
// Get the JPanel located in the center of our JFrame
JPanel currentView = (JPanel) myFrame.getContentPane().getComponent( 2 );
if ( currentView != null )
{
// Remove it from the JPanel
myFrame.getContentPane().remove( currentView );
}
// Add the new JPanel
myFrame.getContentPane().add( otherView, BorderLayout.CENTER );
// Pack the JFrame and show it
myFrame.pack();
So here is what I have. I would really appreciate it if you could help me out.
I think that this issue corresponding with HierarchyListener, for comparing
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ContainerListener extends JFrame {
private static final long serialVersionUID = 1L;
public ContainerListener() {
super("Test");
setContentPane(new TestPanel());
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] parameters) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ContainerListener containerListener = new ContainerListener();
}
});
}
private class TestPanel extends JPanel {
private static final long serialVersionUID = 1L;
TestPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
add(new JButton(new AbstractAction("Add label") {
private static final long serialVersionUID = 1L;
private int n = 0;
#Override
public void actionPerformed(ActionEvent event) {
TestPanel.this.add(new JLabel("Label " + ++n));
validate();
}
}));
addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("Components Change: " + e.getChanged());
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (e.getComponent().isDisplayable()) {
System.out.println("Components: " + e.getChanged());
} else {
System.out.println("Components: " + e.getChanged());
}
}
}
});
addContainerListener(new ContainerAdapter() {
#Override
public void componentAdded(ContainerEvent event) {
System.out.println("componentAdded : " + event.getChild() + "containerName" + " was added");
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
I highly recommend listening to the advice given by #Jeffrey, but if you do proceed with this design, then perhaps implementing the ContainerListener interface may prove useful.
When in doubt, consult the API.
I have a simple Java Swing GUI Form with a browse button. The browse button creates a new JFileChooser when it's clicked.
However, if you click browse immediately after the window opens, the file chooser window seems to loose focus, showing the parent window behind it, but it refuses to repaint itself. I have to drag it off screen and back on again to get it to return to normal.
I've tried to reduce my code to the simplest version that still has the problem. (It just makes a very large browse button.
public class FormTest extends JFrame
{
private final int width = 490;
private final int height = 400;
private JPanel outerPanel;
private static FormTest myTest;
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch( Exception e )
{
e.printStackTrace();
}
myTest = new FormTest();
myTest.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
myTest.setResizable(false);
myTest.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
closeWindow();
}
});
myTest.setVisible(true);
}
public FormTest()
{
super("Convert Ratings");
this.setSize(width, height);
initComponents();
}
private void initComponents()
{
outerPanel = new JPanel();
outerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
outerPanel.add(Box.createRigidArea(new Dimension(0, 5)));
JButton myButton = new JButton("browse");
myButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.showOpenDialog(myTest);
}
});
outerPanel.add(myButton);
this.add(outerPanel);
}
private static void closeWindow()
{
int result = JOptionPane.showConfirmDialog(myTest, "Are you sure you want to close the application?",
"Question", JOptionPane.YES_NO_OPTION);
if( result == JOptionPane.YES_OPTION )
{
System.exit(0);
}
}
}
In this example, the browse button must be clicked immediately after the window opens and the bug will show itself after about 10 seconds.
Any help or suggestions would be much appreciated.
Thanks,
B.J.
Since your question has changed I'll add another answer. It looks like you're looking to use a CardLayout.
The unresponsiveness of your application is probably caused by some incorrect logic with repainting/hiding/unhiding panels.
Here is Oracle's tutorial on using it
http://download.oracle.com/javase/tutorial/uiswing/layout/card.html
New Addition:
I'm currently on a mac and I can't see the issue, I'll try it again when I'm at a PC later today.
Original Post:
Sounds like a event dispatch thread issue. Make sure you are doing anything that manipulates the GUI in the event dispatch thread.
http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
Any long running task should use another thread or swing worker to perform it's function, otherwise it will cause things to stop responding/lock up/etc.