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);
}
Related
I have a bit of an unusual problem:
I have a swing label that updates for "Used letters" in the game Hangman. I have it declared like this:
used = new JLabel(" Used: ");
But then i have another area in the code where i add onto it. Here:
used.setText(used.getText() + lUsed + " , ");
Now when the user enters letters, it updates the label and the letters are added, but if you enter enough, they push the rest of the contents of the frame out of view. The label expands the WEST side of my borderlayout so much that everything else get's pushed and then some times cut off the application window.
Is there a good way to use HTML to make it so that it word wraps the text and does not change the panel (what it's contained in) size?
GridLayout c = new GridLayout(rows,0);
westPanel = new JPanel(c);
westPanel.add(guessedPanel);
westPanel.add(usedPanel);
frame.getContentPane().add(westPanel, BorderLayout.WEST);
How it's laid out ^^
For a more general solution for those coming from Google, you can add HTML to Swing components very easily, as long as the content being added starts and
ends with the proper HTML tags.
For example, you may insert HTML text into a JLabel such that:
label.setText("<html> Text </html>");
You could color center it and underline the first letter like this:
label.setText("<html><center><u>T</u>ext</center></html>");
Here's a good tutorial on how to use HTML in your Swing components.
--
For your specific solution, you can simply use HTML when adding text to the label. Instead of using used.getText() you should store the text in a String somewhere (that does not enclose the opening and closing HTML tags), and update that String, in order to be able to effectively manage the opening and closing HTML tags. So it could go something like this
String text; // Earlier in the code
...
text += ("<br> " + lUsed);
used.setText("<html>" + text + "</html>")
Among other things, you could attempt setting a preferred or maximum size of the label so that it is not allowed to become to large. Also, you could make the label a text panel or text area of some kind instead, which would automatically support word wrapping, scrolling, and other features that you may want.
Here's a guide on how to use JTextAreas.
Specify a width in styles for the body tag of the HTML. See Text Wrap in JOptionPane for an example.
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);
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 am designing a Jframe using netbeans. I do have few questions.
Can we create a label for a field in a desired location(For eg.,we have a field named height, I need to display a label below it indicating height is in cm) conditionally?
Can we disable a field based on a condition?(by disable I mean it shouldn't be displayed in my frame)
Can someone suggest me whether we can achieve them through some examples.
Tried this, after some helpful suggestions
private void englishRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
JLabel userlabel;
if (englishRadioButton.isSelected())
{
userlabel = new JLabel("Inches");
userlabel.setBounds(311, 59, 64, 36);
//userlabel.setLocation(307,55);
//userlabel.setSize(70,40);
userlabel.setForeground(Color.green);
userlabel.setText("Inches");
userlabel.setVisible(true);
System.out.println(englishRadioButton.getBounds());
inchesTextField.setVisible(true);
}
}
The textfield is visible only when I click the English radio button,at the same time I need to get a label but it's not displayed with the above code. Can I know where I am going wrong?
Please see the attached screenshots
When English button is clicked, I need a label beneath the second textfield as inches, I am disabling the text field when Metric is displayed. I am able to achieve the later one but not the former one
Thanks!!
Yes, relative placement of components is easily achieved with use of layout managers.
Yes, all components have a setEnabled(...) and a setVisible(...) method either of which can be called at any time during a program's run. The former helps you activate/inactivate components and the latter helps make them visible/invisible. If you want to swap complete "views", use a CardLayout.
Regarding:
Can someone suggest me whether we can achieve them through some examples.
Please, you first as I strongly believe that the onus of effort here should be yours, the questioner's, since you're the one asking the questions, and the one with the most to learn by coding as much as possible. Let's see your attempts and we can help you with them. Otherwise the best examples are to be found at the Swing Tutorials.
For links, please look here: Swing Tag Info.
Edit
You ask:
I tried the above posted code,conditionally disabling the text field works well but getting a label doesn't work. Can you please suggest on that?
I don't see you adding your JLabel to any component. If you are going to create a component on an event, you must add it to a component whose ancestor hierarchy eventually reaches a visible top-level component such as a JFrame. Then after adding a component to a container (say a JFrame), you must call revalidate() on the container to have its layout managers re-layout its components, and then repaint() to repaint any "dirty" pixels.
I again will re-iterate that you're far better off not using null layout and absolute positioning, but rather using layout managers and relative positioning. If you want a label with and without visible text, it's often best to add an empty JLabel to the GUI on GUI creation, and just set its text when needed, as long as the label is located somewhere that allows its text to shrink and expand.
Also, as to your current problem, you might wish to show a picture of what you're trying to achieve, and what you're getting. Or if you can't post a picture here yet, post a link to an image or images you've created, and then we'll post it for you.
I'm building a program in Java, using Swing, that will act as an interactive presentation.
I have paragraphs I need to display (presumably in JLabels) , and within each paragraph are certain words and phrases that need to be formatted differently (have a different color), and I need them to call a method that will display something else when clicked or hovered over.
I know there must be a way to accomplish this...
If you want to apply some style, you can use HTML in your JLabel's content.
If you need some custom behavior and you want to handle it in a different way for some parts of your JLabel, you need your component to be split in a more detailed way.
Create a container(JPanel) and arrange you components within it. From now, your smaller components will be able to listen for events like mouseEntered and mouseClicked and handle them separately, not confusing the whole JLabel component.
In this way, every smart part of text will be a standalone component.