I'm writing a text editor in Java, using Swing. My main component that I use to enter the text is JTextPane. I know how to bold selected text, but I'd also like just to press bold and have new text formatted. Here's my code:
static void boldSelection(JTextPane editor, JButton button){
StyledDocument doc = (StyledDocument) editor.getDocument();
int selectionEnd = editor.getSelectionEnd();
int selectionStart = editor.getSelectionStart();
if (selectionStart == selectionEnd) {
return;
}
Element element = doc.getCharacterElement(selectionStart);
AttributeSet as = element.getAttributes();
MutableAttributeSet asNew = new SimpleAttributeSet(as.copyAttributes());
StyleConstants.setBold(asNew, !StyleConstants.isBold(as));
doc.setCharacterAttributes(selectionStart, editor.getSelectedText().length(), asNew, true);
}
It works, but I have no idea how to change it, since I have to pass the length to setCharacterAttributes.
To be clear:
that's what I have:
Bolding selected text
and that's what I want to do:
Entering bolded text
The EditorKit used by the JTextPane supports a Bold Action along with other common actions the might be used by an editor. So you don't need to write any special code, only create a Swing component to use the Action.
Check out the section from the Swing tutorial on Text Component Features for a working example.
The tutorial example only use menu items but you can also use the Action to create a JButton to add to a JToolBar.
Related
I am making a small Swing application and have a JTextarea where I want a part of the text to be highlighted.
When I start my appl. the line that I indicated to be highlighted is highlighted by the method "highlight()"
public static void highlight() {
uihw.getTa().setSelectionStart(indexTxt[pencil]);//uihw is the ui instvar that has the jTextarea
uihw.getTa().setSelectionEnd(indexTxt[pencil]+lines[pencil].length());
}
As seen here:
Now, the moment I hit a Button ,it should select the next item below and highlight it.
public static void buttonClicked(String f){
if (pencil!=lines.length-1){
pencil++;
}
highlight();
}
And this is where the highlighting stops working.
I can go through the list up until the end (so I am sure the selection is actually done) but the text isn't highlighted anymore.
Any ideas on the why? Or suggestions for a better implementation of my highlighting feature?
Selections may not be visible if the component loses focus. Instead you can use the Highlighter of the Component:
HighlightPainter highlightPainter = DefaultHighlighter.DefaultHighlightPainter(Color.BLUE);//
Highlighter highlighter = textArea.getHighlighter();
highlighter.addHighlight(start, end, highlightPainter);
If you wish the color to be the same as a selection color, you can use
HighlightPainter highlightPainter = DefaultHighlighter.DefaultPainter;
or specify the selection color via the Look and feel
HighlightPainter highlightPainter = DefaultHighlighter.DefaultHighlightPainter(UIManager.getColor("TextArea.selectionBackground"));
I am trying to implement a text editor in NetBeans with simple functions like: text styling (bold, italic, underlined ...), open file, save file and search. Search function searches for a specified string in the document and highlights the results. The problem occurs when I am trying to remove those highlights or add new ones for different search. Currently I use StyledDocument object together with jTextPane.
private void textHighlight(int startAt, int endAt, Color c) {
Style sCh;
sCh = textEditor.addStyle("TextBackground", null);
StyleConstants.setBackground(sCh, c);
StyledDocument sDoc = textEditor.getStyledDocument();
sDoc.setCharacterAttributes(startAt, endAt - startAt, sCh, false);
}
private void textFind(java.awt.event.ActionEvent evt) {
int searchIndex = 0;
String searchValue = searchField.getText();
if(lastIndex != -1) {
while(searchIndex < lastIndex) {
countOccurencies++;
int i = textEditor.getText().indexOf(searchValue, searchIndex);
textHighlight(i, i+searchValue.length(), Color.MAGENTA);
searchIndex = i+searchValue.length();
}
statusLabel.setText(countOccurencies + " rezultatov.");
} else {
statusLabel.setText("Ni rezultatov!");
}
}
}
private void searchEnd(java.awt.event.ActionEvent evt) {
textEditor.removeStyle("TextBackground");
}
removeStyle() doesn't seem to be working.
Must admit I don't know how Styles work, but maybe the attributes of the Style are copied to the Document at the time you add the Style?
Another option is to use the Highlighter class. See textPane.getHighlighter(). Then you can keep track of the individual highlights you add in an ArrayList and then use the ArrayList to remove the highlights when you want the clear the text pan.
Also, inside your search loop you have a couple of problems:
Don't use the getText() method. This can cause problems with text offsets being off by one for every line of text in the text pane. See Text and New Lines for more information and the solution.
You are getting the text inside the loop which is not very efficient. You should only get the text once outside the loop.
public class Text extends JPanel {
private String text;
public Text()
{
this.setPreferredSize(new Dimension(20,20));
setFont (new Font(text, Font.PLAIN, 24));
text = "";
}
public void showUnderline()
{
Hashtable<TextAttribute, Object> map = new Hashtable
<TextAttribute, Object>();
map.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
}
the text object will be created within another class. in that class I will need to underline it with the showUnderline method. The method seems incomplete.I'm shooting for the java exclusive approach, meaning no HTML.
How do I link the text to the showUnderline method?
What do you mean 'java exclusive approach, meaning no HTML' ? You probably are looking for a JLabel, and you can put very simple html in it. Here's the first result on google:
http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-JLabel.html
It has an example of making text different colors, fonts, and bold or italicized. You could probably just do something like:
JLabel label = new JLabel("<u>MY TEXT</u>",JLabel.CENTER);
From there, you can place it like you would place any other JComponent.
If you really don't want HTML, you could use a JTextPane. Here's an example:
http://www.exampledepot.com/egs/javax.swing.text/style_hilitewords2.html
Is it possible to enable the selection of text from a JLabel? If not, what's the best alternative control to use, and how can it be configured to appear like a JLabel?
A JTextField doesn't allow html-formatted text like a JLabel. If you want selectable html text you could alternatively try a JTextPane set to html formatting:
JTextPane f = new JTextPane();
f.setContentType("text/html"); // let the text pane know this is what you want
f.setText("<html>Hello World</html>"); // showing off
f.setEditable(false); // as before
f.setBackground(null); // this is the same as a JLabel
f.setBorder(null); // remove the border
You can use a JTextField without enabling the editing
JTextField f=new JTextField("Hello World");
f.setEditable(false);
content.add(f);
Pierre
Building on the answers:
You can use a JTextField without enabling the editing
JTextField f=new JTextField("Hello World");
f.setEditable(false);
f.setBackground(null); //this is the same as a JLabel
f.setBorder(null); //remove the border
I don't know how to stop the text from "Jumping" when you select it, or replace the text (programmatically). Maybe it is just my computer...
When using JTextField, you will also want to remove the border:
f.setBorder(null);
and set the disabled text color: f.setDisabledTextColor(Color.black);
As variant below CopyableLabel supports html tags and Fonts as JLabel.
public class CopyableLabel extends JTextPane {
private static final long serialVersionUID = -1;
private static final Font DEFAULT_FONT;
static {
Font font = UIManager.getFont("Label.font");
DEFAULT_FONT = (font != null) ? font: new Font("Tahoma", Font.PLAIN, 11);
}
public CopyableLabel() {
construct();
}
private void construct() {
setContentType("text/html");
setEditable(false);
setBackground(null);
setBorder(null);
putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
setFont(DEFAULT_FONT);
}
}
JLabels cannot be editable.
However, you could use a JTextField and just change the foreground / background colors to make it appear as a JLabel. If you wanted to be really fancy you could add code to change the colors when it's selected to indicate that it's editable.
Besides the changes suggested in other responses (setEditable, setContentType, setOpaque or setBackground, maybe setEnabled + setDisabledTextColor(Color.black), maybe setBorder(null) and/or setMargin(new Insets(0,0,0,0))
To get the font of a JTextPane to look like a JLabel, see the suggestion from this blog post:
"Unfortunately, simply calling set font on JEditorPane will have no effect, as the default font is pulled from a style sheet rather than the JComponent. There is, however, a clever way around the errant font default. The best way to change the default font in an HTML rendering JEditorPane, is to alter the style sheet like this:"
// create a JEditorPane that renders HTML and defaults to the system font.
JEditorPane editorPane =
new JEditorPane(new HTMLEditorKit().getContentType(),text);
// set the text of the JEditorPane to the given text.
editorPane.setText(text);
// add a CSS rule to force body tags to use the default label font
// instead of the value in javax.swing.text.html.default.csss
Font font = UIManager.getFont("Label.font");
String bodyRule = "body { font-family: " + font.getFamily() + "; " +
"font-size: " + font.getSize() + "pt; }";
((HTMLDocument)editorPane.getDocument()).getStyleSheet().addRule(bodyRule);
I'm developing a an eclipse plugin that uses an SWT interface. I need to display text, and within that text there needs to be links. The only two widgets that I've found that will allow me to include clickable links in text are Link and Browser. Browser, however, is overkill for my needs, and I couldn't properly customize the look of it. This only leaves the Link widget.
The problem is I need the Link widget to inherit a gradient from the Composite in which it is in. It does this correctly, only when it is resized or scrolled the Link component flickers. The Link is the only component in which I have seen this effect.
In an attempt to fix this I've tried manipulating other components into having clickable links, but I haven't found a good solution yet.
Is there anyway to fix the flickering effect on the Link, or is there a different component which would support links?
Thanks,
Brian
After spending the day working on this, I came up with a workaround. I created a Composite for the text area. For each word that isn't part of a url,got its own label. For links, each letter got its own label. Then the labels for the url characters got a listener to launch a browser. Using this method provided the Link functionality, handled resizing properly, and has no flicker.
Have you tried passing SWT.NO_BACKGROUND to your Link widget? It might get a little strange... and you may have to do a little more work to get the gui drawing properly, but that would be my first guess.
Other than that, here's my Quick n' dirty implementation of a link inside of a StyledText. You will need to fill in for changing the cursor (if that's something you want), as well as coming up with a good "text to link" mapping scheme.
The only thing is I'm not sure if StyledText will inherit your background... give it a shot.
public class StyledTextExample {
public static void main(String [] args) {
// create the widget's shell
Shell shell = new Shell();
shell.setLayout(new FillLayout());
shell.setSize(200, 100);
Display display = shell.getDisplay();
// create the styled text widget
final StyledText widget = new StyledText(shell, SWT.NONE);
String text = "This is the StyledText widget.";
widget.setText(text);
widget.setEditable(false);
final StyleRange hyperlinkStyle = new StyleRange();
String linkWord = "StyledText";
hyperlinkStyle.start = text.indexOf(linkWord);
hyperlinkStyle.length = linkWord.length();
hyperlinkStyle.fontStyle = SWT.BOLD;
hyperlinkStyle.foreground = display.getSystemColor(SWT.COLOR_BLUE);
widget.setStyleRange(hyperlinkStyle);
widget.addMouseListener(new MouseAdapter() {
public void mouseUp(MouseEvent arg0) {
Point clickPoint = new Point(arg0.x, arg0.y);
try {
int offset = widget.getOffsetAtLocation(clickPoint);
if (widget.getStyleRangeAtOffset(offset) != null) {
System.out.println("link");
}
} catch (IllegalArgumentException e) {
//ignore, clicked out of text range.
}
}});
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch()) display.sleep();
}
}