ok let me put the codes first because I might be stating everything as bizarre as i see it
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; public class DoubleCallToRepaintWithNimbusPLAFBizzareProblem { private java.util.List<String> words; private boolean stopSlide; private int wordX; private int head; private int tail; private JButton slide; public DoubleCallToRepaintWithNimbusPLAFBizzareProblem() { words = new ArrayList<String>(); initWordList(); tail = words.size() - 1; stopSlide = true; } public void initWordList() { words.add("F I R S T S L I D E"); words.add("S E C O N D S L I D E"); words.add("T H I R D S L I D E"); words.add("F O U R T H S L I D E"); } public void showWindow() { Panel p = new Panel(); JFrame f = new JFrame(); slide = new JButton("Slide"); slide.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { stopSlide = false; slide.setEnabled(false); } }); p.add(slide); p.setPreferredSize(new Dimension(700, 450)); f.getContentPane().add(p); f.pack(); f.setLocationRelativeTo(null); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setResizable(false); f.setVisible(true); } private class Panel extends JPanel implements Runnable { private Thread runner; private boolean stopThread; public Panel() { runner = new Thread(this); runner.start(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setFont(new Font("Monospaced", Font.BOLD, 35)); g2d.drawString(words.get(head), wordX, 220); g2d.drawString(words.get(tail), wordX + 900, 220); } @Override public void run() { while (!stopThread) { try { Thread.sleep(5); if (!stopSlide) { if (wordX >= -900) { wordX -= 5; } if (wordX < -900 && !stopSlide) { wordX = 0; head = tail; tail--; stopSlide = true; // set enabled again, and i see in the API // there is a call to repaint() inside of it slide.setEnabled(true); // when tail becomes negative 1, // make it the size() - 1 of the list // imediately before the repaint() call below if (tail < 0) { tail = words.size() - 1; } } } repaint(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } } } public static void main(String[] args) { try { for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } new DoubleCallToRepaintWithNimbusPLAFBizzareProblem().showWindow(); } }
i tried to reproduce the thing i encoutered as small as possible , so this is a far as it goes.
- when i do a slide, the int values(head and tail) that calls the values in the word lists, decrements from size() - 1 to 0,
- when it reaches the critical point -1 (tail variable), inside the run method, i have an if part that turns the tail into a positive value that i want immediately before the call to repaint() below it, so i will be able to avoid a -1 out of bounds exception.
- why do i get a -1 exception?
- i tried to debug it for a couple of hours then i pin-point the problem(first assessment)
FIRST ASSESSMENT:
- every time I slide, I disable the slide button when a sliding is occuring, for every succesfull slide animations, i enable the slide button again, as you can see, i put that setEnabled(true) call inside the run() method, JUST BEFORE the if-part that turns the tail variable to something positive before a repainting again, repaint()
- from there i manage to see that there is another repaint() call inside the JComponent setEnabled() method - I dig in
- and from there i realize that when i have a -1 tail, that setEnabled() call calls a repaint() inside of it that repaints everything, and i thought that it might affect the other painting events(my sliding words), thats why i get a -1 outOfBounds(ONCE. only ONCE) it proceeds on the if-part that sets the tail a positive value(not a -1), then proceed to my own painting(the repaint() below of it) and good to go again.
- what i did is i placed the call to .setEnabled() (slide.setEnabled(true)) below the if-part that sets the tail to something positive value, and everything works fine, thats why i am, somehow confident with my understanding that there is a 2 call to repaint() that affects everything. one is inside the setEnabled() of JComponent and the other one is that i have
- now i tried to reproduce again the problem WITHOUT THE NIMBUS PLAF INSTALLATION, and everything i said above doesnt happen
- now the second assesment goes
SECOND ASSESSMENT:
- lets go back to square 1, all those things i said above, removing the installed NIMBUS PLAF, no error has occured
what is going on?, i might be wrong on something(maybe all) and i admit that Im doing a concurrency in an appropriate way. But please.. i need some assitance. Is using Nimbus plaf or installing another PLAF is risky? or calling a swing instance method with a repaint() inside of it in a run method with another repaint() is dangerous? , please ask me if my statements are hard to understand. ill try to explain as more clearly as possible. thank you in advance