2014-01-09 75 views
5

另请参阅Java Swing GUI hour glass。然而,提供的答案似乎并不奏效。摆动:将光标更改为等待光标

我有以下代码:

private void loadFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) {             

    int returnVal = fileChoser.showOpenDialog(this); 
    if (returnVal == JFileChooser.APPROVE_OPTION) { 

     try { 
      this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
      // do stuff 
     } finally { 
      this.setCursor(Cursor.getDefaultCursor()); 
     } 
    } 
} 

当用户选择菜单栏中的条目,根据该被调用。但是光标不会改变。请注意,加载文件需要一个文件,因此光标的更改应该是可见的。

我在做什么错?

编辑:

this是顶级的JFrame。

编辑2:moved solution to separate answer

+0

的根窗格为了更好地帮助越早,张贴[SSCCE](http://sscce.org /)。请注意,该文件正在[此问题]上进行审查和讨论(http://meta.stackexchange.com/q/214955/155831),欢迎加入。 –

+0

//在做什么事情发生? 在那里实现的代码应该在一个单独的线程中。否则,您的应用程序将看不到对光标所做的任何更改。 – oopbase

+2

不要阻塞EDT(Event Dispatch Thread) - 当发生这种情况时GUI将“冻结”。而不是调用'Thread.sleep(n)'实现一个Swing'Timer'来重复执行任务,或者一个'SwingWorker'执行长时间运行的任务。有关更多详细信息,请参见[Swing中的并发](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 –

回答

5

首先做一个SwingWorker类:​​

private class FileLoader extends SwingWorker<String, Void> { 

    private final JFrame frame; 
    private final File file;   

    public SdfLoader(JFrame frame, File file) {    
     frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
     this.frame = frame; 
     this.file = file; 
    } 

    @Override 
    public String doInBackground() throws IOException { 

      String result = null; 
      // read file and set result; 
     return result; 
    } 

    @Override 
    public void done() { 
     try { 
      String result = get(); 
      //do stuff 
     } catch (ExecutionException | InterruptedException ex) { 
      // display error 
      JOptionPane.showMessageDialog(SdfViewer.this, 
        ioException.getMessage(), 
        "Error opening file", 
        JOptionPane.ERROR_MESSAGE); 
     } finally { 
      frame.setCursor(Cursor.getDefaultCursor()); 
     } 
    } 

} 

然后调用它是这样的:由@mKorbel做出

private void loadFileMenuItemActionPerformed(java.awt.event.ActionEvent evt) { 
    int returnVal = fileChoser.showOpenDialog(this); 
    if (returnVal == JFileChooser.APPROVE_OPTION) { 
     File file = fileChoser.getSelectedFile(); 
     logger.debug("Opening SD-File '{}'.", file.getAbsoluteFile()); 
     FileLoader loader = new FileLoader(this, file); 
     loader.execute(); 
    } 
} 

编辑,请原谅我这个hi_jack

  • 我找不到我的帖子h该代码在这里(一些与underlaing数据库happends),

  • 使用这种逻辑,

  • 剩下的就是在我的评论在这里

虚拟-1K错,错,错,您的doInBackground()缺失 publish() - process(),done() is extremly wrong designed,如果可以使用,请阅读@trashgod的回答中的注释 Runnable#用于FileIO,Socket或任何XxxStreams的线程而不是黑色 孔基于未来的SwingWorker

  • 请删除您的线程的代码按编辑

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_INTERVAL_SELECTION); 
     myTable.setRowSelectionAllowed(false); 
     myTable.setColumnSelectionAllowed(true); 
     //myTable.setCellSelectionEnabled(true); 

     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

虚拟-1K错误,错误,错误,你doInBackground()缺少发布() - 进程(),[完成()是极端错误设计](http://stackoverflow.com/questions/7053865/cant- get-arrayindexoutofboundsexception-from-future-and-swingworker-if-threa),如果可以使用Runnable#Thread for FileIO,Socket或任何XxxStreams而不是基于Future和SwingWorker的黑洞,请阅读注释 – mKorbel

+0

我不需要发布和处理方法,现在已经完成了。 Runnable有一个问题,因为你不能向用户报告异常...它只会失败,异常会被忽视:我认为这很愚蠢,尤其是FileIO。 –

+0

这不是真的,Runnable没有任何问题,也没有在你的评论中描述过,这个说明中谈到了为什么不使用SwingWorker(有很长和很长的bug历史,并且经常重复),也没有用于生产代码,肯定一切都取决于你,Runnable是FileIO,XxxStream,Socket,JDBC的最佳选择 – mKorbel

2

加载文件已经保持EDT忙,所以它不会改变光标的机会。

3
  • 为EventDispatchThread常见的问题是,当ActionListener的所有代码被执行

  • 那么你每天的活动都在一瞬间完成,那么每一个代码,方法,类在一个时刻重新粉刷/后要使用此分割到逻辑包裹的(最好的选择)两个摆动操作的两个独立事件,

    1. 一个与光标切换 - 仅游标可以的PropertyChangeListener调用或从ButtonModel的JM管理enuItem

    2. 另一个摇摆动作或任何SwingListener调用REST /或预期码

    3. 你可以链接这两个摇摆动作(我的上午),第一次一个叫第二

+0

@Andrew汤普森不需要我有这个线程在我的雷达:-), – mKorbel

+0

很酷。希望我们会看到一个新的改进版本'现在很快'。 :) –

+1

@安德鲁·汤普森对于我之前比较空洞的评论感到抱歉,对我来说很重要的是,这个选项作为标准在这里存在,没有别的,我忽略了每一个blablblba,每个词都是针对/反对或者其他...... – mKorbel

5

你没有看到这些变化的原因很可能是你在做EDT的所有工作。永远不要这样做。即使您在单独的线程上使用// do stufffinally块也会在UI有机会重新绘制之前执行。

相反,您应该产生一个设置等待光标的SwingWorker,然后在后台执行繁重的工作(文件加载),最后在完成时重置为普通光标。

这可能表明,首先不需要等待光标,并且在这种情况下使用进度条会更合适。

+0

请参阅编辑我的问题对于我的解决方案 –

2

哇 - 什么是所有的代码。它很容易:

final JScrollPane jsp = new JScrollPane(jt); 

jsp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 

       //DO SOMETHING 
jsp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
0

你不应该运行(EDT)Swing事件分派线程上的一个漫长的过程,往往只要你喜欢(开关面板时的例子),显示等待光标在框架中同时加载一些快速的数据。

为了实现此附上光标改变为JFrame

public class TestFrame extends JFrame { 

    private static final long serialVersionUID = 5671798241966272024L; 

    /** 
    * In this example static to show how they can be 
    * centralized in application with multiple frames 
    */ 
    public static void setWaitCursor(JFrame frame) { 
     if (frame != null) { 
      RootPaneContainer root = (RootPaneContainer) frame.getRootPane().getTopLevelAncestor(); 
      root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
      root.getGlassPane().setVisible(true); 
     } 
    } 

    public static void setDefaultCursor(JFrame frame) { 
     if (frame != null) { 
      RootPaneContainer root = (RootPaneContainer) frame.getRootPane().getTopLevelAncestor(); 
      root.getGlassPane().setCursor(Cursor.getDefaultCursor()); 
     } 
    } 

    public TestFrame() { 
     super("Test"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     init(); 
    } 

    private void init() { 
     getContentPane().setLayout(new BorderLayout()); 
     JButton btnTest = new JButton("Load some quick stuff"); 
     btnTest.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       TestFrame.setWaitCursor(TestFrame.this); 
       doSomeShortProccessing(); 
       TestFrame.setDefaultCursor(TestFrame.this); 
      } 
     }); 
     getContentPane().add(btnTest); 
     pack(); 
    } 

    protected void doSomeShortProccessing() { 
     try { 
      //You should never do Thread.sleep on the EDT is just to display function 
      //Normaly process would be create a new panel and load some quick data 
      Thread.sleep(1000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     TestFrame frame = new TestFrame(); 
     frame.setLocationRelativeTo(null); //Middle of screen 
     frame.setVisible(true); 
    } 
}