I'm working on a simple text adventure game, which should allow the user to enter text and get their response, much like a simple command prompt.
For various reasons, I'm trying to use a JPanel window and some other stuff so that I can control how the content is displayed. Below is the code I have so far.
I'm having some problems, however: the text in the JTextPane aligns to the top of the window instead of the bottom, and the text isn't scrollable. Basically, the text you've just entered should appear above the text entry box just like a command prompt, and old text should be scrollable. Does anyone know how I should fix this?
Thanks in advance.
Minor edit: here's a screenshot of what it currently looks like.
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();
}
}
Amazing what you can find with some googling.
So, the following example is based on Centering text vertically in JEditorPane. The example does leave a "blank" line at the bottom of the view, which I'm sure with a little effort, you can figure out how to remove it, but this will give you a jumping off point to start with.
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;
}
}
}
}
The magic happens in the layoutMajorAxis
method