2013-08-20 55 views
1

我有一個窗口,它在表格中顯示日誌事件。 例如,用戶正在讀取某一行表中的文本。當新的日誌到來時,它們被添加到表格的開頭,並且用戶正在閱讀的行向下移動。我有一個要求,當在表的開頭添加新行時,防止JScrollPane滾動。我嘗試了不同的東西,但沒有任何幫助。有人可以告訴我如何實現這個? 在此先感謝!如何使JScrollPane在表格的開頭添加行後不滾動

回答

1

棘手的任務:-)移動出現是因爲默認情況下,滾動位置是而不是以任何方式調整:添加上面的行只是保持垂直滾動位置,然後指向一個不同的行像以前一樣。

只需要什麼:

的的visibleRect /最後一行
  • 跟蹤前插入
  • 聽型號的變化插入
  • 計算新的可見矩形等老最後一行滾動回視圖
  • 觸發滾動

這很棘手,因爲我們需要聽取模型更改。該監聽器是由表格內部註冊的modelListener的鄰居,該表格根據更改進行更新。所以我們需要確保的內部變更完成並同時使用之前的信息的內部更新。

一個骯髒的解決方案 - 取決於搖擺聽衆通知通常的順序是最後加入先通知(注意:DONT在生產代碼它會容易折斷,網絡改變了LAF時) - 是通知當收集前狀態並調整包裹在一個invokeLater的滾動位置:

final DefaultTableModel model = new DefaultTableModel(20, 2); 
for (int i = 0; i < model.getRowCount(); i++) { 
    model.setValueAt(i, i, 0); 
} 
final JTable table = new JTable(model); 
Action action = new AbstractAction("add row at 0") { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     model.insertRow(0, new Object[] {}); 
    } 
}; 
JXFrame frame = wrapWithScrollingInFrame(table, "modify scroll"); 
TableModelListener l = new TableModelListener() { 

    @Override 
    public void tableChanged(TableModelEvent e) { 
     if (!TableUtilities.isInsert(e)) return; 
     final Rectangle r = table.getVisibleRect(); 
     final int lastRow = table.rowAtPoint(
       new Point(0, r.y + r.height - 5)); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       // assuming 
       // a) the insert was exactly 1 row 
       // b) was _before_ the old last row in view-coordinates 
       Rectangle cell = table.getCellRect(lastRow + 1, 0, true); 
       cell.translate(0, -r.height + cell.height); 
       cell.height = r.height; 
       table.scrollRectToVisible(cell); 
      } 
     }); 
    } 
}; 
model.addTableModelListener(l); 

得到的適當的方式之前,狀態乾淨取決於您的具體情境。您可以將表格的生命週期內跟蹤第一/最後一排的,在(一個或全部)

  • 一個ListSelectionListener該行selectionModel設置更新它們(如果用戶閱讀該行始終被選中)
  • 一個ChangeListener垂直滾動條
  • 一個的ComponentListener到滾動窗格的大小改變
+0

感謝您的repsonse!我幫助了! – obogoliy