JavaFX TextArea: how to set tabulation width - java

How do I set tab width of JavaFX TextArea ?
When I use tabulation (tab key) in TextArea, the width of the tabulation is wide. I want to control the width, i.e., use 4 spaces. In the documentation I could not find a method to do this.
I tried this code (where taInput is a TextArea), but it is not working as it should:
taInput.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.TAB) {
// TAB SPACES
StringBuilder sb = new StringBuilder(config.getTabSpacesCount());
for (int i=0; i<config.getTabSpacesCount(); i++) {
sb.append(' ');
}
taInput.insertText(taInput.getCaretPosition(), sb.toString());
e.consume();
}
}
});

Finally I found a way to do this.
It seems that the setOnKeyPressed() method is not good for this task because the event is handled after the keyPress action is executed.
The addEventFilter() handles the events before their actions are executed, so you can manipulate the events.
My new code:
taInput.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.TAB) {
String s = StringUtils.repeat(' ', config.getTabSpacesCount());
taInput.insertText(taInput.getCaretPosition(), s);
e.consume();
}
}
});

#tenotron
your code also executes same logic for combination of TAB key with set of modifiers ( shift, control, alt, meta or shortcut). Meaning
In TextArea
Pressing TAB key = Ctrl(modifier) + TAB = .... = your logic.
To fix this issue , you have to use KeyCombination
Sample Code :
textArea.addEventFilter(KeyEvent.KEY_PRESSED,
new EventHandler<KeyEvent>() {
final KeyCombination combo = new KeyCodeCombination(
KeyCode.TAB);
#Override
public void handle(KeyEvent event) {
// check for only tab key
if (combo.match(event)) {
textArea.insertText(textArea.getCaretPosition(),
"I am not real TAB");
event.consume();
}
}
});
now Pressing TAB key results "I am not Real TAB" , ctrl+TAB will highlight the next Node on the scene.
Reference :
Correctly Checking KeyEvents
KeyCombination

From JavaFX 14 onward, the best way to deal with this is to use CSS to change the tab width, as shown in my answer to Setting the tab spacing/size visualization for a JavaFX TextArea
Replacing tab characters with multiple spaces doesn't have the same effect as tabs advance to the next tab stop, they don't add a fixed-width gap. Even if you adjusted for the characters preceding the tab, when not using a fixed-width font, an integer number of actual spaces may not give you the correct position.

Try making what you want displayed as a String. Then use s.replace("\t", " ");
if you want four spaces. This worked for me.

Related

How to make text area within JavaFX to be accepting only text input, no numbers?

I would like to know whether it is possible to make text area in JavaFX to accept only text format, no numbers - in the worst case at least to say to user when typing numbers inside this text area that it's forbidden.
Solution:
is quite simple, just check the text inside text area with this method :
if (!Pattern.matches("[a-zA-Z]+", userInputText.getText())){
System.out.println("wrong input");
}
I have personally added this onHandleKeyReleased action event:
#FXML
public void handleKeyReleased() {
String text = userInputText.getText();
boolean disableButtons = text.isEmpty() || text.trim().isEmpty() || (!Pattern.matches("[a-zA-Z]+", userInputText.getText())) ;
okButton.setDisable(disableButtons);
}
So after user writes any number inside the text field, the button for confirming his action will be disabled, so it will look like this:
correct input
incorrect input
This should work with input UI element within JavaFx.
for number : What is the recommended way to make a numeric TextField in JavaFX?
try invert it (near match !)
textField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue,
String newValue) {
if (!newValue.matches("\\d*")) {
textField.setText(newValue.replaceAll("[^\\d]", ""));
}
}
});

Changing the font color of JTextPane and continuing to write with the old one

I have a problem with JTextPane font color and cannot seem to find a solution.
I have a text box (JTextPane) where the user is typing in text. At some point he presses a button which will change the color of some of the words.
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setBackground(attr, Color.RED);
StyledDocument doc = inputArea.getStyledDocument();
//find the start of the word
String wholeText = inputArea.getText();
int i = 0;
while (i <= wholeText.length() - word.length()) {
if (wholeText.substring(i, i + word.length()).equals(word)) {
doc.setCharacterAttributes(i, word.length(), attr, false);
}
i ++;
}
The problem now is that if this word is the last one from the text, if the user returns back to writing text, the newly typed text is red, not black. I have spent 2 hours trying to figure it out, but no luck.
Edit: I have also tried using Highlighter, but the problem is the same.
I've use the following code before after inserting text with attributes into a document:
// Newly typed text at the end of the document will inherit the
// "keyword" attributes unless we remove the attributes
textPane.setCaretPosition(doc.getLength());
textPane.getInputAttributes().removeAttributes(keyWord);
Ok, so I figured it out so I will post my solution.
Even with the above solution if I clicked the highlighted word and for example added a character to it, the caret would become red and won't be fixed by anything.
That is why I added a key listener to the text pane and on each key stroke I did this:
inputArea.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
StyleConstants.setForeground(blackColor, Color.BLACK);
inputArea.setCharacterAttributes(blackColor, false);
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
Where black color is of type SimpleAttributeSet. This may be not very elegant, but solves it.

How to use a highlighter in JTextArea

I have this notebook class that I have been working on. I have two problems that I'm facing right now:
1: Bold and Italicize specific text
I have two icons in my toolbar that make the text bolded or italicized when you click on it. All of that works fine, however, It always selects all the text in the document rather than specifically selected text. Is there a way I can use the blue highlight of a left click on a mouse in order to bold or italicize specific text? This is the code for the bolding Abstract Action. The italics looks exactly the same, except for italics.
Action Bold = new AbstractAction("Bold", new ImageIcon("bold.png"))
{
public void actionPerformed(ActionEvent e)
{
if(bolded == false)
{
area.setFont(area.getFont().deriveFont(Font.BOLD));
bolded = true;
}
else
{
area.setFont(area.getFont().deriveFont(Font.PLAIN));
bolded = false;
}
}
};
2 Highlighter over text
I want to add an actual highlighter that will just paint certain groups of words that the user selects yellow. I've read through the Oracle page on this, and I'm still not all that sure about using it. I see a lot of examples of people searching for specific words and highlighting it that way, but I'm not looking to highlight these specific words. I want the user to decide which text to highlight.
Action Highlight = new AbstractAction("Highlight", new ImageIcon("highlighter.png"))
{
public void actionPerformed(ActionEvent e) throws BadLocationException
{
Highlighter highlighter = area.getHighlighter();
HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
highlighter.addHighlight(0 , 6, painter);
}
};
The code above is what I managed to pull together from some other tutorials online, however, the BadLocationException doesn't compile right when it is inside the Abstract Action, so this isn't looking like a viable option.
Any help is appreciated!
actionPerformed does not throw any checked Exceptions.
Simply remove the exception and catch it inside the method.
public void actionPerformed(ActionEvent e)
{
try {
Highlighter highlighter = area.getHighlighter();
HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.RED);
highlighter.addHighlight(0 , 6, painter);
catch(throws BadLocationException ex) {
ex.printStackTrace();
}
}
}

Java swt change typed character

I have swt browser widget in which user can type with keyboard, I need for certain character user press change it to others.
for example when user press x, I change it y.
I add key listener where I can block user input with doit = false;
but now I can't pass my character.
here is what I am doing:
browser_1.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event arg0) {
if(arg0.character=='x')
{
arg0.doit=false;
//now here how to send y as a charachter to browser widget
}
}
});
In other words can I somehow change character to other without using arg0.doit=false;
So after some search, here is the solution
In SWT you can add to display 'filter' listener instance which can modify pretty anything in the event (see docs for details).
Caution from Javadoc: Setting the type of an event to SWT.None from within the handleEvent() method can be used to change the event type and stop subsequent Java listeners from running. Because event filters run before other listeners, event filters can both block other listeners and set arbitrary fields within an event. For this reason, event filters are both powerful and dangerous. They should generally be avoided for performance, debugging and code maintenance reasons.
Here's the code (changes any typed key to 'l' character and wrote that in console, when the event actually arise)
browser.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
System.out.println(event.character);
}
});
display.addFilter(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
if(event.widget instanceof Browser) {
event.character = 'l';
}
}
});
IMHO it's really dirty solution, implementation on browser side (by JavaScript) is much more prettier
Also when I'm looking to your code (don't know if it's just some testing, proof-of-concept code, anyway), using variables with something_number or arg0 makes me sad. It makes code so much unreadable and obscure, try to avoid them ;]..
You can do following:
Text textControl = new Text(...);
textControl.addKeyListener(this);
...
public void keyPressed(KeyEvent e) {
if (e.character == 'x' && (e.stateMask & SWT.CONTROL) == 0) {
e.doit = false;
textControl.insert("y");
}
}
Some comments to this code:
We check for e.stateMask because we still need keep CTRL+X as cut-function. Please note, if you use instead of current code this one (that just check that no special button is pressed):
if (e.character == 'x' && e.stateMask == 0)
You will get a bug when CapsLock is on. In this case user should press Shift+X to get lower x.
Method insert("y") inserts charater to the place of cursor. When some text is seleted, the whole selection will be replaced by "y".
Current example changes only lower case of "x". You should change it if needed to handle also change upper X to Y.
I had a similar requirement: converting a decimal separator press on the keypad (a dot) to the decimal separator of our locale (a comma). I tried the same idea as Sorceror, but it didn't work for me either. What does work is setting event.doit = false and posting a new event that is the clone of the original event with the character replaced:
#Override
public void handleEvent(Event event) {
if (event.widget instanceof Browser && event.character == 'x') {
Event eventClone = cloneEvent(event);
eventClone.character = 'y';
event.doit = false;
display.post(eventClone);
}
}
(If display is a local variable you need to make it final.)
I created a small utility method to create a clone of the event:
/**
* #return a clone of the given {#link Event}
*/
public static Event cloneEvent(Event event) {
Event clone = new Event();
clone.display = event.display;
clone.widget = event.widget;
clone.type = event.type;
clone.detail = event.detail;
clone.item = event.item;
clone.index = event.index;
clone.gc = event.gc;
clone.x = event.x;
clone.y = event.y;
clone.width = event.width;
clone.height = event.height;
clone.count = event.count;
clone.time = event.time;
clone.button = event.button;
clone.character = event.character;
clone.keyCode = event.keyCode;
clone.keyLocation = event.keyLocation;
clone.stateMask = event.stateMask;
clone.start = event.start;
clone.end = event.end;
clone.text = event.text;
clone.doit = event.doit;
clone.data = event.data;
clone.touches = event.touches;
clone.xDirection = event.xDirection;
clone.yDirection = event.yDirection;
clone.magnification = event.magnification;
clone.rotation = event.rotation;
return clone;
}

How to intercept keyboard strokes going to Java Swing JTextField?

The JTextField is a calculator display initialized to zero and it is bad form to display a decimal number with a leading 0 like 0123 or 00123. The numeric buttons (0..9) in a NetBeans Swing JFrame use append() [below] to drop the leading zeros, but the user may prefer the keyboard to a mouse, and non-numeric characters also need to be handled.
private void append(String s) {
if (newEntry) {
newEntry = false;
calcDisplay.setText(s);
} else if (0 != Float.parseFloat(calcDisplay.getText().toString())) {
calcDisplay.setText(calcDisplay.getText().toString() + s);
}
}
You could restrict the characters input to the JTextField by adding a custom KeyListener. Here is a quick example to demonstrate the idea:
myTextField.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if (!Character.isDigit(c)) {
e.consume(); // Stop the event from propagating.
}
}
});
Of course, you need to consider special keys like Delete and combinations like CTRL-C, so your KeyListener should be more sophisticated. There are probably even freely available utilities to do most of the grunt work for you.
You can do this with DocumentFilter.
(Edit: This answer originally included a ling to a simple complete example program on my now defunct weblog.)

Categories

Resources