I'm new to Java and I started a little RPG game. When a battle starts, I would like to display the battle messages in a little box. I would like the box to be scrolled automatically, displaying the new message every time, and not losing the old messages.
I am going to give you the information you need, but it is your duty to figure out how to use them:
1-you should use a JTextArea to display your messages.
2-when a new message come, use the append() function on you JTextArea object (use \n to return automatically in line).
3-add a JScrollPane to your JTextArea so it can be scrollable.
4-update you caret automatically to always show the last message printed use this where myJTA is your JTextArea:
DefaultCaret caret = (DefaultCaret)myJTA.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
now you have all the pieces of the puzzle.
Good luck.
EDIT:
if you want your JTextArea not editable use:
myJTA.setEdtable(false);
Related
So im creating a server, and that works great, however I am a bit stuck on the GUI. You see, I would like it to look just like Command Prompt, where only the next line is editable, and it does not let you delete any other text. So right now I have:
JTextArea ta = new JTextArea();
JScrollPane sp = new JScrollPane(ta);
Then the frame stuff...
f.setTitle("Server");
f.setBounds(ss.width - 600, 50, 550, 350);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);//added window listener so closes socket connection first
f.setAlwaysOnTop(true);
Then adding it:
f.add(sc);
jt.setBackground(Color.BLACK);
jt.setForeground(Color.WHITE);
//jt.setEditable(false);
Finally, the method I use to output to the TextArea:
public static void append(String text) {
jt.append(text);
jt.append("\n\n"+System.getProperty("user.name")+" / "+getIp()+" > ");
jt.setCaretPosition(jt.getDocument().getLength());
}
Now I need to assign a String to what the user types into the JTextArea after they press enter:>?
jt.addActionListener(...{
public void ActioEvent(ActionEvent e){
String text = JTextArea.getLines().getLastLine().getText().replace(System.getProperty("user.name")+" / "+getIp()+" > ", "");
}
});
Maybe something like that?
Then I need to have it so that only the part after the ">" is editable?
The way to do this is with a DocumentFilter. This is a fairly obscure and little-used part of Java, and is far from easy to use. However it allows you to insert a DocumentFilter between the UI (where rich text content is edited) and the underlying model (the content). You pass all the 'insert' and 'remove' operations through the filter, which can either accept, refuse or modify them. You can code the filter to only permit modifications to the command line, and not to the prompt.
As I say, this is a pretty hard piece of coding, and the Document/DocumentFilter structure has a lot of complexity that your particular application doesn't need. However it does provide you with the facilities you need.
There is a tutorial in the standard Java doc pages, but not an advanced one, and very few examples that I know of are out there on the web.
ProtectedTextComponent (thanks camickr) provides an example of how to do something similar.
Use a Collection a JTextField.
Let the user type on a JTextField, and once he presses enter, move the control to the next JTextField while making the above JTextField uneditable and also remove the JScrollPane from it.
Hope this helps.
I also agree that the JTextArea/JTextField approach is the common and simpler approach.
However if you want to complicate your life a little then you can check out Protected Text Component which will do most of the logic for you.
The current implemtation of the ProtectedDocument only allows you to add protection to the Document, not remove it so the first thing you will need to do is add a method to "Clear" all the protect pieces of text. This is easy enough, you just clear the entries in the Map used by the class.
Next you will need to replace the default "Enter" Action used by the JTextPane. You do this by playing with the Key Bindings of the text area. See Key Bindings for some basic information. In your custom Action you would first need to invoke the newly created "clear(...)" method. Then you would add you text to the text area. Finally you would protect all the text but the last "x" number of characters.
I'm making a program in java that recive some strings and then display them in a new frame scolling them in one line, like the news, (shown below)
There, the text are displayed in a line, like what I need, but my problem is that I don't know what I should use in java, I though about put a panel on a frame and then a textfield inside the panel, then I realize that it's impossible because for every message I may need to change the color of background for an highlight message...
So, if anyone can help me, can you tell me what should i use for the diferent message and how i can get the text scrolling?
Thank you all in advance!
I am writting a simple server chat client using gui to make the chat box and so on. I am simply wondering if I should use jtextarea instead of jtextfield if someone wants to write a long message since jtextfield does not allow word wrap.
Does it matter if I use jtextarea of jtextfield or is there a specific reason not to use jtextarea as my input box?
My guess:
You'll probably need both a JTextField and a JTextArea (or other multi-line text component).
The JTextField would be for the user to type in their chat messages to be sent. It would be editable.
and the JTextArea would show the incoming chats as well as the chats the user has sent. It would not be editable.
Consider placing the JTextArea in a JScrollPane
Consider placing both in a BorderLayout-using container with the JScrollPane that holds the JTextArea placed in the CENTER position and the JTextField in the SOUTH position.
A JTextField is a little easier to work with. You can add an ActionListener to it so that when the user hits enter the Action can be invoked an the message will be sent. Of course you can still have a "Send" JButton. the user can click on as well.
With a JTextArea, the Enter key will add a new line, so it you want the user to be able to sent the text when Enter is used you will need to customize the processing, maybe by using Key Bindings. I would prefer the text area because I like to see as much of the text as possible, like I am doing now as I repond to this question.
From oracle docs and personal experience, the JTextField makes life a lot easier as the ActionEventListener is set by default so the actions(characters or text) set in the field are copied to the JTextArea which is like a log of activity carried out in the field.
So the ball is in your court. You can use it JTextField together with JTextArea or JTextArea alone and write the listener class to suit you purpose and certainerly added a listenable event e.g a button.
Besides, always specify the size of the field to avoid layout issues that may compromise the Ui of your application as there is always a dynamic resizing if the size is not specified out rightly.
In fact I just start actively practise swing in order my theoretical knowledge comes handy :) I've already done a lot for chat GUI implementation but at the end stuck with some issues. So I decided to rework chat GUI from scratch, but I need to make right choice of components for it.
At first, I must say that there's no "input" functionality in the first implementation.
My current chat implementation consists of the following components:
JScrollPane to scroll up/down messages
Each message is the JPanel with JLabel inside. JLabel works great with HTML so it is easy to change smiles tokens to . Also message constructs from two strings: sender's name and message. So again, support of HTML in JLabel lets us mark sender's name with tag.
The reasons I think I'm stuck and chat GUI should be reworked from scratch:
JLabel works with HTML but if you use JScrollPane.HORIZONTAL_SCROLLBAR_NEVER, there's no more words wrap in it. Replacement of JLabel with JTextArea isn't good idea, cause JTextArea doesn't work with HTML.
There's no possibility to scroll down scrollbars automatically when new message is added. At least I didn't manage to do it.
It is difficult to control amount of components (JPanels with JLabels) to delete old ones when new message received from server. Otherwise it is possible to create hundreds of JPanels with JLabels in ten-fifteen minutes in an active chat. WeakReference is good here but usage of JPanel + JLabel for each message is bad design from the very beginning.
There're some other issues but they're not so critical and couldn't influence "rework decision".
I'd greatly appreciate if you could give a hint what components do suit well for such application like chat based on "reasons" described above.
Your design is bad and you should feel bad.
Try to copy some text from a bunch of JLabel displayed contiguously.
Just use a JTextPane or something like that! This function is from a program of mine, in a class that extends JTextPane, it adds some text at the end, with some peculiar style. You can modify it to do whatever you need.
public void append(String append,Color fg,Color bg, boolean bold,boolean italic, boolean underline) {
try {
// Get the text pane's document
StyledDocument doc = (StyledDocument)this.getDocument();
// The color must first be wrapped in a style
Style style = doc.addStyle("StyleName", null);
StyleConstants.setForeground(style, fg);
StyleConstants.setBackground(style,bg);
StyleConstants.setBold(style,bold);
StyleConstants.setItalic(style,italic);
StyleConstants.setUnderline(style,underline);
// Insert the text at the end of the text
doc.insertString(doc.getLength(), append, style);
} catch (Exception e) {
e.printStackTrace();
}
this.setCaretPosition (this.getDocument().getLength()-1);
}
I have a few text areas that are filled with loops of information. Is it possible to make it 'jump' or scroll back to the top automatically after the loop has completed, so that the user sees it from the start and not the end?
You can use setCaretPosition() to set the cursor at position 0 of the TextArea. That usually works for me.
Use setUpdatePolicy with NEVER_UPDATE, and make sure the setUpdatePolicy comes before setting any text to the JTextArea. In my example I initialize a JTextArea without any text and call setUpdatePolicy right after.
JTextArea jTextArea = new JTextArea();
((DefaultCaret)jTextArea.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
I have solved this problem by creating a new TextArea which acts as a sort of buffer (and isn't displayed). The loop writes to this area and when completed gets the text from that and sets it to the required TextArea.