I am creating a Help System that uses links (a JButton extension) that expand and collapse subpanels with JLabels in them. The links and the collapsible panels work, but I'm having trouble implementing my find dialog. I want to be able to highlight parts of the text for which the user searches. I think my use of text attributes to underline the text in the links is messing with my ability to highlight the parts of the text, but I'm not sure how to do it differently. Here's the code for my Link class which my links subclass:
public abstract class Link extends JButton {
private static final int SPACE = 5;
private static final Color TEXT_COLOR = Color.BLUE;
public Link(String text) {
super(text);
setBorder(BorderFactory.createEmptyBorder(SPACE, SPACE, SPACE,
2 * SPACE));
setContentAreaFilled(false);
setFocusable(false);
setForeground(TEXT_COLOR);
Map<TextAttribute, Integer> underlineAttribute =
new HashMap<TextAttribute, Integer>();
underlineAttribute.put(TextAttribute.UNDERLINE,
TextAttribute.UNDERLINE_ON);
setFont(getFont().deriveFont(underlineAttribute));
}
}
How can I implement highlighting text in my links without getting rid of the underlining? Do I need to change them to subclass something else?
One approach is to use HTML formatting for the button text. Of course, the path of least surprise for the end user would be if the buttons looked like buttons and the links looked like links (i.e. not buttons).
Should I subclass something else for the links?
For a link I'd generally use a JTextField, as shown on my answer to How to change JButton?
E.G.
Related
In Javafx there is an option to set colors/styles for buttons e.g.,
button.setStyle("-fx-background-color: red");
Is there any syntax for checking a buttons style for witch color the button has?
Basically I want to do something like:
if (button.style("-fx-background-color: red")) {
something....
}
Yes, you can do it via .contains() or via regular expression (.matches()) by using getStyle() (for example, in your case, it would be button.getStyle().contains("-fx-background-color: red").
However, keep in mind that both setStyle() and getStyle() only refer to inline styles. Therefore, they will not include the styles that are passed via CSS selectors in attached CSS files.
Generally, using visual properties for determining semantic properties is not considered a good practice. If you have buttons that are supposed to exhibit a particular behavior, consider extending the Button class and adding those as proper properties instead.
Button button = new Button();
String[] styles = button.getStyle().split(";");
for(String style : styles){
if(style.contains("-fx-background-color")){
String color = style.split(": ")[1]; // the color of the button
}
}
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.
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 want to highlight the lines which are errors while validating, I am currently using jtextarea, looked into jtextpane and styles, i need some suggestions in implementing like the below way. Should i have to take jtextarea or jtextpane or any other best and easy option? thanks
private void validate(String text){
lines = text.split("\n");
for(String line : lines){
if(line.substring(0, 1).equals("")){
//want to highlight the entire line in red color
} else {
//remove the highlight
}
}
}
Use
textarea.getHighligter().addHighlight()
See the doc DefaultHighlighter and Demos and Usage of DefaultHighlighter
JTextArea will certainly not work as it only supports plain text. You will need a JTextPane. A handy overview (as I always forget which one does what) can be found in the Swing tutorial
For your validation, I would add a DocumentListener which validates the input and changes the color depending on the state.
I am trying to reproduce the behavior of a spreadsheet cell using GWT. I was able to make a Composite widget called "Cell" which is by default a "Label" widget. When a user clicks on this widget, it becomes a "TextBox" widget. On a blur event, the widget becomes a "Label" widget once again.
My question concerns efficiency and rendering time. It would probably be easiest to just make my "Cell" a "TextBox" and just change the appearance to the user via CSS (according to whether they are entering data or not). However, I think that this will affect rendering time and so I revert to a "Label" widget whenever input is not necessary. The problem with this method, however, is that I am basically creating a new TextBox/Label each time the user needs to enter anything into the "Cell".
Here is my pseudo-code (since I am not around an IDE)...
public class Cell extends Composite {
private SimplePanel sp;
public Cell() {
Label l = new Label("");
sp.add(l);
}
private void switchMode() {
Widget w = sp.getWidget();
if (w instanceof Label) {
// we have a Label, change it to a TextBox
String text = ((Label) w).getText();
sp.remove(w);
sp.add(new TextBox(text));
// force garbage collection
w = null;
} else {
// we have a TextBox, change it to a Label
String text = ((TextBox) w).getText();
sp.remove(w);
sp.add(new Label(text));
// force garbage collection
w = null;
}
}
...
When there is a onBlurEvent on the TextBox or when there is an onClick event on the Label, the switchMode() method is called. Critiquing of code is welcomed.
Would it instead be smarter to include a TextBox and Label as private variables of the Cell class, and then just add or remove the corresponding object as needed?
We met similar problem: efficient display of excel-like table (a lot of rows and cols, each cell in-place editable).
The final solution was: render the table as string: each cell is rendered just as text, put all via innerHTML.
When the user selects a cell with mouse or keyboard, special hidden TextArea appeared over the selected cell (with the same size) and focus gives to the TextArea. OnBlur - text entered goes back to the cell and the TextArea is hidden again.
We use no widgets for cells. The TextArea is only one for the whole table.
See also
"Effective GWT: Developing a complex, high-performance app with Google Web Toolkit"
http://code.google.com/events/io/2009/sessions/EffectiveGwt.html
An even easier way would be to have both of them added to your panel (not simplePanel though), and use setVisable methods to alter visability.