Java JTextPane 垂直对齐

Java JTextPane Vertical Alignment

我正在开发一款简单的文字冒险游戏,它应该允许用户输入文字并得到他们的回应,就像一个简单的命令提示符一样。

出于各种原因,我正在尝试使用 JPanel window 和其他一些东西,以便我可以控制内容的显示方式。以下是我目前的代码。

但是我遇到了一些问题:JTextPane 中的文本与 window 的顶部而不是底部对齐,并且文本不可滚动。基本上,您刚刚输入的文本应该像命令提示符一样出现在文本输入框上方,并且旧文本应该是可滚动的。有谁知道我应该如何解决这个问题?

提前致谢。

小修改:这是它当前的截图。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

public class TextDemo extends JPanel implements ActionListener {

protected JTextField textField;
protected JTextPane textArea;
private final static String newline = "\n";
public static Color fg = Color.WHITE, bg = Color.BLACK;
public static final Font header = new Font("Times New Roman", Font.PLAIN, 96);
public static final Font normal = new Font("Times New Roman", Font.PLAIN, 24);

public TextDemo() {
    super(new GridBagLayout());

    textField = new JTextField();
    textField.setFont(normal);
    textField.setForeground(fg);
    textField.setBackground(bg);
    textField.setPreferredSize(new Dimension(640, 30));
    textField.addActionListener(this);

    textArea = new JTextPane();
    textArea.setFont(normal);

    //textArea.setLineWrap(true);
    //textArea.setWrapStyleWord(true);
    textArea.setForeground(fg);
    textArea.setBackground(bg);
    textArea.setPreferredSize(new Dimension(640, 450));
    textArea.setEditable(false);
    //textArea.setAlignmentY(Component.BOTTOM_ALIGNMENT);


    JScrollPane scrollPane = new JScrollPane(textArea);

    //scrollPane.setAlignmentY(JScrollPane.BOTTOM_ALIGNMENT);
    //Add Components to this panel.
    GridBagConstraints c = new GridBagConstraints();
    c.gridwidth = GridBagConstraints.REMAINDER;

    c.fill = GridBagConstraints.BOTH;`

    c.weightx = 1.0;
    c.weighty = 1.0;
    add(scrollPane, c);

    c.fill = GridBagConstraints.HORIZONTAL;
    add(textField, c);

    //add(textArea, BorderLayout.SOUTH);
}

public void actionPerformed(ActionEvent evt) {
    SimpleAttributeSet sas = new SimpleAttributeSet();
    StyleConstants.setAlignment(sas, StyleConstants.ALIGN_RIGHT);
    StyleConstants.setForeground(sas, Color.WHITE);
    String text = textField.getText();
    Document doc = textArea.getStyledDocument();
    try {
        doc.insertString(doc.getLength(), text + newline, sas);
    } catch (BadLocationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //textArea.append(text + newline);
    textField.setText("");

}

private static void createAndShowGUI() {
    //Create and set up the window.
    JFrame frame = new JFrame("TextDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Add contents to the window.
    frame.add(new TextDemo());

    //Display the window.
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    TextDemo.createAndShowGUI();
}
}

通过谷歌搜索就能找到令人惊奇的东西。

所以,下面的例子是基于Centering text vertically in JEditorPane的。该示例确实在视图底部留下了一条 "blank" 行,我相信只要稍作努力,您就可以弄清楚如何删除它,但这将为您提供一个起点。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.ParagraphView;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int lineCount = 0;

        public TestPane() {
            setLayout(new BorderLayout());
            JTextPane tp = new JTextPane();
            tp.setEditorKit(new MyEditorKit());
            add(new JScrollPane(tp));

            JButton btn = new JButton("Add");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        Document doc = tp.getDocument();
                        int end = doc.getLength();
                        doc.insertString(end, (++lineCount) + " some more text\n", null);
                    } catch (BadLocationException ex) {
                        ex.printStackTrace();
                    }
                }
            });

            add(btn, BorderLayout.SOUTH);
        }

    }

    class MyEditorKit extends StyledEditorKit {

        public ViewFactory getViewFactory() {
            return new StyledViewFactory();
        }

        class StyledViewFactory implements ViewFactory {

            public View create(Element elem) {
                String kind = elem.getName();
                if (kind != null) {
                    if (kind.equals(AbstractDocument.ContentElementName)) {

                        return new LabelView(elem);
                    } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                        return new ParagraphView(elem);
                    } else if (kind.equals(AbstractDocument.SectionElementName)) {

                        return new CenteredBoxView(elem, View.Y_AXIS);
                    } else if (kind.equals(StyleConstants.ComponentElementName)) {
                        return new ComponentView(elem);
                    } else if (kind.equals(StyleConstants.IconElementName)) {

                        return new IconView(elem);
                    }
                }

                return new LabelView(elem);
            }

        }
    }

    class CenteredBoxView extends BoxView {

        public CenteredBoxView(Element elem, int axis) {

            super(elem, axis);
        }

        protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {

            super.layoutMajorAxis(targetSpan, axis, offsets, spans);
            int textBlockHeight = 0;
            int offset = 0;

            for (int i = 0; i < spans.length; i++) {

                textBlockHeight += spans[i];
            }
            offset = targetSpan - textBlockHeight;
            for (int i = 0; i < offsets.length; i++) {
                offsets[i] += offset;
            }

        }
    }
}

奇迹发生在 layoutMajorAxis 方法中