Reputation: 113
I have a Java swing application that creates and displays a tabbedpane and creates an update thread. The update thread when triggered needs to add a set of tabs with content but I am getting an exception now and again "Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException".
Is this something to do with adding tabs in a different thread? If so how do I add a tab to it in a thread safe way please??
Here is an example application that illustrates the problem
public class Example extends JFrame implements Runnable {
private final JTabbedPane tabbedPane;
private final Rectangle bounds;
public Example() {
super("Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
bounds = new Rectangle(0, 0, 500, 500);
setBounds(bounds);
setLayout(null);
tabbedPane = new JTabbedPane();
tabbedPane.setBounds(bounds);
JPanel jp = new JPanel();
jp.setLayout(null);
jp.setBounds(bounds);
jp.add(tabbedPane);
add(jp);
new Thread(this).start();
}
@Override
public void run() {
while (true) {
for (int i = 0; i < 3; i++) {
tabbedPane.addTab("NEW" + i, new JPanel());
repaint();
}
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public static void main(String[] args) {
Example e = new Example();
e.setVisible(true);
}
}
Upvotes: 0
Views: 402
Reputation: 347334
Swing is not thread safe...
This means that you should never try to create or modify the UI from outside the context of the Event Dispatching Thread.
The likely issue is you've run into some kind of race condition. Take a look at Concurrency in Swing and How to use Swing Timers for more details
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.Timer;
public class Example extends JFrame {
private final JTabbedPane tabbedPane;
private final Rectangle bounds;
public Example() {
super("Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
bounds = new Rectangle(0, 0, 500, 500);
setBounds(bounds);
// setLayout(null);
tabbedPane = new JTabbedPane();
tabbedPane.setBounds(bounds);
// JPanel jp = new JPanel();
// jp.setLayout(null);
// jp.setBounds(bounds);
// jp.add(tabbedPane);
// add(jp);
add(tabbedPane);
Timer timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 3; i++) {
tabbedPane.addTab("NEW" + tabbedPane.getTabCount(), new JPanel());
}
tabbedPane.revalidate();
}
});
timer.start();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Example e = new Example();
e.setVisible(true);
}
});
}
}
Avoid using null
layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
Take a look at Laying Out Components Within a Container for more details
Upvotes: 1