即使正在触发正确的事件,GUI也不会使用当前信息进行更新

时间:2014-09-02 22:58:17

标签: java swing swingworker jprogressbar tablecellrenderer

我遇到一个GUI的问题,其中 ProgressCellRenderer 没有更新,直到我点击它或突出显示它甚至调整窗口大小。我已经缩减了代码,只使用通用数据并使用sleep来模拟长时间运行的任务。

我错过了什么导致它不会更新,直到我对gui本身进行更新?

这是将运行的最低工作代码。

 public class Test
    {

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

        public Test()
        {
            EventQueue.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    }
                    catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
                    {
                    }

                    UpdatableTableModel model = new UpdatableTableModel();

                    JTable table = new JTable();
                    table.setModel(model);

                    table.getColumn("Status").setCellRenderer(new ProgressCellRender());

                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);

                    StringFinderWorker worker = new StringFinderWorker(model);
                    worker.execute();

                }
            });
        }

        public class ProgressCellRender extends JProgressBar implements TableCellRenderer
        {
            private static final long serialVersionUID = 1L;

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
            {
                int progress = 0;
                if (value instanceof Float)
                {
                    progress = Math.round(((Float) value) * 100f);
                }
                else if (value instanceof Integer)
                {
                    progress = (int) value;
                }
                setValue(progress);
                return this;
            }
        }

        public class RowData
        {
            private String string;
            private float status;

            public RowData(String string)
            {
                this.string = string;
                this.status = 0f;
            }

            public String getString()
            {
                return string;
            }

            public float getStatus()
            {
                return status;
            }

            public void setStatus(float status)
            {
                this.status = status;
            }
        }

        public class UpdatableTableModel extends AbstractTableModel
        {
            private static final long serialVersionUID = 1L;

            private List<RowData> rows;
            private Map<String, RowData> mapLookup;

            public UpdatableTableModel()
            {
                rows = new ArrayList<>(25);
                mapLookup = new HashMap<>(25);
            }

            @Override
            public int getRowCount()
            {
                return rows.size();
            }

            @Override
            public int getColumnCount()
            {
                return 2;
            }

            @Override
            public String getColumnName(int column)
            {
                String name = "??";
                switch (column)
                {
                    case 0:
                        name = "The String";
                        break;
                    case 1:
                        name = "Status";
                        break;
                }
                return name;
            }

            @Override
            public Object getValueAt(int rowIndex, int columnIndex)
            {
                RowData rowData = rows.get(rowIndex);
                Object value = null;
                switch (columnIndex)
                {
                    case 0:
                        value = rowData.getString();
                        break;
                    case 1:
                        value = rowData.getStatus();
                        break;
                }
                return value;
            }

            @Override
            public void setValueAt(Object aValue, int rowIndex, int columnIndex)
            {
                RowData rowData = rows.get(rowIndex);
                switch (columnIndex)
                {
                    case 3:
                        if (aValue instanceof Float)
                        {
                            rowData.setStatus((float) aValue);
                        }
                        break;
                }
            }

            public void addString(String string)
            {
                RowData rowData = new RowData(string);
                mapLookup.put(string, rowData);
                rows.add(rowData);
                fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
            }

            protected void updateStatus(String string, int progress)
            {
                RowData rowData = mapLookup.get(string);
                if (rowData != null)
                {
                    int row = rows.indexOf(rowData);
                    float p = (float) progress / 100f;
                    setValueAt(p, row, 3);
                    fireTableCellUpdated(row, 3);
                }
            }
        }

        public class StringFinderWorker extends SwingWorker<List<String>, String>
        {

            private UpdatableTableModel model;

            public StringFinderWorker(UpdatableTableModel model)
            {
                this.model = model;
            }

            @Override
            protected void process(List<String> chunks)
            {
                for (String string : chunks)
                {
                    model.addString(string);
                }
            }

            protected ArrayList<String> getStrings()
            {
                ArrayList<String> strings = new ArrayList<String>();
                for (int i = 0; i < 24; i++)
                {
                    strings.add("test: " + i);
                }
                return strings;
            }

            @Override
            protected List<String> doInBackground() throws Exception
            {
                List<String> strings = getStrings();

                for (int i = 0; i < strings.size(); i++)
                {
                    publish(strings.get(i));
                }
                return strings;
            }

            @Override
            protected void done()
            {
                try
                {
                    List<String> strings = get();
                    for (String string : strings)
                    {
                        new StringDownloaderWorker(model, string).execute();
                    }
                }
                catch (Exception exp)
                {
                    exp.printStackTrace();
                }
            }
        }

        public class StringDownloaderWorker extends SwingWorker<String, String>
        {

            private String currentString;
            private UpdatableTableModel model;

            public StringDownloaderWorker(UpdatableTableModel model, String string)
            {
                this.currentString = string;
                this.model = model;

                addPropertyChangeListener(new PropertyChangeListener()
                {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt)
                    {
                        if (evt.getPropertyName().equals("progress"))
                        {
                            StringDownloaderWorker.this.model.updateStatus(currentString, (int) evt.getNewValue());
                        }
                    }
                });

            }

            @Override
            protected String doInBackground() throws Exception
            {
                for (int i = 0; i <= 100; i++)
                {
                    setProgress(i);
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch (InterruptedException ie)
                    {
                        //
                    }
                }

                return currentString;
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

当你看到这个时,你会踢自己......

用于注册单元格已更改的事实的列索引是错误的...

您正在使用setValueAt(p, row, 3);,当进度列实际为1时,您应该实际使用setValueAt(p, row, 1);

这也意味着switch方法中的setValueAt语句需要更改。

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    RowData rowData = rows.get(rowIndex);
    switch (columnIndex) {
        case 1:
            if (aValue instanceof Float) {
                rowData.setStatus((float) aValue);
                fireTableCellUpdated(rowIndex, columnIndex);
            }
            break;
    }
}

您还会注意到我已将fireTableCellUpdated调用移至此方法,因为您永远不知道何时可能会调用setValueAt

答案 1 :(得分:0)

每当有变更时,您必须更新您的表格

我的意思是当你的桌子上有一些变化时你必须调用你的更新功能来更新表格

要做到这一点,你可以使用一个监听器来检测一些变化;如果一个单元格或更多单元格中有更改,则必须调用该函数来更新表格

通常要实现此类更新,您必须使用模型输入,因为每次您的表在一个或多个单元格中有一些更改时===&gt;这意味着你的表的模型是改变

更新模型,然后调用main函数更新当前窗口的容器 其他三个函数用于更新SWING接口:更新函数或重绘函数或setContentPane(您的Jpanel或表的容器)