Hello, I found another interesting performance regression in one of my applications. Scrolling in a JTable seems to be sluggish when I show a splashcreen first, rendering speed is good when I don't show the splashscreen or when the splashcreen does not exceed a width or height of 150 pixels.
Test: [code] import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.text.View; import java.awt.*; import java.io.IOException; import java.lang.reflect.InvocationTargetException; public class ScrollpaneTest { private static final String MULTILINE = "The following JComponent methods are safe to call from any thread: repaint(), revalidate(), and invalidate(). " + "The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate(), " + "respectively. The invalidate() method just marks a component and all of its direct ancestors as requiring validation.\n" + "Listener lists can be modified from any thread: It's always safe to call the addListenerTypeListener() and " + "removeListenerTypeListener() methods. The add/remove operations have no effect on an event dispatch that's under way." + "Most post-initialization GUI work naturally occurs in the event-dispatching thread. Once the GUI is visible, most " + "programs are driven by events such as button actions or mouse clicks, which are always handled in the event-dispatching thread.\n" + "\n" + "However, some programs need to perform non-event-driven GUI work after the GUI is visible. Here are some examples:\n" + "\n" + " * Programs that must perform a lengthy initialization operation\n" + " before they can be used: This kind of program should generally show some GUI while the initialization is occurring, " + "and then update or change the GUI. The initialization should not occur in the event-dispatching thread; otherwise, repainting " + "and event dispatch would stop. However, after initialization the GUI update/change should occur in the event-dispatching thread, " + "for thread-safety reasons.\n" + " \n" + " * Programs whose GUI must be updated as the result of non-AWT events: For example, suppose a server program can get requests " + "from other programs that might be running on different machines. These requests can come at any time, and they result in one of " + "the server's methods being invoked in some possibly unknown thread. How can that method update the GUI? By executing the GUI update " + "code in the event-dispatching thread.\n" + "\n" + "The SwingUtilities class provides two methods to help you run code in the event-dispatching thread:\n" + "\n" + " * invokeLater(): Requests that some code be executed in the event-dispatching thread. This method returns immediately, without " + "waiting for the code to execute.\n" + " \n" + " * invokeAndWait(): Acts like invokeLater(), except that this method waits for the code to execute. As a rule, you should use " + "invokeLater() instead of this method.\n" + "\n" + "This page gives you some examples of using this API. Also see the BINGO example in The Java Tutorial, especially the following " + "classes: CardWindow, ControlPane, Player, and OverallStatusPane. "; public static void main(String[] args) throws IOException, InterruptedException, InvocationTargetException { final SplashScreen[] splashScreens = new SplashScreen[1]; EventQueue.invokeAndWait(new Runnable() { public void run() { splashScreens[0] = new SplashScreen(); splashScreens[0].setVisible(true); } }); splashScreens[0].setDescription("loading"); Thread.sleep(300); splashScreens[0].setDescription("loading more"); Thread.sleep(300); splashScreens[0].setDescription("loading almost done"); Thread.sleep(300); EventQueue.invokeLater(new Runnable() { public void run() { splashScreens[0].dispose(); initGUI(); } }); } private static class SplashScreen extends Window { private String description; private int iw; private int ih; private SplashScreen() { super(null); iw = 151;//150=fast, 151=slow ih = 120; setSize(iw, ih + 30); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((screen.width - iw) / 2, (screen.height - ih + 30) / 2); } public void paint(Graphics g) { g.setColor(Color.BLACK); g.fillRect(0, ih, getWidth(), 30); g.setColor(Color.WHITE); if (description != null) { System.out.println(Thread.currentThread().getName()); g.drawString(description, 10, ih + 25); } } public void setDescription(String description) { this.description = description; repaint(); } } private static void initGUI() { JFrame frame = new JFrame(); JTable table = new JTable(new DefaultTableModel(new String[][]{ {"A", MULTILINE}, {"B", MULTILINE}, {"C", MULTILINE}, {"D", MULTILINE}, {"E", MULTILINE}, {"F", MULTILINE}, {"G", MULTILINE}, {"H", MULTILINE}, {"I", MULTILINE}, }, new String[]{"A", "B"})); table.getColumnModel().getColumn(1).setCellRenderer(new MultilineTableCellRenderer()); JScrollPane scrollPane = new JScrollPane(table) { protected JViewport createViewport() { return new JViewport() { public void setViewPosition(Point p) { long ns1 = System.nanoTime(); super.setViewPosition(p); long ns2 = System.nanoTime(); System.out.println((ns2 - ns1) / 1000000. + " ms"); } }; } }; frame.getContentPane().add(scrollPane, BorderLayout.CENTER); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(100, 100, 500, 500); frame.setVisible(true); } private static class MultilineTableCellRenderer extends JTextArea implements TableCellRenderer { protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); private MultilineTableCellRenderer() { setWrapStyleWord(true); setLineWrap(true); setBorder(noFocusBorder); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (isSelected) { super.setForeground(table.getSelectionForeground()); super.setBackground(table.getSelectionBackground()); } else { super.setForeground(table.getForeground()); super.setBackground(table.getBackground()); } setFont(table.getFont()); setBorder(noFocusBorder); boolean enabled = table.isEnabled(); setEnabled(enabled); setValue(table, row, column, value); return this; } protected void setValue(JTable table, int row, int column, Object value) { if (value != null) { String title = value.toString(); setText(title); View view = getUI().getRootView(this); view.setSize((float) table.getColumnModel().getColumn(column).getWidth() - 3, -1); float y = view.getPreferredSpan(View.Y_AXIS); int h = (int) Math.ceil(y + 3); if (table.getRowHeight(row) != h) { table.setRowHeight(row, h); } } else { setText(""); } } } } [/code] Increasing the width or height in the constructor of the splashscreen above 150 pixels triggers the problem on my machine. This can be reproduced always, and never occurs if both sizes are smaller than 150 pixels. Using -Dsun.java2d.d3d=false resolves the problem. The problem is resolved as soon as I remove the line g.drawString(description, 10, ih + 25); Removing the calls to the SplashScreen#setDescription method resolves the problem. Also moving the calls to SplashScreen#setDescription into EDT seems to resolve the problem. I had the impression that calling repaint outside of the EDT is OK ( http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html ). Is this a wrong assumption? The paint method itself seems to be called using the Thread AWT-EventQueue-0. Operating System is Windows Vista CheckAdaptersInfo ------------------ Adapter Ordinal : 0 Description : NVIDIA GeForce Go 7900 GS (Microsoft Corporation - WDDM) GDI Name, Driver : \\.\DISPLAY1, nvd3dum Vendor Id : 0x10de Version : 7.15.10.9746 ------------------ InitD3D: successfully created Direct3D9 object D3DGD_getDeviceCapsNative D3DPPLM::CheckDeviceCaps: device 0: Passed D3DContext::InitContext device 0 D3DContext::ConfigureContext device 0 D3DContext::ConfigureContext: successfully created device: 0 D3DContext::InitDevice: device 0 D3DContext::InitDefice: successfully initialized device 0 [V] | CAPS_DEVICE_OK [V] | CAPS_ALPHA_RT_PLAIN [V] | CAPS_ALPHA_RTT [V] | CAPS_OPAQUE_RTT [V] | CAPS_LCD_SHADER | CAPS_BIOP_SHADER [V] | CAPS_MULTITEXTURE [V] | CAPS_TEXNONPOW2 [V] | CAPS_TEXNONSQUARE 1.6.0_05-ea-b04 (-Dsun.java2d.d3d=false) 5.124674 ms 0.006845 ms 4.371156 ms 0.003911 ms 3.381505 ms 0.006984 ms 4.547785 ms 0.00426 ms 5.117689 ms 0.005028 ms 7.560877 ms 1.6.0_05-ea-b04 (-Dsun.java2d.d3d=true) 60.889512 ms 0.005028 ms 158.421811 ms 0.00461 ms 119.451774 ms 0.003003 ms 0.003073 ms 0.002864 ms 0.005099 ms 125.332689 ms 0.002724 ms 0.002933 ms 0.005378 ms 110.553087 ms Thanks, Martin [Message sent by forum member 'til77' (til77)] http://forums.java.net/jive/thread.jspa?messageID=239487 =========================================================================== To unsubscribe, send email to [EMAIL PROTECTED] and include in the body of the message "signoff JAVA2D-INTEREST". For general help, send email to [EMAIL PROTECTED] and include in the body of the message "help".