在 JTable 单元格中显示时间计数器的有效方法

发布于 2024-07-14 15:41:08 字数 103 浏览 4 评论 0原文

时间计数器显示表中一行的寿命(以秒为单位)。 理想情况下,它每秒更新一次。 我知道我可以在表模型中增加适当的数据,触发事件(每行一个)等。这似乎有点矫枉过正! 有没有更好、更轻松的方法?

A time counter shows the age in seconds of a row in the table. Ideally, it would be updated once per second. I know I can just increment the appropriate data in the table model, fire the events (one per row), etc. It seems like overkill! Is there a better, lighter way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

雪化雨蝶 2024-07-21 15:41:08

您需要的是:

  • 一种对表模型中的行“年龄”进行建模的方法。 最好隐式完成此操作,因此您只需存储一次行的创建时间,并在请求单元格值时计算年龄 (Object getValueAt(row, column))。
  • 每秒触发表更改事件的(守护程序)线程。 您不必为每一行触发一个事件,而是可以触发一个表示整列更新的事件。

下面是表模型的一些伪代码:

public Object getValueAt (int rowIndex, int columnIndex) {

    // if it's the column with the 'row age', calculate the age and return it
    long rowAgeMs = System.currentTimeMs() - getCreationTime(rowIndex);

   // return the age in milliseconds, or a date, or a formatted time string 
}

表模型还应该为线程提供一个方法,这样它就可以触发“行龄”列的更改事件:

public class MyTableModel Implements TableModel {

   private final List<TableModelListener> listeners = new LinkedList<TableModelListener>();

   public void addTableModelListener (TableModelListener l) {
          listeners.add(l);
   }

   public void removeTableModelListener (TableModelListener l) {
          listeners.remove(l);
   }

   public void updateColumn (int column) {
          TableModelEvent evt = new TableModelEvent(this, 0, Math.max(0, getRowCount() - 1), column);
          for (TableModelListener listener : listeners) {
                 listener.tableChanged(evt);
          }
   }

然后,线程将触发 updateColumn (..) 方法每秒针对“行龄”列。 此方法的调用应在 EventDispatchThread 中完成,这是使用 SwingUtilities.invokeAndWait(..) 或 SwingUtilities.invokeLater(..) 完成的。

Thread rowAgeUpdater = new Thread() {

        @Override
        public void run () {
            while (isAlive()) {
                try {

                    long time = System.currentTimeMillis();
                    long sleepTime = (time / 1000 + 1) * 1000 - time;
                    Thread.sleep(sleepTime);

                    SwingUtilities.invokeAndWait(new Runnable() {
                        public void run () {
                            model.updateColumn(ROW_AGE_COLUMN_INDEX);
                        }
                    });

                } catch (Exception e) {
                    return;
                }

            }
        }
    };
    rowAgeUpdater.setDaemon(true);
    rowAgeUpdater.setPriority(Thread.MIN_PRIORITY);
    rowAgeUpdater.start();

只要 TableModelEvent 的粒度仅覆盖需要更新的单元格(在您的情况下:仅包含行龄的列),它就是实现这一点的最有效方法。

What you need is:

  • a way to model the 'age' of the row in your table model. This is best done implicitely, so you just store the creation time of the row once and calculate the age when the cell value is requested (Object getValueAt(row, column)).
  • A (daemon) thread which fires the table change event each second. You don't have to fire one event per row, but instead you can fire an event that signals a whole column update.

Here's some pseudocode for the table model:

public Object getValueAt (int rowIndex, int columnIndex) {

    // if it's the column with the 'row age', calculate the age and return it
    long rowAgeMs = System.currentTimeMs() - getCreationTime(rowIndex);

   // return the age in milliseconds, or a date, or a formatted time string 
}

The table model should then also offer a method for the thread, so it can fire a change event for the 'row age' column:

public class MyTableModel implements TableModel {

   private final List<TableModelListener> listeners = new LinkedList<TableModelListener>();

   public void addTableModelListener (TableModelListener l) {
          listeners.add(l);
   }

   public void removeTableModelListener (TableModelListener l) {
          listeners.remove(l);
   }

   public void updateColumn (int column) {
          TableModelEvent evt = new TableModelEvent(this, 0, Math.max(0, getRowCount() - 1), column);
          for (TableModelListener listener : listeners) {
                 listener.tableChanged(evt);
          }
   }

The thread would then just trigger the updateColumn(..) method each second for the 'row age' column. The invocation of this method should be done in the EventDispatchThread, this is done using SwingUtilities.invokeAndWait(..) or SwingUtilities.invokeLater(..).

Thread rowAgeUpdater = new Thread() {

        @Override
        public void run () {
            while (isAlive()) {
                try {

                    long time = System.currentTimeMillis();
                    long sleepTime = (time / 1000 + 1) * 1000 - time;
                    Thread.sleep(sleepTime);

                    SwingUtilities.invokeAndWait(new Runnable() {
                        public void run () {
                            model.updateColumn(ROW_AGE_COLUMN_INDEX);
                        }
                    });

                } catch (Exception e) {
                    return;
                }

            }
        }
    };
    rowAgeUpdater.setDaemon(true);
    rowAgeUpdater.setPriority(Thread.MIN_PRIORITY);
    rowAgeUpdater.start();

As long as the granularity of the TableModelEvent only covers the cells that need to be updated (in your case: only the column with the row age), it's the most efficient way to realize this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文