我有一个带有JTextPane的swing gui来输出底层应用程序的日志。我的问题是,在初始化gui和记录第一个日志条目后,滚动条被 "禁用",直到我触发一个动作。在下一个日志条目之后,水平滚动条就会 "出现"。
第二个问题是,有时会发生一个日志语句有1030个字符长。但是水平滚动的最大长度是606个字符。如果我从JTextPane复制文本,我得到了一个洞(1030char)的文本。
我在MainFrame中尝试logTxtArea.setText(".... -> 1030 chars..."); <<- 滚动器按预期工作,也显示了日志语句。
这是我在主机中的JTestPane初始化代码。
private static JTextPane logTxtArea = new JTextPane();
......
logTxtArea.setEditable(false);
logTxtArea.setEditorKit(new NoWrapEditorKit());
JScrollPane logScroller = new JScrollPane(logTxtArea);
logScroller.setFont(new Font("Segoe UI", Font.PLAIN, 12));
logScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
logScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = 1;
gbc.gridheight = 8;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 15, 10, 5);
gbc.weightx = 1;
gbc.weighty = 1;
main.add(logScroller, gbc);
而我的NoWrapEditorKit->。
public class TextAreaAppender extends AppenderSkeleton {
private static Style style;
protected void append(LoggingEvent event) {
this.layout = new PatternLayout("%d - %m%n");
String msg = this.layout.format(event);
JTextPane textArea = MainFrame.getLogTxtArea();
Color color = Color.BLACK;
if (event.getLevel() == Level.INFO) {
color = Color.BLUE;
} else if (event.getLevel() == Level.WARN || event.getLevel() == Level.ERROR || event.getLevel() == Level.FATAL) {
color = Color.RED;
}
if (msg.contains("INFO:")) {
color = Color.MAGENTA;
}
appendToPane(textArea, msg, color);
MainFrame.getLogTxtArea().setCaretPosition(MainFrame.getLogTxtArea().getDocument().getLength());
}
public void close() {
}
public boolean requiresLayout() {
return false;
}
private void appendToPane(JTextPane tp, String msg, Color c) {
int len = tp.getDocument().getLength();
if (style == null) {
style = tp.addStyle("", null);
}
try {
StyleConstants.setForeground(style, c);
tp.getStyledDocument().insertString(len, msg, style);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
所以目标是每行得到一条日志语句,不换行。另外,很长的语句(1030个字符)应该显示完整。
谢谢
更新
下面是一个简短的例子。
public class TextFrame extends JFrame {
private JTextPane txtPane;
private Style style;
public TextFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(true);
this.setMinimumSize(new Dimension(600, 400));
this.setPreferredSize(new Dimension(900, 600));
txtPane = new JTextPane()
{
public boolean getScrollableTracksViewportWidth()
{
return getUI().getPreferredSize(this).width
<= getParent().getSize().width;
}
};
txtPane.setEditable(false);
JScrollPane logScroller = new JScrollPane(txtPane);
logScroller.setFont(new Font("Segoe UI", Font.PLAIN, 12));
logScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
logScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
this.add(logScroller);
append("Short text" + System.lineSeparator(), Color.BLACK);
append("1030 char text - 1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz12345" + System.lineSeparator(), Color.BLACK);
append("2000 char text - 1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz123" + System.lineSeparator(), Color.BLACK);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private void append(String message, Color color) {
int len = txtPane.getDocument().getLength();
if (style == null) {
style = txtPane.addStyle("", null);
}
try {
StyleConstants.setForeground(style, color);
txtPane.getStyledDocument().insertString(len, message, style);
} catch (BadLocationException e) {
e.printStackTrace();
}
//scroll to bottom
txtPane.setCaretPosition(txtPane.getDocument().getLength());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
new TextFrame();
}
});
}
}
我的问题是,在初始化gui和记录第一条日志后,滚动条是 "禁用 "的,直到我触发......它才会工作。解决方法是将JTextPane添加到一个JPanel中。设置JPanel的Layout为BoarderLayout。我认识到,滚动速度stucks,所以我设置了滚动速度。
这是最终的解决方案。
public class TextFrame extends JFrame {
private JTextPane txtPane = new JTextPane();
private Style style;
public TextFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(true);
this.setMinimumSize(new Dimension(600, 400));
this.setPreferredSize(new Dimension(900, 600));
txtPane.setFont(new Font("Segoe UI", Font.PLAIN, 20));
txtPane.setEditable(false);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(txtPane);
JScrollPane logScroller = new JScrollPane(panel);
logScroller.getVerticalScrollBar().setUnitIncrement(16);
logScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
logScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
this.add(logScroller);
//txtPane.setText("TEST text in this line..");
append("Short text" + System.lineSeparator(), Color.BLACK);
append("1030 char text - 1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz12345" + System.lineSeparator(), Color.BLACK);
append("2000 char text - 1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz123" + System.lineSeparator(), Color.BLACK);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private void append(String message, Color color) {
int len = txtPane.getDocument().getLength();
if (style == null) {
style = txtPane.addStyle("", null);
}
try {
StyleConstants.setForeground(style, color);
txtPane.getStyledDocument().insertString(len, message, style);
} catch (BadLocationException e) {
e.printStackTrace();
}
//scroll to bottom
//txtPane.setCaretPosition(txtPane.getDocument().getLength());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
new TextFrame();
}
});
}
}