2011-05-18 67 views
14

我有问题在我的应用程序中显示等待光标。只要鼠标位于定义自己光标的面板上方,等待光标就不会出现。如果面板不改变光标,则会出现等待光标。java等待光标显示问题

我附上一个SSCE来准确地解释我的问题。

public class BusyCursorTest extends javax.swing.JFrame { 

public BusyCursorTest() { 

    javax.swing.JMenuBar menuBar = new javax.swing.JMenuBar(); 
    javax.swing.JMenu menu = new javax.swing.JMenu("Menu"); 
    javax.swing.JMenuItem wait1 = new javax.swing.JMenuItem("Wait 100 ms"); 
    javax.swing.JMenuItem wait2 = new javax.swing.JMenuItem("Wait 250 ms"); 
    javax.swing.JMenuItem wait3 = new javax.swing.JMenuItem("Wait 500 ms"); 
    javax.swing.JMenuItem wait4 = new javax.swing.JMenuItem("Wait 1000 ms"); 
    menu.add(wait1); 
    menu.add(wait2); 
    menu.add(wait3); 
    menu.add(wait4); 
    menuBar.add(menu); 
    setJMenuBar(menuBar); 
    wait1.addActionListener(getActionListener(this, delayActionListener(100))); 
    wait2.addActionListener(getActionListener(this, delayActionListener(250))); 
    wait3.addActionListener(getActionListener(this, delayActionListener(500))); 
    wait4.addActionListener(getActionListener(this, delayActionListener(1000))); 

    cursorPanel = new javax.swing.JPanel(); 
    cursorPanel.addMouseListener(new java.awt.event.MouseAdapter() { 

     public void mouseEntered(java.awt.event.MouseEvent e) { 
      cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.CROSSHAIR_CURSOR)); 
     } 

     public void mouseExited(java.awt.event.MouseEvent e) { 
      cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); 
     } 

    }); 

    javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane(); 
    tabbedPane.addTab("Default", new javax.swing.JPanel()); 
    tabbedPane.addTab("Cursor change", cursorPanel); 
    getContentPane().add(tabbedPane); 

    setTitle("Cursor test"); 
    setSize(400, 400); 
    setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); 
    setVisible(true); 
} 

private java.awt.event.ActionListener delayActionListener(final int delay) { 
    java.awt.event.ActionListener listener = new java.awt.event.ActionListener() { 

     public void actionPerformed(java.awt.event.ActionEvent ae) { 
      try { 
       Thread.sleep(delay); 
      } catch (InterruptedException e) { 
      } 
     } 

    }; 
    return listener; 
} 

public static void main(String[] args) { 
    new BusyCursorTest(); 
} 

public static java.awt.event.ActionListener getActionListener(final java.awt.Component component, 
    final java.awt.event.ActionListener originalActionListener) { 

    java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener() { 

     public void actionPerformed(final java.awt.event.ActionEvent e) { 

      java.util.TimerTask timerTask = new java.util.TimerTask() { 

       public void run() { 
        originalCursor = component.getCursor(); 
        component.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); 
       } 

      }; 
      java.util.Timer timer = new java.util.Timer(); 

      try { 
       timer.schedule(timerTask, DELAY_MS); 
       originalActionListener.actionPerformed(e); 
      } finally { 
       timer.cancel(); 
       component.setCursor(originalCursor); 
      } 
     } 

    }; 
    return actionListener; 
} 

private javax.swing.JPanel cursorPanel = null; 

public static java.awt.Cursor originalCursor = null; 

public static final int DELAY_MS = 250; 
} 

运行附加的SSCE。

当选择第一个选项卡(“默认”)时,单击1000ms菜单项将显示忙状态光标。

当选择第二个选项卡(“光标更改”)时,单击1000ms菜单项不会显示繁忙光标。

我该如何解决这个问题?

我强烈希望我的代码不必考虑任何面板,因为要跟踪哪些面板可能处于最前沿非常困难。而且,由于鼠标点击,事件并不总是生成。

什么是建议的解决方法,以便我可以修改顶层容器的行为?

回答

5

搜索互联网后,我找到了答案,我的问题。

关键是将光标设置在包含要显示忙光标的组件的帧的玻璃窗格上。我从网上的以下文章中得到了这个想法。

Wait, Cursor, Wait!

An Automatic Wait Cursor: WaitCursorEventQueue

我修改了SSCE,使其为案件工作时,在框架内的组件设置自己的光标。这是修改后的SSCE。

public class BusyCursorTest extends javax.swing.JFrame { 

private javax.swing.JPanel cursorPanel = null; 

public BusyCursorTest() { 

    javax.swing.JMenuBar menuBar = new javax.swing.JMenuBar(); 
    javax.swing.JMenu menu = new javax.swing.JMenu("Menu"); 
    javax.swing.JMenuItem wait1 = new javax.swing.JMenuItem("Wait 100 ms"); 
    javax.swing.JMenuItem wait2 = new javax.swing.JMenuItem("Wait 250 ms"); 
    javax.swing.JMenuItem wait3 = new javax.swing.JMenuItem("Wait 500 ms"); 
    javax.swing.JMenuItem wait4 = new javax.swing.JMenuItem("Wait 1000 ms"); 
    menu.add(wait1); 
    menu.add(wait2); 
    menu.add(wait3); 
    menu.add(wait4); 
    menuBar.add(menu); 
    setJMenuBar(menuBar); 
    wait1.addActionListener(getActionListener(this, delayActionListener(100))); 
    wait2.addActionListener(getActionListener(this, delayActionListener(250))); 
    wait3.addActionListener(getActionListener(this, delayActionListener(500))); 
    wait4.addActionListener(getActionListener(this, delayActionListener(1000))); 

    cursorPanel = new javax.swing.JPanel(); 
    cursorPanel.addMouseListener(new java.awt.event.MouseAdapter() { 

     public void mouseEntered(java.awt.event.MouseEvent e) { 
      cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.CROSSHAIR_CURSOR)); 
     } 

     public void mouseExited(java.awt.event.MouseEvent e) { 
      cursorPanel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR)); 
     } 

    }); 

    javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane(); 
    tabbedPane.addTab("Default", new javax.swing.JPanel()); 
    tabbedPane.addTab("Cursor change", cursorPanel); 
    getContentPane().add(tabbedPane); 

    setTitle("Cursor test"); 
    setSize(400, 400); 
    setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); 
    setVisible(true); 
} 

private java.awt.event.ActionListener delayActionListener(final int delay) { 
    java.awt.event.ActionListener listener = new java.awt.event.ActionListener() { 

     public void actionPerformed(java.awt.event.ActionEvent ae) { 
      try { 
       Thread.sleep(delay); 
      } catch (InterruptedException e) { 
      } 
     } 

    }; 
    return listener; 
} 

public static void main(String[] args) { 
    new BusyCursorTest(); 
} 

public static java.awt.event.ActionListener getActionListener(final javax.swing.JFrame frame, 
    final java.awt.event.ActionListener originalActionListener) { 

    java.awt.event.ActionListener actionListener = new java.awt.event.ActionListener() { 

     public void actionPerformed(final java.awt.event.ActionEvent e) { 

      java.util.TimerTask timerTask = new java.util.TimerTask() { 

       public void run() { 
        originalCursor = frame.getCursor(); 
        startWaitCursor(frame); 
       } 

      }; 
      java.util.Timer timer = new java.util.Timer(); 

      try { 
       timer.schedule(timerTask, DELAY_MS); 
       originalActionListener.actionPerformed(e); 
      } finally { 
       timer.cancel(); 
       stopWaitCursor(frame); 
      } 
     } 

    }; 
    return actionListener; 
} 

private static void startWaitCursor(javax.swing.JFrame frame) { 
    frame.getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR)); 
    frame.getGlassPane().addMouseListener(mouseAdapter); 
    frame.getGlassPane().setVisible(true); 
} 

private static void stopWaitCursor(javax.swing.JFrame frame) { 
    frame.getGlassPane().setCursor(originalCursor); 
    frame.getGlassPane().removeMouseListener(mouseAdapter); 
    frame.getGlassPane().setVisible(false); 
} 

private static java.awt.Cursor originalCursor = null; 

private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() { 
}; 

public static final int DELAY_MS = 250; 

}

+0

上,绘制轮子滚动事件的jscrollpan效果非常好,只是想指出上面的代码不能捕获鼠标事件。如果我保持事件线程繁忙,则可能无法捕捉鼠标事件。 – 2011-05-19 22:19:43

+0

在阻塞EDT时正确可靠地捕获鼠标事件的SSCE发布在线程中:http://stackoverflow.com/questions/7085239/java-swing-clear-the-event-queue。 – 2011-12-20 22:34:32

1

尝试将它设置在框架上,而不是给定组件的

+0

我确实设置在上述SSCE框架上的光标。 – 2011-05-19 13:48:46

+0

那么:@ Santosh-Tiwari它现在如何,它的工作?我想我也遇到了类似的情况,因为你...... – gumuruh 2011-08-15 09:39:08

+0

是忙游标工作得很好。两个问题:i)如果我阻止了EDT,我仍然无法捕捉鼠标事件。一旦EDT释放,它就开始处理排队的鼠标/键盘事件。 ii)忙状态光标仍然不会出现在新的对话框/框架上。我知道如何解决这个问题,但尚未打扰。 – 2011-08-16 21:08:13

2

嗯,你的代码有问题Concurency in Swing有两个方面

取代了Thread.sleep(延迟);而java.util.Timer中与java.swing.Timer因为块EDT

但在其他手上有怎样的方式(从OTN通过splungebob)故意块EDT 注:对所有的Swing rulles这个例子中,并以这种形式的工作方式和作为例子

import java.awt.*; 
import java.util.*; 
import javax.swing.*; 
import javax.swing.event.*; 

public class DelayedComboBoxDemo implements Runnable { 

    private JCheckBox chkA = new JCheckBox("A"); 
    private JCheckBox chkB = new JCheckBox("B"); 
    private JCheckBox chkC = new JCheckBox("C"); 
    private JComboBox cboItems = new JComboBox(); 
    private JFrame frame; 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new DelayedComboBoxDemo()); 
    } 

    @Override 
    public void run() { 
     cboItems.addItem("-"); 
     JPanel p = new JPanel(); 
     p.add(chkA); 
     p.add(chkB); 
     p.add(chkC); 
     p.add(cboItems); 
     frame = new JFrame("Delayed ComboBox Test"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(p); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     cboItems.addPopupMenuListener(new PopupMenuListener() { 

      @Override 
      public void popupMenuCanceled(PopupMenuEvent e) { 
      } 

      @Override 
      public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 
      } 

      @Override 
      public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 
       int items = cboItems.getItemCount(); 
       rebuildList(); 
       if (items != cboItems.getItemCount()) { 
        cboItems.hidePopup(); 
        cboItems.showPopup(); 
       } 
      } 
     }); 
    } 

    private void rebuildList() { 
     frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     Vector<String> items = new Vector<String>(); 
     if (chkA.isSelected()) { 
      items.add("A"); 
     } else if (chkB.isSelected()) { 
      items.add("B"); 
     } else if (chkC.isSelected()) { 
      items.add("C"); 
     } else { 
      items.add("-"); 
     } 
     cboItems.setModel(new DefaultComboBoxModel(items)); 
     try { 
      Thread.sleep(3000); // simulate a long transaction 
     } catch (InterruptedException ex) { 
     } 
     frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
    } 
} 
+0

我不确定并发是否是问题(仍在探索这方面)。我正在使用Thread.sleep()来模拟长事务。它与这样一个事实有关,即其中一个选项卡设置自己的光标,以某种方式覆盖切换到繁忙的光标。 – 2011-05-19 13:57:25

+0

从setCursor()方法的javadoc中:具有非null游标的任何组件都将覆盖在其父容器上设置的游标。我需要找出一种方法,只有当我必须显示一个忙碌光标时,才能覆盖该覆盖。 – 2011-05-19 14:29:22

+1

如果你只创建一个例子,并且没有任何输出到GUI的BackGround任务,那么你通过Thread.sleep(int)块的GUI,如我发布的例子,在其他情况下,你将冒这样的风险到GUI不按预期工作,或直接冻结,在这种情况下,只是mousrHover重新绘制,我会给你另一个例子,证明正确性和使用Timer和Runnable,但我必须实现你的BusyCursor .. – mKorbel 2011-05-19 14:42:22

4
import java.awt.*; 
import java.awt.event.*; 
import java.text.SimpleDateFormat; 
import java.util.Random; 
import javax.swing.*; 
import javax.swing.UIManager.LookAndFeelInfo; 
import javax.swing.table.*; 

public class TableWithTimer implements ActionListener, Runnable { 

    private static final long serialVersionUID = 1L; 
    private JFrame frame = new JFrame(); 
    private JScrollPane scroll = new JScrollPane(); 
    private JTable myTable; 
    private JPanel buttonPanel = new JPanel(); 
    private JButton startButton = new JButton("Start Thread to Update Table"); 
    private JButton stopButton = new JButton("Stop Thread for Update Table"); 
    private JButton newButton = new JButton("Load new Data to Table"); 
    private int count = 0; 
    private int delay = 3; 
    private javax.swing.Timer timer = null; 
    private boolean runProcess; 
    private int row = 0; 
    private int column = 0; 
    private String value = "Amnd"; 
    private int amndValue = 0; 
    private String valueAt = ""; 
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 
    private String[] head = {"One", "Two", "Three", "Four", "Five", "Six"}; 
    private String[][] data = new String[25][6]; 

    public TableWithTimer() { 
     myTable = new TableBackroundPaint0(data, head); 
     myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
     myTable.setGridColor(Color.gray); 
     myTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
     final TableCellRenderer cellRendener = myTable.getTableHeader().getDefaultRenderer(); 
     myTable.getTableHeader().setDefaultRenderer(new TableCellRenderer() { 

      @Override 
      public Component getTableCellRendererComponent(JTable table, Object value, 
        boolean isSelected, boolean hasFocus, int row, int column) { 
       JLabel label = (JLabel) cellRendener.getTableCellRendererComponent(
         table, value, isSelected, hasFocus, row, column); 
       label.setBackground(Color.orange); 
       label.setForeground(Color.darkGray); 
       label.setFont(new Font("SansSerif", Font.BOLD, 12)); 
       label.setBorder(BorderFactory.createCompoundBorder(label.getBorder(), 
         BorderFactory.createEmptyBorder(0, 5, 0, 0))); 
       label.setHorizontalAlignment(SwingConstants.LEFT); 
       label.setHorizontalAlignment(SwingConstants.CENTER); 
       if ((label.getText().equals("First")) || (label.getText().equals("Second"))) { 
        label.setForeground(Color.red); 
       } 
       if ((label.getText().equals("Day")) || (label.getText().equals("Month")) || (label.getText().equals("Year"))) { 
        label.setForeground(Color.blue); 
       } 
       if ((label.getText().equals("Time"))) { 
        label.setForeground(Color.green); 
       } 
       return label; 
      } 
     }); 
     TableColumnModel cm = myTable.getColumnModel(); 
     for (int column1 = 0; column1 < cm.getColumnCount(); column1++) { 
      TableColumn colLeft1 = cm.getColumn(column1); 
      cm.getColumn(column1).setWidth(140); 
      cm.getColumn(column1).setPreferredWidth(140); 
     } 
     //myTable.setFillsViewportHeight(true); // apply paintComponent for whole Viewport 
     JButton cornerButtonTop = new JButton(); 
     cornerButtonTop.setBackground(scroll.getViewport().getBackground()); 
     JButton cornerButtonBottom = new JButton(); 
     cornerButtonBottom.setOpaque(false); 
     scroll.setCorner(JScrollPane.UPPER_RIGHT_CORNER, cornerButtonTop); 
     scroll.setCorner(JScrollPane.LOWER_RIGHT_CORNER, cornerButtonBottom); 
     scroll.setViewportView(myTable); 
     scroll.setMinimumSize(new Dimension(600, 400)); 
     scroll.setMaximumSize(new Dimension(900, 600)); 
     scroll.setPreferredSize(new Dimension(850, 430)); 
     frame.add(scroll, BorderLayout.CENTER); 
     buttonPanel.setLayout(new GridLayout(1, 4, 10, 10)); 
     startButton.addActionListener(this); 
     startButton.setEnabled(false); 
     stopButton.addActionListener(this); 
     stopButton.setEnabled(false); 
     JButton hideButton = new JButton(); 
     newButton.addActionListener(this); 
     newButton.setEnabled(false); 
     buttonPanel.add(startButton); 
     buttonPanel.add(stopButton); 
     buttonPanel.add(hideButton); 
     buttonPanel.add(newButton); 
     hideButton.setVisible(false); 
     frame.add(buttonPanel, BorderLayout.SOUTH); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocation(100, 100); 
     frame.pack(); 
     frame.setVisible(true); 
     start(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (e.getSource() == startButton) { 
      runProcess = true; 
      new Thread(this).start(); 
      myTable.requestFocus(); 
      startButton.setEnabled(false); 
      stopButton.setEnabled(true); 
     } else if (e.getSource() == stopButton) { 
      scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      runProcess = false; 
      startButton.setEnabled(true); 
      stopButton.setEnabled(false); 
      newButton.setEnabled(true); 
     } else if (e.getSource() == newButton) { 
      runProcess = false; 
      startButton.setEnabled(true); 
      stopButton.setEnabled(false); 
      newButton.setEnabled(false); 
      addNewData(); 
     } 
    } 

    public void addNewData() { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       TableModel model = myTable.getModel(); 
       for (int j = 0; j < model.getRowCount(); j++) { 
        int column = model.getColumnCount(); 
        for (int i = 0; i < column; i++) { 
         model.setValueAt("Deleted", j, i); 
        } 
       } 
       startNewData(); 
      } 
     }); 
    } 

    private void start() { 
     scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     timer = new javax.swing.Timer(delay * 100, updateCol()); 
     timer.start(); 
    } 

    private void startNewData() { 
     scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     count = 0; 
     timer = new javax.swing.Timer(1500, updateCol()); 
     timer.start(); 
    } 

    @Override 
    public void run() { 
     scroll.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     count = 0; 
     Random random = new Random(); 
     while (runProcess) { 
      row = random.nextInt(myTable.getRowCount()); 
      column = random.nextInt(myTable.getColumnCount()); 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        try { 
         amndValue++; 
         valueAt = ((myTable.getValueAt(row, column)).toString()); 
         if (!(valueAt.startsWith("A"))) { 
          count++; 
          if (count == ((25 * 6))) { 
           JOptionPane.showMessageDialog(myTable, " Update done "); 
           scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
           runProcess = false; 
          } 
          java.util.Date date = new java.util.Date(); 
          String dateTime = sdf.format(date.getTime()); 
          myTable.setValueAt((value + " " + String.valueOf(amndValue) + " at: " + dateTime), row, column); 
          //myTable.setValueAt(new Integer(1), row, column); // please uncoment for generate misstype error on EDT 
          myTable.changeSelection(row, column, false, false); 
          System.out.println("update cycle with value :" 
            + (value + " " + String.valueOf(amndValue) + " at: " + dateTime) + ", table row :" + row 
            + ", table column " + column); 
         } 
        } catch (Exception e) { 
         runProcess = false; 
         System.out.println("Error for update JTable cell"); 
         e.printStackTrace(); 
        } 
       } 
      }); 
      try { 
       Thread.sleep(500); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public Action updateCol() { 
     return new AbstractAction("text load action") { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public void actionPerformed(ActionEvent e) { 

       System.out.println("updating row " + (count + 1)); 
       TableModel model = myTable.getModel(); 
       int cols = model.getColumnCount(); 
       int row = 0; 
       for (int j = 0; j < cols; j++) { 
        row = count; 
        myTable.changeSelection(row, 0, false, false); 
        timer.setDelay(200); 
        Object value = "row " + (count + 1) + " item " + (j + 1); 
        model.setValueAt(value, count, j); 
       } 
       count++; 
       if (count >= myTable.getRowCount()) { 
        myTable.changeSelection(0, 0, false, false); 
        timer.stop(); 
        System.out.println("update cycle completed"); 
        myTable.clearSelection(); 
        startButton.setEnabled(true); 
        newButton.setEnabled(true); 
        scroll.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
       } 
      } 
     }; 
    } 

    public static void main(String args[]) { 
     try { 
      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
       System.out.println(info.getName()); 
       if ("Nimbus".equals(info.getName())) { 
        UIManager.setLookAndFeel(info.getClassName()); 
        break; 
       } 
      } 
     } catch (UnsupportedLookAndFeelException e) { 
      // handle exception 
     } catch (ClassNotFoundException e) { 
      // handle exception 
     } catch (InstantiationException e) { 
      // handle exception 
     } catch (IllegalAccessException e) { 
      // handle exception 
     } 
     TableWithTimer tableWithTimer = new TableWithTimer(); 
    } 
} 

class TableBackroundPaint0 extends JTable { 

    private static final long serialVersionUID = 1L; 

    TableBackroundPaint0(Object[][] data, Object[] head) { 
     super(data, head); 
     setOpaque(false); 
     ((JComponent) getDefaultRenderer(Object.class)).setOpaque(false); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     Color background = new Color(168, 210, 241); 
     Color controlColor = new Color(230, 240, 230); 
     int width = getWidth(); 
     int height = getHeight(); 
     Graphics2D g2 = (Graphics2D) g; 
     Paint oldPaint = g2.getPaint(); 
     g2.setPaint(new GradientPaint(0, 0, background, width, 0, controlColor)); 
     g2.fillRect(0, 0, width, height); 
     g2.setPaint(oldPaint); 
     for (int row : getSelectedRows()) { 
      Rectangle start = getCellRect(row, 0, true); 
      Rectangle end = getCellRect(row, getColumnCount() - 1, true); 
      g2.setPaint(new GradientPaint(start.x, 0, controlColor, (int) ((end.x + end.width - start.x) * 1.25), 0, Color.orange)); 
      g2.fillRect(start.x, start.y, end.x + end.width - start.x, start.height); 
     } 
     super.paintComponent(g); 
    } 
} 
+0

+1 for'javax.swing.Timer';渐变也很有趣。 – trashgod 2011-05-29 16:34:50

+0

@trashgod这个渐变是一件艺术品,对于视口和SelectedRow(s)也是如此,Nimbus是非常冷酷的,但是这个http://stackoverflow.com/questions/1249278/how-to-disable-the-default-在Nimbus L&F, – mKorbel 2011-05-29 18:33:50