最初に表示される行の数と、スクロール可能なJTextArea(JScrollPane内のJTextArea)に現在表示されている行の数を確認するにはどうすればよいですか?
2 に答える
しばらく時間がかかった興味深い質問ですが、かなり有効な答えがあると思います。それでも、もっと良い方法がいくつかあるかもしれません。答えを改善するためにコメントしてください。
戦略:
- FontMetrics と getVisibleRect() を使用して表示されている行を見つける
- 表示されている行の内容を見つけます。
したがって、私の考えは、目に見える四角形から始めるべきだということです。これに基づいて、最初に表示される垂直オフセット ( getVisibleRect().y
) と表示される垂直オフセットの最後( ) を見つけることができますgetVisibleRect().y+getVisibleRect().height
。それができたら、フォントの高さを使用して、どの行が表示されているかを判断できます。
2 番目の部分は、それらの行に何が含まれているかを調べることです。これは私が使用Utilities
する場所でgetRowStart()
あり、getRowEnd()
機能します。
以下は、私が詳しく説明したサンプル コードです (フレームのサイズを変更したり、テキスト領域をスクロールしたりすると、結果がコンソールに出力されます)。
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;
public class TestTextAre {
private void initUI() {
JFrame frame = new JFrame(TestTextAre.class.getSimpleName());
final JTextArea ta = new JTextArea(5, 25);
ta.setText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has "
+ "been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of "
+ "type and scrambled it to make a type specimen book.\n It has survived not only five centuries, but also the "
+ "leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the"
+ " release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing "
+ "software like Aldus PageMaker including versions of Lorem Ipsum.");
ta.setColumns(20);
ta.setEditable(false);
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
JScrollPane scrollpane = new JScrollPane(ta);
scrollpane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
if (e.getValueIsAdjusting()) {
return;
}
printTAVisibleInfo(ta);
}
});
frame.add(scrollpane);
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
printTAVisibleInfo(ta);
}
});
frame.pack();
frame.setVisible(true);
}
private void printTAVisibleInfo(final JTextArea ta) {
List<Row> taInfo = getTAInfo(ta);
int y1 = ta.getVisibleRect().y;
int y2 = y1 + ta.getVisibleRect().height;
int lineHeight = ta.getFontMetrics(ta.getFont()).getHeight();
int startRow = (int) Math.ceil((double) y1 / lineHeight);
int endRow = (int) Math.floor((double) y2 / lineHeight);
endRow = Math.min(endRow, taInfo.size());
System.err.println(startRow + " " + endRow);
for (int i = startRow; i < endRow; i++) {
System.err.println(taInfo.get(i) + " is visible");
}
}
private List<Row> getTAInfo(final JTextArea ta) {
List<Row> taInfo = new ArrayList<TestTextAre.Row>();
int start = 0;
int end = -1;
int i = 0;
try {
do {
start = Utilities.getRowStart(ta, end + 1);
end = Utilities.getRowEnd(ta, start);
taInfo.add(new Row(i, start, end, ta.getDocument().getText(start, end - start)));
i++;
} while (end < ta.getDocument().getLength());
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return taInfo;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestTextAre().initUI();
}
});
}
public static class Row {
private final int row;
private final int start;
private final int end;
private final String text;
public Row(int row, int start, int end, String text) {
super();
this.row = row;
this.start = start;
this.end = end;
this.text = text;
}
public int getRow() {
return row;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public String getText() {
return text;
}
@Override
public String toString() {
return "Row " + row + " contains " + text + " (" + start + "," + end + ")";
}
}
}
水平スクロールバーもある場合は、水平オフセットを で計算できるはずですFontMetrics.stringWidth()
。
さて、これは問題に対する私の見解です...(いい質問ですが)
このソリューションでは、少し考慮する必要があります。部分的に表示された行を返します。
public class TestTextArea {
public static void main(String[] args) {
new TestTextArea();
}
public TestTextArea() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestTextAreaPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestTextAreaPane extends JPanel {
private JTextArea textArea;
private JTextArea viewText;
public TestTextAreaPane() {
setLayout(new GridLayout(2, 1));
textArea = new JTextArea(20, 100);
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
textArea.setText(loadText());
viewText = new JTextArea(20, 100);
viewText.setWrapStyleWord(false);
viewText.setLineWrap(false);
viewText.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
add(scrollPane);
add(viewText);
scrollPane.getViewport().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (textArea.getText().length() > 0) {
JViewport viewport = (JViewport) e.getSource();
Rectangle viewRect = viewport.getViewRect();
Point p = viewRect.getLocation();
int startIndex = textArea.viewToModel(p);
p.x += viewRect.width;
p.y += viewRect.height;
int endIndex = textArea.viewToModel(p);
if (endIndex - startIndex >= 0) {
try {
viewText.setText(textArea.getText(startIndex, (endIndex - startIndex)));
} catch (BadLocationException ex) {
ex.printStackTrace();
viewText.setText(ex.getMessage());
}
}
}
}
});
}
protected String loadText() {
String text = null;
File file = new File("src/testtextarea/TestTextArea.java");
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder(128);
String read = null;
while ((read = br.readLine()) != null) {
sb.append(read).append("\n");
}
text = sb.toString();
} catch (IOException exp) {
exp.printStackTrace();
} finally {
try {
br.close();
} catch (Exception e) {
}
}
return text;
}
}
}