使用JScrollPane和JViewport的最大尺寸小于内容的滚动限制

问题描述:

我有一个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

该问题与线程安全无关。经过大量挖掘,我发现JPanel的外观窗口管理器实现的外观尺寸限制为32767,所以它没有关系,它位于JScrollPane。这个想法是为了避免对个人JScrollPane的额外管理,但这个限制使得它无法避免。

JPanel的内容转移到各自的个人JscrollPane中解决了问题。由于我未知的原因,滚动仍然有点迟缓。

您的示例不正确地同步,因为它更新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