2014-09-04 77 views
3

我有一個JFrame,其中包含JScrollPane,其中包含JPanelJPanel包含一堆JTextArea s。 我正在加載大量文本(大約8k-10k個字符)。使用JScrollPane和JViewport的最大尺寸小於內容的滾動限制

佈局工作正常,但滾動有點滯後。

真正的問題是,它似乎JPanelJScrollPaneJViewport有硬32767大小的限制,所以當任何JTextArea增長高於,不能滾動任何進一步顯示文本的最後1/3 。

您可以在下面看到該問題的最小示例。我用了NetBeans JFrame設計者所以它可能是一個有點冗長,但我已經從默認更改的唯一事情是JTextArea s爲的JPanel的直接孩子,滾動條政策,並稍大字體大小:

public class NewJFrame extends javax.swing.JFrame { 

/** 
* Creates new form NewJFrame 
*/ 
public NewJFrame() { 
    initComponents(); 
} 

/** 
* This method is called from within the constructor to initialize the form. 
* WARNING: Do NOT modify this code. The content of this method is always 
* regenerated by the Form Editor. 
*/ 
@SuppressWarnings("unchecked") 
// <editor-fold defaultstate="collapsed" desc="Generated Code">       
private void initComponents() { 

    jScrollPane1 = new javax.swing.JScrollPane(); 
    jPanel1 = new javax.swing.JPanel(); 
    jTextArea1 = new javax.swing.JTextArea(); 
    jTextArea2 = new javax.swing.JTextArea(); 

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

    jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 
    jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 

    jTextArea1.setColumns(20); 
    jTextArea1.setFont(new java.awt.Font("Monospaced", 0, 14)); // NOI18N 
    jTextArea1.setRows(5); 

    jTextArea2.setColumns(20); 
    jTextArea2.setFont(new java.awt.Font("Monospaced", 0, 14)); // NOI18N 
    jTextArea2.setRows(5); 
    jTextArea2.setText("Some long text..."); 

    javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); 
    jPanel1.setLayout(jPanel1Layout); 
    jPanel1Layout.setHorizontalGroup(
     jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addGroup(jPanel1Layout.createSequentialGroup() 
      .addComponent(jTextArea1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
      .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 
      .addComponent(jTextArea2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
      .addGap(0, 0, 0)) 
    ); 
    jPanel1Layout.setVerticalGroup(
     jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addGroup(jPanel1Layout.createSequentialGroup() 
      .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 
       .addComponent(jTextArea1, javax.swing.GroupLayout.DEFAULT_SIZE, 342, Short.MAX_VALUE) 
       .addComponent(jTextArea2)) 
      .addGap(0, 0, 0)) 
    ); 

    jScrollPane1.setViewportView(jPanel1); 

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
    getContentPane().setLayout(layout); 
    layout.setHorizontalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addComponent(jScrollPane1) 
    ); 
    layout.setVerticalGroup(
     layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
     .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 96, Short.MAX_VALUE) 
    ); 

    pack(); 
}// </editor-fold>       

/** 
* @param args the command line arguments 
*/ 
public static void main(String args[]) { 
    final NewJFrame f = new NewJFrame(); 
    /* Set the Nimbus look and feel */ 
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> 
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. 
    * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
    */ 
    try { 
     for(javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) 
      if("Nimbus".equals(info.getName())) { 
       javax.swing.UIManager.setLookAndFeel(info.getClassName()); 
       break; 
      } 
    }catch(ClassNotFoundException ex) { 
     java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    }catch(InstantiationException ex) { 
     java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    }catch(IllegalAccessException ex) { 
     java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    }catch(javax.swing.UnsupportedLookAndFeelException ex) { 
     java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 
    } 
    //</editor-fold> 

    /* Create and display the form */ 
    java.awt.EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      f.setVisible(true); 
     } 
    }); 
    StringBuilder txt = new StringBuilder(); 
    for(int i=0; i<10000; i++) 
     txt.append(i).append("\n"); 
    f.jTextArea1.setText(txt.toString()); 
    txt = new StringBuilder(); 
    txt.append("JTextArea height: ").append(f.jTextArea1.getHeight()).append('\n'); 
    txt.append("JTextArea rows: ").append(f.jTextArea1.getRows()).append('\n'); 
    txt.append("JScrollPane height:").append(f.jScrollPane1.getHeight()).append('\n'); 
    txt.append("JViewport height:").append(f.jScrollPane1.getViewport().getHeight()).append('\n'); 
    txt.append("JPanel height:").append(f.jPanel1.getHeight()).append('\n'); 
    f.jTextArea2.setText(txt.toString()); 
} 
// Variables declaration - do not modify      
private javax.swing.JPanel jPanel1; 
private javax.swing.JScrollPane jScrollPane1; 
private javax.swing.JTextArea jTextArea1; 
private javax.swing.JTextArea jTextArea2; 
// End of variables declaration     
} 

如果您運行此操作並滾動到底部,您會希望看到計數達到10 000,但它只能達到1637,並且您可以看到來自下一行的頂部像素幾乎不顯示。

我已經嘗試setMaximumSizesetSizeJPanel,在JScrollPane及其JViewport但一切都沒有改變。我也有些困惑,即使有10萬行文本,其中一些文本可以滾動到足以查看,getRows()getSize()方法返回原始值。

當我想要一個可滾動的JTextArea大於32767時,處理這種情況的正確方法是什麼?

+0

我不能相信JViewport可以有這樣的限制。我開發了一個有一百萬行的表格,它可以很好地滾動。請提供一個工作示例以獲得更好的幫助。 – 2014-09-04 21:11:42

+0

我會想象硬限制將接近於Interger.MAX_VALUE,基於Dimension的要求 – MadProgrammer 2014-09-04 21:20:15

+0

您可以使用這種[方法](http://stackoverflow.com/a/25526869/230513)利用'JTable'輕量級渲染;根據需要使用自定義或彈出單元格編輯器。 – trashgod 2014-09-05 00:50:52

回答

1

該問題與線程安全無關。經過大量挖掘,我發現JPanel的外觀窗口管理器實現的外觀尺寸限制爲32767,所以它沒有關係,它位於JScrollPane。這個想法是爲了避免對個人JScrollPane的額外管理,但這個限制使得它無法避免。

JPanel的內容轉移到各自的個人JscrollPane中解決了問題。由於我未知的原因,滾動仍然有點遲緩。

2

您的示例不正確地同步,因爲它更新initial thread上的jTextArea2。請注意0​​不再是線程安全的。以下示例調用EditorKit#read()(建議here)加載相同的27 MB,176 K行文件here。這需要幾秒鐘的時間,約爲JTable方法的兩倍,但滾動是可比的。

import java.awt.EventQueue; 
import java.io.BufferedReader; 
import java.io.FileReader; 
import java.io.IOException; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 

/** 
* @see https://stackoverflow.com/a/25691384/230513 
*/ 
public class Test { 

    private static final String NAME = "/var/log/install.log"; 

    private void display() { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JTextArea text = new JTextArea(24, 32); 
     try { 
      text.read(new BufferedReader(new FileReader(NAME)), null); 
     } catch (IOException ex) { 
      ex.printStackTrace(System.err); 
     } 
     f.add(new JScrollPane(text)); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(() -> { 
      new Test().display(); 
     }); 
    } 
} 
+0

我很抱歉,但這與我正在嘗試做的事情或我給出的示例無關。我沒有看到線程安全是如何重置「JTextArea」中的文本的問題 - 我根本不使用「append()」。即使我是,我只有主線程寫入'JTextArea',所以我不明白爲什麼會出現同步問題。你的例子沒有表現出我的問題,但它也缺乏我的佈局,所以這不是很有用。 – nwod 2014-09-05 21:51:41

+0

糟糕,你說'append()',但'setText()'有同樣的問題;更新。你可以使用任何你想要的佈局。該示例顯示滾動窗格可以處理比「大約8k-10k個字符」更多的文本。 – trashgod 2014-09-06 00:38:59

+1

對於沒有生成所有代碼的'SSCCE' +1。 '但它也缺乏佈局我'佈局是問題。誰知道GroupLayout在做什麼(我當然不知道)?爲什麼你會創建一個帶有scrollpane/panel/textarea的結構?通常情況下,文本區域直接添加到滾動窗格。擺脫所有組佈局代碼和麪板。然後,將文本區域添加到滾動窗格的視口。然後將滾動窗格添加到BorderLayout.WEST,將第二個文本區域添加到BorderLayout.EAST。 – camickr 2014-09-06 01:26:45