I've come across unusual problem in Java (1.7 JRE), and I can't find a solution.
I am using JTextArea to write text in it, in form of decimal number, for example 123.4 with right to left orientation. Every time I enter "." in turns up at the beginning of the text, like this .123 and when I enter next number it shows up like it should 123.4
It happens both when I try entering numbers with keyboard and via JButtons using method I wrote. Here's the part of the code:
String number;
JTextArea textAreaUnos;
.
.
.
number=number+".";
textAreaUnos.setText(number);
I've also tried writing it like this:
textAreaUnos.append(".");
but the result is the same when I type, for example
123
.123
123.4
In left to right orientation, this is not happening.
Has anyone had problem like this before, and have you managed to solve it?
One work around is using JTextPane or JEditorPane. Below is an example of JTextPane.
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
class Demo{
public static void main(String[]args){
SwingUtilities.invokeLater(()->{
JFrame frame=new JFrame("Right-Left");
JTextPane box=new JTextPane();
frame.getContentPane().add(box);
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setAlignment(attr, StyleConstants.ALIGN_RIGHT);
box.setParagraphAttributes(attr, true);
frame.setSize(300,200);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
});
}
}
Indeed when you append with RIGHT_TO_LEFT a string which start o ends with a non digit nor letter the output is wrong (i.e 123. gets converted to .123)
I managed to append it right by checking if character is .isLetterOrDigit and append to Start or End depending on the check. I know it's tricky but it was the only solution i found.
Main:
import java.awt.ComponentOrientation;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Main extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextArea t1 = new JTextArea("", 10, 15), t2;
public Main() {
Box b = Box.createHorizontalBox();
b.add(new JScrollPane(t1));
t2 = new JTextArea(10, 15);
t2.setEditable(false);
b.add(new JScrollPane(t2));
add(b);
setSize(425, 200);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t2.setComponentOrientation ( ComponentOrientation.RIGHT_TO_LEFT);
t1.addKeyListener ( new KeyListener( )
{
#Override
public void keyTyped ( KeyEvent e )
{
}
#Override
public void keyReleased ( KeyEvent e )
{
char check = (char)e.getKeyCode ( );
if(Character.isLetterOrDigit ( check ) )
{
t2.setText ( t1.getText ( ).substring ( 0 , t1.getText ( ).length ( )-1 ) + check);
}
else
{
t2.setText ( check + t2.getText ( ) );
}
}
#Override
public void keyPressed ( KeyEvent e )
{
}
});
}
public static void main(String args[]) {
new Main();
}
}
Test:
Related
I have a quick question about implementing my SpellChecker into my Swing Text Editor. I tried to search around but couldn't find anything on how to get the red squiggly line under misspelled words. Is there something I could import then call on those misspellings? Also, how would I be able to make a menu pop up when I right-click on those miss spelled words? Thanks
There is plenty of material out there depending on what you want to do...
First of, use a JTextPane, which supports nice text formatting options.
How to underline text:
Comments are included as explanations.
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
public class WordUnderline {
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final Style defaultStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
final JTextPane pane = new JTextPane();
//My super-creative text...
pane.setText("These are words...\nHere come more words!\nWord word word.");
final StyledDocument doc = pane.getStyledDocument();
doc.addDocumentListener(new DocumentListener() {
private void clearStyle(final DocumentEvent e) {
SwingUtilities.invokeLater(() -> doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, true));
}
#Override
public void insertUpdate(final DocumentEvent e) {
//When you type a new letter, we want to (lets say) clear all the styles from the whole document...
clearStyle(e);
}
#Override
public void removeUpdate(final DocumentEvent e) {
//When you erase a letter, we want to (lets say) clear all styles from the whole document...
clearStyle(e);
}
#Override
public void changedUpdate(final DocumentEvent e) {
//When changing the style of the document, we want to do nothing else (but the change will happen).
}
});
final JButton doit = new JButton("Underline selected text!");
doit.addActionListener(e -> {
final SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setUnderline(sas, true);
/*I would suggest here to experiment a bit with the StyleConstants
class... For example: StyleConstants.setBackground(sas, Color.RED);*/
final int start = pane.getSelectionStart();
final int end = pane.getSelectionEnd();
doc.setCharacterAttributes(start, end - start, sas, true);
});
final JPanel contents = new JPanel(new BorderLayout());
contents.add(doit, BorderLayout.PAGE_START);
contents.add(pane, BorderLayout.CENTER);
final JFrame frame = new JFrame("Word underline.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
How to pop a menu on word selection:
Comments are included as explanations.
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
import javax.swing.text.Utilities;
public class WordPopUp {
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final JTextPane pane = new JTextPane();
//My super-creative text...
pane.setText("These are words...\nHere come more words!\nWord word word.");
pane.addMouseListener(new MouseAdapter() {
private boolean pendingPopUp = false; //Indicates whether we have already a popup popped up...
private void pop(final MouseEvent mevt) {
if (SwingUtilities.isRightMouseButton(mevt)) {
try {
final StyledDocument doc = pane.getStyledDocument();
//Get the location of the document where the user clicked:
final int offset = pane.viewToModel(mevt.getPoint());
//Find what word is at the location of the document where the user clicked:
final int start = Utilities.getWordStart(pane, offset),
end = Utilities.getWordEnd(pane, offset);
//Set the selection to be that word:
pane.setSelectionStart(start);
pane.setSelectionEnd(end);
//Obtain the value of the selected word:
final String word = doc.getText(start, end - start);
//Create the contents of the popup:
final JPanel popupPanel = new JPanel();
//Create the alternative words (via JButtons):
final int cnt = 4;
final ArrayList<JButton> words = new ArrayList<>();
for (int i = 0; i < cnt; ++i) {
final JButton button = new JButton(word + (i + 1));
popupPanel.add(button);
words.add(button);
}
final JButton cancel = new JButton("Cancel");
popupPanel.add(cancel);
//Create the popup itself:
final Popup popup = PopupFactory.getSharedInstance().getPopup(pane, popupPanel, mevt.getXOnScreen(), mevt.getYOnScreen());
//Hook action listenere to the word and cancel buttons:
words.forEach(button -> button.addActionListener(e -> {
try {
//Get the text of that button (it is going to be the new word):
final String newWord = ((JButton) e.getSource()).getText();
//Replace the old text with the new one:
doc.remove(start, end - start);
doc.insertString(start, newWord, null);
//Prepare caret position, so the user can keep on writing:
pane.setCaretPosition(start + newWord.length());
}
catch (final BadLocationException | RuntimeException x) {
JOptionPane.showMessageDialog(pane, "Oups!");
}
finally {
popup.hide();
pendingPopUp = false;
}
}));
//On cancel, deselect the selected text and close the popup:
cancel.addActionListener(e -> {
popup.hide();
pane.setSelectionStart(offset);
pane.setSelectionEnd(offset);
pendingPopUp = false;
});
pendingPopUp = true;
popup.show();
}
catch (final BadLocationException | RuntimeException x) {
JOptionPane.showMessageDialog(pane, "Oups! No word found?...");
}
}
}
private void maybePop(final MouseEvent mevt) {
if (mevt.isPopupTrigger()) {
if (pendingPopUp)
System.err.println("A popup is already popped. Close it to pop a new one.");
else
pop(mevt);
}
}
#Override
public void mouseClicked(final MouseEvent mevt) {
maybePop(mevt);
}
#Override
public void mousePressed(final MouseEvent mevt) {
maybePop(mevt);
}
#Override
public void mouseReleased(final MouseEvent mevt) {
maybePop(mevt);
}
});
final JFrame frame = new JFrame("Word underline.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(pane));
//Give some room to spare:
final Dimension dim = frame.getPreferredSize();
dim.width += 100;
dim.height += 100;
frame.setPreferredSize(dim);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Resources and references:
How to Use Editor Panes and Text Panes
clickable text from jTextPane
making text underline font by using JTextPane?
How to get selection from JTextPane
How to clear all styling from StyledDocument?
Getting 'Attempt to mutate notification' exception
How do I set different colors for text and underline in JTextPane?
Underline StyleConstant in a different colour with AttributeSet
Deselect selected text in JTextPane
how to get the red squiggly line under misspelled words.
You can highlight the text and use a custom Painter to draw the red squiggly line.
Check out the Squiggle Painter for the custom painting code.
Basic usage would be:
SquigglePainter red = new SquigglePainter( Color.RED );
try
{
textField.getHighlighter().addHighlight( ?, ?, red );
}
catch(BadLocationException ble) {}
where the "?" would be the start/end offset of the text you want to underline.
I am trying to use KeyEvent to limit the characters in a jTextField that it can take as input on the KeyTyped event using the following code:
private void userIDFieldKeyTyped(java.awt.event.KeyEvent evt) {
char c = evt.getKeyChar();
if(c!=KeyEvent.VK_BACK_SPACE && c!=KeyEvent.VK_DELETE){
if (Character.isLetter(c) && Character.isDigit(c)){
} else {
evt.consume();
}
}
}
But the above code is not working as expected, it do not take any character as input, as it is clear from the code I am trying to input only AlphaNumeric characters, is there any way to remove this problem? Also I have tried using KeyEvent.VK_ALPHANUMERIC but it didn't work either.
Edit:
What I mean by limiting the characters is that the text field can take input only certain characters which I have allowed and not that to stop takinginput after a certain number of characters has been alread been entered.
I think that JFormattedTextField handles all your requirements. It can limit the number of characters entered, as well as filter out non-required characters. Here is a small example. The MaskFormatter is responsible for handling the required limitations.
import java.awt.EventQueue;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
import javax.swing.text.MaskFormatter;
/**
* For testing class {#code javax.swing.JFormattedTextField}
*/
public class FmTxtFld implements Runnable {
private JFrame frame;
private JFormattedTextField fmtTxtFld;
#Override // java.lang.Runnable
public void run() {
try {
showGui();
}
catch (ParseException xParse) {
xParse.printStackTrace();
}
}
private void showGui() throws ParseException {
frame = new JFrame("FmTxtFld");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// Ten alphanumeric characters, i.e. letter or digit.
MaskFormatter formatter = new MaskFormatter("AAAAAAAAAA"); //throws java.text.ParseException
fmtTxtFld = new JFormattedTextField(formatter);
fmtTxtFld.setColumns(10);
JLabel label = new JLabel("JFormattedTextField");
JPanel panel = new JPanel();
panel.add(label);
panel.add(fmtTxtFld);
frame.add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
FmTxtFld instance = new FmTxtFld();
EventQueue.invokeLater(instance);
}
}
If you run the above code you will see that the text field only echoes valid characters, i.e. only letters and digits, and will also not accept more that 10 characters.
I'm failing to understand why my yankee and whiskey JButtons aren't working. Right now I only want them to close the program when romeo is greater than 1 and sierra is greater than 1.
import java.awt.*;
import java.lang.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.util.Scanner;
public class AlphaMenu extends JFrame /*implements actionPerformed*/
{
private GraphicsDevice gamma;
public JButton charlie, zulu, yankee, xray;
public JFrame beta;
public JPanel delta, echo, foxtrot, golf, hotel;
public JTextArea whiskey, victor;
public BorderLayout uniform;
public ImageIcon bg;
public JLabel tango;
public int sierra, romeo;
public Integer quebec, papa;
public ActionEvent oscar;
public ActionEvent november;
public AlphaMenu()
{
//Initialization of Objects
charlie = new JButton("EXIT");
zulu = new JButton("Enter Time");
yankee = new JButton("Enter Amount of Money");
xray = new JButton("Calculate");
sierra = 0;
romeo = 0;
quebec = new Integer(0);
papa = new Integer(0);
whiskey = new JTextArea(2, 15);
victor = new JTextArea(2, 15);
bg = new ImageIcon("background.gif");
beta = new JFrame();
delta = new JPanel();
echo = new JPanel();
foxtrot = new JPanel();
golf = new JPanel();
hotel = new JPanel();
uniform = new BorderLayout();
ImageIcon bg = new ImageIcon("background.gif");
tango = new JLabel("");
tango.setIcon(bg);
//Modification of panels
beta.add(delta, uniform.PAGE_END);
beta.add(golf, uniform.PAGE_START);
beta.add(echo, uniform.LINE_START);
beta.add(foxtrot, uniform.LINE_END);
beta.add(hotel, uniform.CENTER);
golf.add(tango);
//Modification of JButton charlie & adding of JButtons
charlie.setPreferredSize(new Dimension(100, 50));
delta.add(charlie);
charlie.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
echo.add(whiskey);
echo.add(yankee);
foxtrot.add(victor);
foxtrot.add(zulu);
//Modification of JFrame beta
beta.setUndecorated(true);
beta.setExtendedState(JFrame.MAXIMIZED_BOTH);
beta.setResizable(false);
beta.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
beta.setVisible(true);
}
public void buttonSetup() throws NumberFormatException
{
//Modification of JButton yankee & JTextArea whiskey & int sierra
romeo = quebec.parseInt(whiskey.getText());
yankee.setPreferredSize(new Dimension(300, 50));
yankee.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent oscar)
{
System.exit(0);
}
});
//Modification of JButton zulu & JTextArea victor & int romeo
sierra = papa.parseInt(victor.getText());
zulu.setPreferredSize(new Dimension(300, 50));
zulu.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent november)
{
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e)
{
}
public static void main(String[] args)
{
new AlphaMenu();
}
}
So, you have two JTextArea (JTextField would probably be better) and a button. you want some buttons to execute exit when the text of both textareas is an integer greater than 1.
seems that your buttonSetup() function isn't called anywhere.
Anyway, I'd create an ActionListener that reads the texts, converts to integer, tests your condition and executes exit(). This ActionListener should be added to all the buttons you want to perform the action
final ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
final int intRomeo = Integer.parseInt(romeo.getText());
final int intSierra = Integer.parseInt(sierra .getText());
if (intRomeo > 1 && intSierra > 1) {
// whatever you want to do
System.exit(0);
}
} catch (/*NumberFormat*/ Exception e) {
// ...not integers
}
};
}
whiskey.addActionListener(al);
yankee.addActionListener(al);
I have to add: the variable names you are using are really bad. Consider choosing something more significative.
For starters, readability...it would probably help the "sloppiness" if you used more appropriate names for your variables, indented different sections of code, and used comments to help describe sections in layman's terms. Maybe "btnExit" and "btnCalculate" would help make things a little easier to navigate.
Moving forward, you also don't have two different classes here, you have one class with several methods. Which is fine but wanted to inform you of that. I think maybe you need to add the buttons to their panels after your action listeners and formatting for each button. I'm just getting into some swing stuff myself and I've noticed moving the .add() functions around in the code has helped when I run into issues like this. Try the following bellow. I indented and used new naming conventions for the comments, but the code uses your convention.
//add the pnlEcho to frmBeta
beta.add(echo, uniform.LINE_START);
//format btnYankee
yankee.setPreferredSize(new Dimension(300, 50));
//btnYankee action listener
yankee.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) { //default action event
System.exit(0); //you could use this
beta.dispose(); //or you could dispose the frame and
//do more work after it is gone
}
});
//add btnYankee to pnlEcho
echo.add(yankee);
I'm failing to understand why my yankee and whiskey JButtons aren't
working
The variable wiskey is not JButton type but JTextArea type.
I am working on a JTextPane that works (almost) exactly like the tags input field here on stackoverflow. For that I am converting text to components as soon as a user hits enter, tab or space. Naturally I do not want any of those characters to actually be input to the text pane. I found this solution, SSCCE:
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.StyledDocument;
#SuppressWarnings("serial")
public class TagTextPane extends JTextPane {
public TagTextPane() {
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "finalizeTag");
this.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "finalizeTag");
this.getInputMap().put(KeyStroke.getKeyStroke("TAB"), "focusNext");
this.getActionMap().put("focusNext", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
finalizeTag();
transferFocus();
}
});
this.getActionMap().put("finalizeTag", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
finalizeTag();
}
});
}
private void finalizeTag() {
StyledDocument doc = (StyledDocument) getDocument();
Element element = doc.getCharacterElement(getCaretPosition() - 1);
int start = element.getStartOffset();
int len = element.getEndOffset() - start;
String tag = "";
try {
tag = this.getDocument().getText(start, len);
} catch (BadLocationException e) {
}
this.setSelectionStart(start);
this.setSelectionEnd(start + len);
JLabel label = new JLabel(tag);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
this.insertComponent(label);
}
public static void main(String[] args) {
JFrame frame = new JFrame("TagTextPaneTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TagTextPane tPane = new TagTextPane();
frame.setSize(400, 100);
frame.getContentPane().add(tPane);
frame.setVisible(true);
}
}
Hitting "tab" usually causes a tab character to be inserted and hitting "enter" usually causes a line break to be entered, as well as hitting "space" causes a space to be entered. The weird thing is that my code stops line breaks and tabs from being entered, but still allows spaces to be entered normally, while performing the intended action.
Why does this approach behave differently for those keys?
How can I stop the space from being entered? (Maybe I want to extend this behavior to commas and the like later on.)
How can I optimally control the behavior of certain characters and keystrokes in a JTextComponent? I have seen this, where the suggestion is to use a KeyListener, but I have also seen this, where Rob Camick points out, why a KeyListener should not be used. So should I rather use a DocumentFilter, or is that breaking a butterfly on a wheel?
Is this even the best way to build this kind of tag input field?
this.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "finalizeTag");
This is handling the keyPressed event for the space character.
You want to handle the keyTyped event of the space character:
this.getInputMap().put(KeyStroke.getKeyStroke(' '), "finalizeTag");
I have to convert styled text to wrapped simple text (for SVG word wrapping). I cannot beleive that the word wrapping information (how many lines are there, where are the line breaks) cannot be extracted from the JTextArea. So I created a small frame program:
package bla;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextArea;
public class Example1 extends WindowAdapter {
private static String content = "01234567890123456789\n" + "0123456 0123456 01234567 01234567";
JTextArea text;
public Example1() {
Frame f = new Frame("TextArea Example");
f.setLayout(new BorderLayout());
Font font = new Font("Serif", Font.ITALIC, 20);
text = new JTextArea();
text.setFont(font);
text.setForeground(Color.blue);
text.setLineWrap(true);
text.setWrapStyleWord(true);
f.add(text, BorderLayout.CENTER);
text.setText(content);
// Listen for the user to click the frame's close box
f.addWindowListener(this);
f.setSize(100, 511);
f.show();
}
public static List<String> getLines( JTextArea text ) {
//WHAT SHOULD I WRITE HERE
return new ArrayList<String>();
}
public void windowClosing(WindowEvent evt) {
List<String> lines = getLines(text);
System.out.println( "Number of lines:" + lines.size());
for (String line : lines) {
System.out.println( line );
}
System.exit(0);
}
public static void main(String[] args) {
Example1 instance = new Example1();
}
}
If you run it you will see this:
And what I expect as output:
Number of lines:6
0123456789
0123456789
0123456
0123456
01234567
01234567
What should I write in place of the comment?
Complete answer:
So, then the complete solution based on the accepted answer without displaying the frame actually (note, that you should remove the actual newline characters from the result):
package bla;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;
public class Example1 {
private static String content = "01234567890123456789\n" + "0123456 0123456 01234567 01234567";
public static List<String> getLines( String textContent, int width, Font font ) throws BadLocationException {
JTextArea text;
text = new JTextArea();
text.setFont(font);
text.setForeground(Color.blue);
text.setLineWrap(true);
text.setWrapStyleWord(true);
text.setText(content);
text.setSize(width, 1);
int lastIndex = 0;
int index = Utilities.getRowEnd(text, 0);
List<String> result = new ArrayList<String>();
do {
result.add( textContent.substring( lastIndex, Math.min( index+1, textContent.length() ) ) );
lastIndex = index + 1;
}
while ( lastIndex < textContent.length() && ( index = Utilities.getRowEnd(text, lastIndex) ) > 0 );
return result;
}
public static void main(String[] args) throws BadLocationException {
Font font = new Font("Serif", Font.ITALIC, 20);
Example1 instance = new Example1();
for (String line : getLines(content,110,font)) {
System.out.println( line.replaceAll( "\n", "") );
}
}
}
Open question in me (not that important), why is that a frame with 100px width containing a jtextarea wraps the text later than a jtextarea without frame with the same width. Ideas for this?
JTextArea does not support styled text, but it does support line-oriented access to its model, PlainDocument, as shown below. For reference,
Don't mix AWT (Frame) and Swing (JTextArea) components unnecessarily.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
As noted here, the getLineCount() method counts line.separator delimited lines, not wrapped lines.
BasicTextUI handles Look & Feel dependent rendering; the methods viewToModel() and viewToModel() translate between the two coordinate systems.
Console:
01234567890123456789
0123456 0123456
01234567 01234567
Code:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class Example2 {
private static final Character SEP = Character.LINE_SEPARATOR;
private static String content = ""
+ "01234567890123456789" + SEP
+ "0123456 0123456" + SEP
+ "01234567 01234567";
private JTextArea text;
public Example2() {
JFrame f = new JFrame("TextArea Example");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Font font = new Font("Serif", Font.ITALIC, 20);
text = new JTextArea(4, 8);
text.setFont(font);
text.setForeground(Color.blue);
text.setLineWrap(true);
text.setWrapStyleWord(true);
text.setText(content);
f.add(new JScrollPane(text));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
for (String s : getLines(text)) {
System.out.println(s);
}
}
private List<String> getLines(JTextArea text) {
PlainDocument doc = (PlainDocument) text.getDocument();
List<String> list = new ArrayList<String>();
for (int i = 0; i < text.getLineCount(); i++) {
try {
int start = text.getLineStartOffset(i);
int length = text.getLineEndOffset(i) - start;
list.add(doc.getText(start, length));
} catch (BadLocationException ex) {
ex.printStackTrace(System.err);
}
}
return list;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Example2 instance = new Example2();
}
});
}
}
Use Utilities.getRowEnd()
Pass 0 as start offset and then previousline's end offset +1
JTextArea does have a : getLines() method, is that not working for you?