I have a spell checker demo here, visually it is exactly what I want (red underline for words that are not correct), but I'm having trouble creating a right-click context menu to apply suggestions.
I was able to get a context menu on the Text object, but I was not able to find the position of the text in the box to replace using the prediction.
Here is the code:
pom.xml
<dependency>
<groupId>org.fxmisc.richtext</groupId>
<artifactId>richtextfx</artifactId>
<version>0.10.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
<type>jar</type>
</dependency>
SpellCheckDemo.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.BreakIterator;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import org.apache.commons.text.similarity.JaroWinklerDistance;
import org.reactfx.Subscription;
public class SpellCheckingDemo extends Application
{
private static final Set<String> dictionary = new HashSet<String>();
private final static double JAROWINKLERDISTANCE_THRESHOLD = .80;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
StyleClassedTextArea textArea = new StyleClassedTextArea();
textArea.setWrapText(true);
Subscription cleanupWhenFinished = textArea.multiPlainChanges()
.successionEnds(Duration.ofMillis(500))
.subscribe(change ->
{
textArea.setStyleSpans(0, computeHighlighting(textArea.getText()));
});
// call when no longer need it: `cleanupWhenFinished.unsubscribe();`
textArea.setOnContextMenuRequested((ContextMenuEvent event) ->
{
if (event.getTarget() instanceof Text)
{
Text text = (Text) event.getTarget();
ContextMenu context = new ContextMenu();
JaroWinklerDistance distance = new JaroWinklerDistance();
for (String word : dictionary)
{
if (distance.apply(text.getText(), word) >= JAROWINKLERDISTANCE_THRESHOLD)
{
MenuItem item = new MenuItem(word);
item.setOnAction(a ->
{
// how do I find the position of the Text object ?
textArea.replaceText(25, 25 + text.getText().length(), word);
});
context.getItems().add(item);
}
}
context.show(primaryStage, event.getScreenX(), event.getScreenY());
}
});
// load the dictionary
try (InputStream input = SpellCheckingDemo.class.getResourceAsStream("/spellchecking.dict");
BufferedReader br = new BufferedReader(new InputStreamReader(input)))
{
String line;
while ((line = br.readLine()) != null)
{
dictionary.add(line);
}
} catch (IOException e)
{
e.printStackTrace();
}
// load the sample document
InputStream input2 = SpellCheckingDemo.class.getResourceAsStream("/spellchecking.txt");
try (java.util.Scanner s = new java.util.Scanner(input2))
{
String document = s.useDelimiter("\\A").hasNext() ? s.next() : "";
textArea.replaceText(0, 0, document);
}
Scene scene = new Scene(new StackPane(new VirtualizedScrollPane<>(textArea)), 600, 400);
scene.getStylesheets().add(SpellCheckingDemo.class.getResource("/spellchecking.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("Spell Checking Demo");
primaryStage.show();
}
private static StyleSpans<Collection<String>> computeHighlighting(String text)
{
StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();
BreakIterator wb = BreakIterator.getWordInstance();
wb.setText(text);
int lastIndex = wb.first();
int lastKwEnd = 0;
while (lastIndex != BreakIterator.DONE)
{
int firstIndex = lastIndex;
lastIndex = wb.next();
if (lastIndex != BreakIterator.DONE
&& Character.isLetterOrDigit(text.charAt(firstIndex)))
{
String word = text.substring(firstIndex, lastIndex).toLowerCase();
if (!dictionary.contains(word))
{
spansBuilder.add(Collections.emptyList(), firstIndex - lastKwEnd);
spansBuilder.add(Collections.singleton("underlined"), lastIndex - firstIndex);
lastKwEnd = lastIndex;
}
System.err.println();
}
}
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
return spansBuilder.create();
}
}
The following files go into the resource folder:
spellchecking.css
.underlined {
-rtfx-background-color: #f0f0f0;
-rtfx-underline-color: red;
-rtfx-underline-dash-array: 2 2;
-rtfx-underline-width: 1;
-rtfx-underline-cap: butt;
}
spellchecking.dict
a
applied
basic
brown
but
could
document
dog
fox
here
if
is
its
jumps
lazy
no
over
quick
rendering
sample
see
styling
the
there
this
were
you
spellchecking.txt
The quik brown fox jumps over the lazy dog.
Ths is a sample dokument.
There is no styling aplied, but if there were, you could see its basic rndering here.
I found out how. By using the caret position, I can select a word and replace it. The problem is, right clicking didn't move the caret. So in order to move the caret, you add a listener.
textArea.setOnMouseClicked((MouseEvent mouseEvent) ->
{
if (mouseEvent.getButton().equals(MouseButton.SECONDARY))
{
if (mouseEvent.getClickCount() == 1)
{
CharacterHit hit = textArea.hit(mouseEvent.getX(), mouseEvent.getY());
int characterPosition = hit.getInsertionIndex();
// move the caret to that character's position
textArea.moveTo(characterPosition, SelectionPolicy.CLEAR);
}
}
});
Edit 1:
Added indexing and concurrency for performance purposes. Context menu is now instantaneous.
Edit 2:
Fixed macOS issue with context menu
Full code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.PauseTransition;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.text.WordUtils;
import org.apache.commons.text.similarity.JaroWinklerSimilarity;
import org.fxmisc.richtext.CharacterHit;
import org.fxmisc.richtext.NavigationActions.SelectionPolicy;
public class SpellCheckingDemo extends Application
{
private static final int NUMBER_OF_SUGGESTIONS = 5;
private static final Set<String> DICTIONARY = ConcurrentHashMap.newKeySet();
private static final Map<String, List<String>> SUGGESTIONS = new ConcurrentHashMap<>();
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
StyleClassedTextArea textArea = new StyleClassedTextArea();
textArea.setWrapText(true);
textArea.requestFollowCaret();
//wait a bit before typing has stopped to compute the highlighting
PauseTransition textAreaDelay = new PauseTransition(Duration.millis(250));
textArea.textProperty().addListener((observable, oldValue, newValue) ->
{
textAreaDelay.setOnFinished(event ->
{
textArea.setStyleSpans(0, computeHighlighting(textArea.getText()));
//have a new thread index all incorrect words, and pre-populate suggestions
Task task = new Task<Void>()
{
#Override
public Void call()
{
//iterating over entire list is ok because after the first time, it will hit the index anyway
for (String word : SpellCheckingDemo.SUGGESTIONS.keySet())
{
SpellCheckingDemo.getClosestWords(word);
SpellCheckingDemo.getClosestWords(StringUtils.trim(word));
}
return null;
}
};
new Thread(task).start();
});
textAreaDelay.playFromStart();
});
textArea.setOnMouseClicked((MouseEvent mouseEvent) ->
{
if (mouseEvent.getButton().equals(MouseButton.SECONDARY))
{
if (mouseEvent.getClickCount() == 1)
{
CharacterHit hit = textArea.hit(mouseEvent.getX(), mouseEvent.getY());
int characterPosition = hit.getInsertionIndex();
// move the caret to that character's position
if (StringUtils.isEmpty(textArea.getSelectedText()))
{
textArea.moveTo(characterPosition, SelectionPolicy.CLEAR);
}
if (mouseEvent.getTarget() instanceof Text && StringUtils.isEmpty(textArea.getSelectedText()))
{
textArea.selectWord();
//When selecting right next to puncuation and spaces, the replacements elimantes these values. This avoids the issue by moving the caret towards the middle
if (!StringUtils.isEmpty(textArea.getSelectedText()) && !CharUtils.isAsciiAlphanumeric(textArea.getSelectedText().charAt(textArea.getSelectedText().length() - 1)))
{
textArea.moveTo(textArea.getCaretPosition() - 2);
textArea.selectWord();
}
String referenceWord = textArea.getSelectedText();
textArea.deselect();
if (!NumberUtils.isParsable(referenceWord) && !DICTIONARY.contains(StringUtils.trim(StringUtils.lowerCase(referenceWord))))
{
ContextMenu context = new ContextMenu();
for (String word : SpellCheckingDemo.getClosestWords(referenceWord))
{
MenuItem item = new MenuItem(word);
item.setOnAction((ActionEvent a) ->
{
textArea.selectWord();
textArea.replaceSelection(word);
textArea.deselect();
});
context.getItems().add(item);
}
if (!context.getItems().isEmpty())
{
textArea.moveTo(textArea.getCaretPosition() - 1);
context.show((Node) mouseEvent.getTarget(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
((Node) mouseEvent.getTarget()).addEventHandler(MouseEvent.MOUSE_PRESSED, event -> context.hide());
} else
{
ContextMenu copyPasteMenu = getCopyPasteMenu(textArea);
copyPasteMenu.show((Node) mouseEvent.getTarget(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
((Node) mouseEvent.getTarget()).addEventHandler(MouseEvent.MOUSE_PRESSED, event -> copyPasteMenu.hide());
}
} else
{
ContextMenu copyPasteMenu = getCopyPasteMenu(textArea);
copyPasteMenu.show((Node) mouseEvent.getTarget(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
((Node) mouseEvent.getTarget()).addEventHandler(MouseEvent.MOUSE_PRESSED, event -> copyPasteMenu.hide());
}
} else
{
ContextMenu copyPasteMenu = getCopyPasteMenu(textArea);
copyPasteMenu.show((Node) mouseEvent.getTarget(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
((Node) mouseEvent.getTarget()).addEventHandler(MouseEvent.MOUSE_PRESSED, event -> copyPasteMenu.hide());
}
}
}
});
// load the dictionary
try (InputStream input = SpellCheckingDemo.class.getResourceAsStream("/spellchecking.dict");
BufferedReader br = new BufferedReader(new InputStreamReader(input)))
{
String line;
while ((line = br.readLine()) != null)
{
DICTIONARY.add(line);
}
} catch (IOException ex)
{
Logger.getLogger(SpellCheckingDemo.class.getName()).log(Level.SEVERE, null, ex);
}
// load the sample document
InputStream input2 = SpellCheckingDemo.class.getResourceAsStream("/spellchecking.txt");
try (java.util.Scanner s = new java.util.Scanner(input2))
{
String document = s.useDelimiter("\\A").hasNext() ? s.next() : "";
textArea.replaceText(0, 0, document);
}
Scene scene = new Scene(new StackPane(new VirtualizedScrollPane<>(textArea)), 600, 400);
scene.getStylesheets().add(SpellCheckingDemo.class.getResource("/spellchecking.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("Spell Checking Demo");
primaryStage.show();
}
private static StyleSpans<Collection<String>> computeHighlighting(String text)
{
StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();
BreakIterator wb = BreakIterator.getWordInstance();
wb.setText(text);
int lastIndex = wb.first();
int lastKwEnd = 0;
while (lastIndex != BreakIterator.DONE)
{
int firstIndex = lastIndex;
lastIndex = wb.next();
if (lastIndex != BreakIterator.DONE && Character.isLetterOrDigit(text.charAt(firstIndex)))
{
String word = text.substring(firstIndex, lastIndex);
if (!NumberUtils.isParsable(word) && !DICTIONARY.contains(StringUtils.lowerCase(word)))
{
spansBuilder.add(Collections.emptyList(), firstIndex - lastKwEnd);
spansBuilder.add(Collections.singleton("underlined"), lastIndex - firstIndex);
lastKwEnd = lastIndex;
SpellCheckingDemo.SUGGESTIONS.putIfAbsent(word, Collections.emptyList());
}
//System.err.println();
}
}
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
return spansBuilder.create();
}
public static List<String> getClosestWords(String word)
{
//check to see if an suggestions for this word have already been indexed
if (SpellCheckingDemo.SUGGESTIONS.containsKey(word) && !SpellCheckingDemo.SUGGESTIONS.get(word).isEmpty())
{
return SpellCheckingDemo.SUGGESTIONS.get(word);
}
List<StringDistancePair> allWordDistances = new ArrayList<>(DICTIONARY.size());
String lowerCaseWord = StringUtils.lowerCase(word);
JaroWinklerSimilarity jaroWinklerAlgorithm = new JaroWinklerSimilarity();
for (String checkWord : DICTIONARY)
{
allWordDistances.add(new StringDistancePair(jaroWinklerAlgorithm.apply(lowerCaseWord, checkWord), checkWord));
}
allWordDistances.sort(Comparator.comparingDouble(StringDistancePair::getDistance));
List<String> closestWords = new ArrayList<>(NUMBER_OF_SUGGESTIONS);
System.out.println(word);
for (StringDistancePair pair : allWordDistances.subList(allWordDistances.size() - NUMBER_OF_SUGGESTIONS, allWordDistances.size()))
{
// 0 is not a match at all, so no point adding to list
if (pair.getDistance() == 0.0)
{
continue;
}
String addWord;
if (StringUtils.isAllUpperCase(word))
{
addWord = StringUtils.upperCase(pair.getWord());
} else if (CharUtils.isAsciiAlphaUpper(word.charAt(0)))
{
addWord = WordUtils.capitalize(pair.getWord());
} else
{
addWord = StringUtils.lowerCase(pair.getWord());
}
System.out.println(pair);
closestWords.add(addWord);
}
System.out.println();
Collections.reverse(closestWords);
//add the suggestion list to index to allow future pulls
SpellCheckingDemo.SUGGESTIONS.put(word, closestWords);
return closestWords;
}
public static ContextMenu getCopyPasteMenu(StyleClassedTextArea textArea)
{
ContextMenu context = new ContextMenu();
MenuItem cutItem = new MenuItem("Cut");
cutItem.setOnAction((ActionEvent a) ->
{
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(textArea.getSelectedText());
clipboard.setContent(content);
textArea.replaceSelection("");
});
context.getItems().add(cutItem);
MenuItem copyItem = new MenuItem("Copy");
copyItem.setOnAction((ActionEvent a) ->
{
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
content.putString(textArea.getSelectedText());
clipboard.setContent(content);
});
context.getItems().add(copyItem);
MenuItem pasteItem = new MenuItem("Paste");
pasteItem.setOnAction((ActionEvent a) ->
{
Clipboard clipboard = Clipboard.getSystemClipboard();
if (!StringUtils.isEmpty(textArea.getSelectedText()))
{
textArea.replaceSelection(clipboard.getString());
} else
{
textArea.insertText(textArea.getCaretPosition(), clipboard.getString());
}
});
context.getItems().add(pasteItem);
context.getItems().add(new SeparatorMenuItem());
MenuItem selectAllItem = new MenuItem("Select All");
selectAllItem.setOnAction((ActionEvent a) ->
{
textArea.selectAll();
});
context.getItems().add(selectAllItem);
if (StringUtils.isEmpty(textArea.getSelectedText()))
{
cutItem.setDisable(true);
copyItem.setDisable(true);
}
return context;
}
private static class StringDistancePair
{
private final double x;
private final String y;
public StringDistancePair(double x, String y)
{
this.x = x;
this.y = y;
}
public String getWord()
{
return y;
}
public double getDistance()
{
return x;
}
#Override
public String toString()
{
return StringUtils.join(String.valueOf(getDistance()), " : ", String.valueOf(getWord()));
}
}
}
Download the full English dictionary here:
https://github.com/dwyl/english-words/blob/master/words_alpha.txt
Related
Iam new into java coding, iam learning and to learn i propose to me create a traceroute program that keep testing the ping response on the route traced.
The first step is get the IP from user and make the traceroute, getting all ip address to be pinged, but iam stuck on this, when i try to add a parsed return of traceroute output to the Jtable, it dont acumullate it, just add the last entry of my while.
Please dont blame my by the bad coding, iam learning.
Iam trying to figure out how to add data to a list and a JTable from a while.
This program get informations from other class, this other class runs a tracert to a ip address and return to Main the tracert results in this format:
13ms;14ms;23ms;192.168.2.3
13ms;14ms;23ms;192.168.2.1
13ms;14ms;23ms;200.122.222.22
this is my table fields: ping1,ping2,ping3,hop
I need to put this data in the table but need to be all ips of the list but iam getting only the last one.
I made alot of tests and commented it because did not workd.
Main.java
package application;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import application.Main.Pinge;
import application.NetworkDiagnostics;
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
// Layout
FlowPane noRaiz = new FlowPane();
// Cena
Scene minhaCena = new Scene(noRaiz, 400, 500);
// Nós
TextField ip = new TextField();
// Tables
// List lista = new ArrayList<String>();
// lista.add("1;2;3;4");
// List<Pinge> lista = Arrays.asList();
// List<Pinge> lista = Arrays.asList(
// new Pinge("OK","OK","OK","OK")
// );
TableView<Pinge> tabela = new TableView<>();
TableColumn colunahop = new TableColumn<>("Hop");
TableColumn colunaping1 = new TableColumn<>("Ping1");
TableColumn colunaping2 = new TableColumn<>("Ping2");
TableColumn colunaping3 = new TableColumn<>("Ping3");
colunahop.setCellValueFactory(new PropertyValueFactory<>("hop"));
colunaping1.setCellValueFactory(new PropertyValueFactory<>("ping1"));
colunaping2.setCellValueFactory(new PropertyValueFactory<>("ping2"));
colunaping3.setCellValueFactory(new PropertyValueFactory<>("ping3"));
tabela.getColumns().addAll(colunahop, colunaping1, colunaping2, colunaping3);
Button vai = new Button();
vai.setText("vai");
Label texto = new Label();
texto.setText("");
TextArea resultadow = new TextArea();
// Adicionar elementos na cena
noRaiz.getChildren().add(ip);
noRaiz.getChildren().add(vai);
noRaiz.getChildren().add(texto);
noRaiz.getChildren().add(tabela);
// noRaiz.getChildren().add(resultadow);
vai.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#SuppressWarnings("null")
#Override
public void handle(ActionEvent envent) {
String resultado = new String();
ip.setText("registro.br");
vai.setFocusTraversable(true);
texto.setText("Rastreando: " + ip.getText());
resultadow.setText("Rastreando: " + ip.getText());
resultado = application.NetworkDiagnostics.traceRoute(ip.getText());
// tabela.getItems().add(lista);
String[] result = resultado.split("\n");
String payload = null;
// lista.add(resultado);
int x1 = 0;
// lista.add(lista.lastIndexOf(lista)+1, new Pinge("TESTE","TESTE","TESTE","TESTE"));
List<Pinge> lista = null;
while (x1 < result.length) {
System.out.println(x1 + ": " + result[x1]);
String[] result1 = result[x1].split(";");
// payload = payload + result1[3] + ":" + result1[0] + ":" + result1[1] + ":" + result1[2] + "\n";
lista = Arrays.asList(new Pinge(result1[3],result1[0],result1[1],result1[2]));
// lista.add(new Pinge(result1[3],result1[0],result1[1],result1[2]));
resultadow.appendText(result1[3] + ":" + result1[0] + ":" + result1[1] + ":" + result1[2] + "\n");
//resultadow.setText(result[x1]);
x1++;
}
//List<Pinge> lista = Arrays.asList(new Pinge("TESTE","TESTE","TESTE","TESTE"));
tabela.setItems(FXCollections.observableArrayList(lista));
}
});
primaryStage.setScene(minhaCena);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static class Pinge {
private String hop;
private String ping1;
private String ping2;
private String ping3;
public Pinge(String hop, String ping1, String ping2, String ping3) {
this.hop = hop;
this.ping1 = ping1;
this.ping2 = ping2;
this.ping3 = ping3;
}
public String getHop() {
return hop;
}
public void setHop(String hop) {
this.hop = hop;
}
public String getPing1() {
return ping1;
}
public void setPing1(String ping1) {
this.ping1 = ping1;
}
public String getPing2() {
return ping2;
}
public void setPing2(String ping2) {
this.ping2 = ping2;
}
public String getPing3() {
return ping3;
}
public void setPing3(String ping3) {
this.ping3 = ping3;
}
}
public static void main(String[] args) {
launch(args);
}
}
This is the class where do the tracert command
NetworkDiagnostics.java
package application;
import java.io.BufferedWriter;
import application.Main;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NetworkDiagnostics {
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
private final String os = System.getProperty("os.name").toLowerCase();
public static String traceRoute(String string) {
String route = "";
String res = "";
int ms = 0;
File arquivo = new File("c:/pedro/tracert.log");
try {
Process traceRt;
traceRt = Runtime.getRuntime().exec("tracert " + string);
// read the output from the command
route = convertStreamToString(traceRt.getInputStream());
route = route.trim().replaceAll(" ", " ").replaceAll(" ", " ").replaceAll(" ms", "ms").replaceAll(" ", ",");
String[] split = route.trim().split("\n");
//regex ip and domain
String IPADDRESS_PATTERN = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
String DOMAIN_PATTERN = "^(www\\.|)(([a-zA-Z0-9])+\\.){1,4}[a-z]+$";
Pattern patternIP = Pattern.compile(IPADDRESS_PATTERN);
// Pattern patternDo = Pattern.compile(DOMAIN_PATTERN);
int x = 1;
while (x < split.length) {
// debug
System.out.println(split[x]);
int y = 0;
String[] details = split[x].split(",");
while (y < details.length) {
Matcher matcherIP = patternIP.matcher(details[y]);
// Matcher matcherDO = patternDo.matcher(details[y]);
if (details[y].contains("ms"))
{
res = res + details[y] + ";";
}
if (matcherIP.find()) {
res = res + matcherIP.group() + "\n";
}
y++;
}
x++;
}
convertStreamToString(traceRt.getErrorStream());
} catch (IOException e) {
}
try {
if (!arquivo.exists()) {
// cria um arquivo (vazio)
arquivo.createNewFile();
}
// caso seja um diretório, é possível listar seus arquivos e diretórios
File[] arquivos = arquivo.listFiles();
// escreve no arquivo
FileWriter fw = new FileWriter(arquivo, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(route.replaceAll("\\s", " "));
bw.newLine();
bw.close();
fw.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return res;
}
}
So I am writing an AutosuggestMenu that adds a listener to a TextField and recommends suggestions in a popup ContextMenu, based on comparing the keystrokes entered with the Collection of words provided.
Unfortunately, changes to the ContextMenu elements are not displayed, and I suspect this is because I am modifying the elements of the ObservableList associated with the ContextMenu and not the list itself.
Browsing stack has led to believe I should implement an extractor, but based on the examples provided I have no idea how to do this for my specific problem. Any solution would be very much appreciated!
Source:
package com.sknb.gui;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import javafx.geometry.Side;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class AutosuggestMenu {
public final static int DEFAULT_MENU_SIZE = 10;
//Data members
private int menuSize;
private Collection<String> wordList;
//GUI members
private ContextMenu menu;
private final Text textBefore, textMatching, textAfter;
public AutosuggestMenu(Collection<String> keyList) {
this(keyList, DEFAULT_MENU_SIZE);
}
public AutosuggestMenu(Collection<String> keyList, int numEntries) {
if (keyList == null) {
throw new NullPointerException();
}
this.wordList = keyList;
this.menuSize = numEntries;
this.menu = new ContextMenu();
for (int i = 0; i < this.menuSize; i++) {
CustomMenuItem item = new CustomMenuItem(new Label(), true);
this.menu.getItems().add(item);
}
this.textBefore = new Text();
this.textMatching = new Text();
this.textAfter = new Text();
}
public void addListener(TextField field) {
field.textProperty().addListener((observable, oldValue, newValue) -> {
String enteredText = field.getText();
if (enteredText == null || enteredText.isEmpty()) {
this.menu.hide();
} else {
List<String> filteredEntries = this.wordList.stream()
.filter(e -> e.contains(enteredText))
.collect(Collectors.toList());
if (!filteredEntries.isEmpty()) {
populatePopup(field, filteredEntries, enteredText);
if (!(this.menu.isShowing())) {
this.menu.show(field, Side.BOTTOM, 0, 0);
}
} else {
this.menu.hide();
}
}
});
field.focusedProperty().addListener((observableValue, oldValue, newValue) -> {
this.menu.hide();
});
}
private void populatePopup(TextField field, List<String> matches, String query) {
int i = 0,
max = (matches.size() > this.menuSize) ? this.menuSize :
matches.size();
for (MenuItem item : this.menu.getItems()) {
if (i < max) {
String result = matches.get(i);
item.setGraphic(generateTextFlow(result, query));
item.setVisible(true);
item.setOnAction(actionEvent -> {
field.setText(result);
field.positionCaret(result.length());
this.menu.hide();
});
} else {
item.setVisible(false);
}
i++;
}
}
private TextFlow generateTextFlow(String text, String filter) {
int filterIndex = text.indexOf(filter);
this.textBefore.setText(text.substring(0, filterIndex));
this.textAfter.setText(text.substring(filterIndex + filter.length()));
this.textMatching.setText(text.substring(filterIndex, filterIndex + filter.length()));
textMatching.setFill(Color.BLUE);
textMatching.setFont(Font.font("Helvetica", FontWeight.BOLD, 12));
return new TextFlow(textBefore, textMatching, textAfter);
}
public int getMenuSize() {
return this.menuSize;
}
public void setMenuSize(int size) {
this.menuSize = size;
}
public Collection<String> getKeyList() {
return this.wordList;
}
public void setKeyList(Collection<String> keyList) {
this.wordList = keyList;
}
//To do: add ways to change style of ContextMenu/menu items/text elements
}
Test class using a text file of English words as a dictionary:
package autosuggestfieldtest;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import com.sknb.gui.AutosuggestMenu;
public class AutosuggestFieldTest extends Application {
private TextField textfield;
private Collection<String> words;
private AutosuggestMenu popup;
#Override
public void start(Stage primaryStage) {
String filename = Paths.get("").toAbsolutePath().toString() + "\\words.txt";
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
words = stream
.collect(Collectors.toSet());
} catch (IOException e) {
System.out.println("DERP");
}
popup = new AutosuggestMenu(words);
textfield = new TextField();
popup.addListener(textfield);
StackPane root = new StackPane();
root.getChildren().add(textfield);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("AutocompleteField Test");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Note: this is a modification of a similar solution by Ruslan, but I was wondering if there is a solution that does not involve clearing/repopulating the menu with every keystroke? I.e. just using the setGraphic and refreshing the ContextMenu?
I am in the process of converting my GUI from Swing to JavaFX (so I can add custom styling things more easily).
I had my application working in Swing but I cannot get it to work in JavaFX.
What I want is to load an external applet into a SwingNode. The applet has music that automatically plays and I can hear it but I cannot see anything.
I'm struggling to find any relevant documentation or help on this.
My Code:
ClientNew.java
package rsclient.coregui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.concurrent.ExecutionException;
import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import rsloader.Loader;
public class ClientNew extends Application {
#Override
public void start(Stage stage) throws InterruptedException, ExecutionException {
SwingNode swingNode = new SwingNode();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final Loader loader = new Loader(Loader.Game.OSRS);
loader.applet.setLayout(null);
loader.applet.resize(800, 550);
JPanel gamepanel = new JPanel(new BorderLayout());
gamepanel.add(loader.applet, BorderLayout.CENTER);
swingNode.setContent(gamepanel);
gamepanel.setVisible(true);
}
});
Tab tab = new Tab();
tab.setText("My Tab");
tab.setClosable(false);
tab.setContent(swingNode);
TabP ane tabPane = new TabPane();
tabPane.getStyleClass().add("tabbedPane");
tabPane.getTabs().add(tab);
stage.setScene(
new Scene(
tabPane,
1000, 650
)
);
stage.setTitle("My APplication");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Loader.java (not my code but it seems to work. Will of course refactor later)
package rsloader;
import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import rsreflection.Reflector;
/***
*#author Xel
*#version 1.0
*#project RSLoader
*#file Loader.java
*#date 18.10.2013
*#time 10.43.48
*/
public class Loader implements AppletStub{
//insane declarations
public enum Game{OSRS, RS3, CLASSIC};
public static final HashMap<String, String> Parameters = new HashMap<String, String>();
public Game game;
public URL GamePack;
public Applet applet;
public String gameUrl;
public String MClass;
public Reflector loader;
public Loader(Game g)
{
game = g;
if(game == Game.OSRS)
gameUrl = "http://oldschool69.runescape.com/";
else if(game == Game.RS3)
gameUrl = "http://world1.runescape.com/";
else
gameUrl = "http://classic2.runescape.com/plugin.js?param=o0,a0,s0";
try {
GetParams(new URL(gameUrl));
loader = new Reflector(new URL[]{GamePack});
applet = (Applet)loader.loadClass(MClass).newInstance();
applet.setStub(this);
applet.init();
applet.start();
} catch (IOException | InstantiationException | IllegalAccessException | ClassNotFoundException e1) {
e1.printStackTrace();
}
}
public void GetParams(URL url) throws IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
String line;
List<String> params = new ArrayList<String>();
while((line = reader.readLine()) != null)
{
if(line.contains("param name"))
params.add(line);
if(GamePack == null) //retarted block
if(line.contains("archive"))
if(game != Game.CLASSIC)
GamePack = new URL(gameUrl + line.substring(line.indexOf("archive=") + 8, line.indexOf(" ');")));
else
GamePack = new URL("http://classic2.runescape.com/" + line.substring(line.indexOf("archive=") + 8, line.indexOf(" code")));
if(MClass == null)
if(line.contains("code="))
MClass = line.substring(line.indexOf("code=") + 5, line.indexOf(".class"));
}
reader.close();
for(String s : params)
{
Parameters.put(GetParamName(s), GetParamValue(s));
}
}
public String GetParamName(String param)
{
try{
int StartIndex = param.indexOf("<param name=\"") + 13;
int EndIndex = param.indexOf("\" value");
return param.substring(StartIndex, EndIndex);
}catch(StringIndexOutOfBoundsException e)//classic handles some differently so why not just catch it =P
{
int StartIndex = param.indexOf("<param name=") + 12;
int EndIndex = param.indexOf(" value");
return param.substring(StartIndex, EndIndex);
}
}
public String GetParamValue(String param)
{
try{
int StartIndex = param.indexOf("value=\"") + 7;
int EndIndex = param.indexOf("\">');");
return param.substring(StartIndex, EndIndex);
}catch(StringIndexOutOfBoundsException e)//and again :D
{
int StartIndex = param.indexOf("value=") + 6;
int EndIndex = param.indexOf(">');");
return param.substring(StartIndex, EndIndex);
}
}
#Override
public void appletResize(int arg0, int arg1) {
}
#Override
public AppletContext getAppletContext() {
return null;
}
#Override
public URL getCodeBase() {
try
{
if(game == Game.OSRS)
return new URL("http://oldschool1.runescape.com/");
else if(game == Game.RS3)
return new URL("http://world1.runescape.com/");
else
return new URL("http://classic2.runescape.com/");
}catch(MalformedURLException e)
{
e.printStackTrace();
}
return null;
}
#Override
public URL getDocumentBase() {
try
{
if(game == Game.OSRS)
return new URL("http://oldschool1.runescape.com/");
else if(game == Game.RS3)
return new URL("http://world1.runescape.com/");
else
return new URL("http://classic2.runescape.com/");
}catch(MalformedURLException e)
{
e.printStackTrace();
}
return null;
}
#Override
public String getParameter(String arg0) {
return Parameters.get(arg0);
}
#Override
public boolean isActive() {
return false;
}
}
To ANYONE who is coming upon this question for rendering applets with JavaFX
Swing DOES NOT support the rendering of Heavyweight components.
There is still, and has not been any support for heavyweight components, which obviously sucks for people looking to render heavyweight games or applications with javafx.
I also was trying to implement a swing applet into JavaFX. I could not see the app. After getting the size of the root pane I saw that it's Dimension was 0,0. The applet doesn't autosize with JavaFX. I added the following line to my init method in the JApplet.
this.getRootPane().setMinimumSize(new Dimension(900,600));
This allowed me to set the size of the applet. I am working on implementing a listener so that it will size with the window.
I have a Javafx TableView where I can add new Rows by double Click on an empty Row at the End of my "filled" / Textfield filled Rows.
My Problem is,if i add some Rows ,Java don't give me more of the empty Rows I could double click to add some Rows.
Edit:removed some unnessary log
To see what i mean, here is the Code:
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
interface inside_table
{
public void Select_Row_by_Col(int index);
}
public class Supermain extends Application {
ObservableList<myTextRow> data;
#Override
public void start(Stage primaryStage) {
ArrayList myindizes=new ArrayList();
final TableView<myTextRow> table = new TableView<>();
table.setEditable(true);
table.setStyle("-fx-text-wrap: true;");
//Table columns
TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory("text"));
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory("text2"));
//Add data
data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem","bla"),
new myTextRow(2, "Ipsum","bla")
);
table.getColumns().addAll(clmID, clmtext,clmtext2);
table.setItems(data);
table.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2 && mouseEvent.getY()>24) {
data.add(new myTextRow(td_get_biggest_ID() + 1,"",""));
table.selectionModelProperty().get().select(data.size()-1);
}
}
}
});
HBox hBox = new HBox();
hBox.setSpacing(5.0);
hBox.setPadding(new Insets(5, 5, 5, 5));
Button btn = new Button();
btn.setText("Get Data");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for (myTextRow data1 : data) {
System.out.println("data:" + data1.getText2());
}
}
});
hBox.getChildren().add(btn);
BorderPane pane = new BorderPane();
pane.setTop(hBox);
pane.setCenter(table);
primaryStage.setScene(new Scene(pane, 640, 480));
primaryStage.show();
class I_table implements inside_table{
#Override
public void Select_Row_by_Col(int index) {
table.getSelectionModel().select(index);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public static class TextFieldCellFactory
implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {
private String ColumnName;
public TextFieldCellFactory(String ColumnName){
this.ColumnName=ColumnName;
}
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell(this.ColumnName);
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
private String last_text;
private String ColumnName;
public TextFieldCell(String cname) {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
last_text="";
this.ColumnName=cname;
this.setGraphic(textField);
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if(this.ColumnName=="text2"){
if(isNowFocused){last_text=textField.getText();System.out.println("NOW focus "+last_text);}
if (! isNowFocused && ! isValid(textField.getText())) {
textField.setText(last_text);
//textField.setText("00:00:00:00");
textField.selectAll();
System.out.println("blur");
}
}
});
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// myindizes.add(getIndex());
// Retrieve the actual String Property that should be bound to the TextField
// If the TextField is currently bound to a different StringProperty
// Unbind the old property and rebind to the new one
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp = (SimpleStringProperty) ov;
if (this.boundToCurrently == null) {
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(sp);
} else if (this.boundToCurrently != sp) {
this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(this.boundToCurrently);
}
double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22);
textField.setPrefHeight(height);
textField.setMaxHeight(height);
textField.setMaxHeight(Double.MAX_VALUE);
// if height bigger than the biggest height in the row
//-> change all heights of the row(textfields ()typeof textarea) to this height
// else leave the height as it is
//System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
//this.textField.setText(item); // No longer need this!!!
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}//update
private boolean isValid(String s){
String splitArray[] = s.split(":");
if (splitArray.length != 4) {
System.out.println("false");
return false;
}
for (int i = 0; i < splitArray.length; i++) {
if (splitArray[i].length() != 2) {
System.out.println("false");
return false;
}
if (!splitArray[i].substring(0, 1).matches("[0-9]")) {
System.out.println("no number1");
return false;
}
if (!splitArray[i].substring(1, 2).matches("[0-9]")) {
System.out.println("no number2");
return false;
}
if (i < 3) {
int itest = Integer.parseInt(splitArray[i]);
if (itest > 59) {
System.out.println(itest + " ist zu groß!");
return false;
}
} else {
int itest2 = Integer.parseInt(splitArray[i]);
if (itest2 > Math.floor(25)) {
System.out.println(itest2 + " ist zu groß!");
return false;
}
//framerate!!!!!
}
System.out.println("splits: " + splitArray[i]);
//if( el.charAt(0).)
}
return true;
}
}
}
public class myTextRow {
private final SimpleIntegerProperty ID;
private final SimpleStringProperty text;
private final SimpleStringProperty text2;
public myTextRow(int ID, String text,String text2) {
this.ID = new SimpleIntegerProperty(ID);
this.text = new SimpleStringProperty(text);
this.text2 = new SimpleStringProperty(text2);
}
//setter
public void setID(int id) {
this.ID.set(id);
}
public void setText(String text) {
this.text.set(text);
}
public void setText2(String text) {
this.text2.set(text);
}
//getter
public int getID() {
return ID.get();
}
public String getText() {
return text.get();
}
public String getText2() {
return text2.get();
}
//properties
public StringProperty textProperty() {
return text;
}
public StringProperty text2Property() {
return text2;
}
public IntegerProperty IDProperty() {
return ID;
}
}
private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) {
HBox h = new HBox();
Label l = new Label("Text");
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
double line_height = l.prefHeight(-1);
int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length();
// System.out.println("new lines= "+new_lines);
String[] lines = s.split("\r\n|\r|\n");
// System.out.println("line count func= "+ lines.length);
int count = 0;
//double rest=0;
for (int i = 0; i < lines.length; i++) {
double text_width = get_text_width(lines[i]);
double plus_lines = Math.ceil(text_width / (width - widthCorrector));
if (plus_lines > 1) {
count += plus_lines;
//rest+= (text_width / (width-widthCorrector)) - plus_lines;
} else {
count += 1;
}
}
//count+=(int) Math.ceil(rest);
count += new_lines - lines.length;
return count * line_height + heightCorrector;
}
private static double get_text_width(String s) {
HBox h = new HBox();
Label l = new Label(s);
l.setWrapText(false);
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
// System.out.println("FXMLDocumentController.get_text_width(): "+l.prefWidth(-1));
return l.prefWidth(-1);
}
public int td_get_biggest_ID() {
int biggest = 0;
for (int i = 0; i < data.size(); i++) {
if (((myTextRow) data.get(i)).getID() > biggest) {
biggest = ((myTextRow) data.get(i)).getID();
}
}
return biggest;
}
}
Just click anywhere else on the TableView but make sure it's at least 24 pixels from the top; This will work since you've added the event handler is added to the TableView...
If you only want to use the last row, then use a custom rowFactory and handle the events there.
Add a placeholder item to the TableView items that marks the row that is used for adding new elements (for some reason the selection model doesn't like null):
final myTextRow addPlaceHolder = new myTextRow(Integer.MIN_VALUE, null, null);
...
//Add data
data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem", "bla"),
new myTextRow(2, "Ipsum", "bla"),
addPlaceHolder
);
make sure your TextFieldCells treat null values as empty rows:
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
...
make sure the first column does not display anything for the placeholder
//Table columns
TableColumn<myTextRow, Number> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(cdf -> {
myTextRow item = cdf.getValue();
return item == addPlaceHolder ? Bindings.createObjectBinding(() -> null) : item.IDProperty();
});
and use the following rowFactory to handle adding the items (you don't need the updateItem part unless you need to add a style class to the TableRow; you need not extend TableRow in this case)
table.setRowFactory(tv -> new TableRow<myTextRow>() {
{
setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton() == MouseButton.PRIMARY
&& mouseEvent.getClickCount() == 2
&& !isEmpty()
&& getItem() == addPlaceHolder) {
data.add(data.size() - 1, new myTextRow(td_get_biggest_ID() + 1, "", ""));
table.selectionModelProperty().get().select(data.size() - 1);
mouseEvent.consume();
}
});
}
#Override
protected void updateItem(myTextRow item, boolean empty) {
super.updateItem(item, empty);
// add style class for row containing addPlaceHolder
List<String> classes = getStyleClass();
final String clazz = "add-row";
if (item == addPlaceHolder) {
if (!classes.contains(clazz)) {
classes.add(clazz);
}
} else {
classes.remove(clazz);
}
}
});
Alright, So im doing Keypressed and keyreleased, and that works with VK_ stuff.... i have a GUi ready and im able to save and load config files, but i was wondering on how i can change the end of r.keyPress(KeyEvent.VK_W) the W out of the VK with my code....
Here is my main
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class Main {
public static void main(String[] args) throws Exception{
Config bot = new Config();
bot.setVerbose(true);
bot.connect("irc.twitch.tv", 6667, "oauth:6u54pi07uzegv42dwee65gpgzmwwgi");
bot.joinChannel("#mmolegion");
JFrame frame = new JFrame("TwitchBot");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(700, 500));
frame.setLocationRelativeTo(null);
frame.setResizable(true);
KeyGetter.LoadKeys();
try {
Config.loadConfig();
} catch (Exception e) {
e.printStackTrace();
}
JMenuBar mb = new JMenuBar();
JMenu file = new JMenu("File");
mb.add(file);
JMenu edit = new JMenu("Edit");
mb.add(edit);
JMenuItem options = new JMenuItem("Options");
options.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Config.openConfig(frame);
}
});
frame.setJMenuBar(mb);
edit.add(options);
frame.pack();
frame.setVisible(true);
}
}
and he is my Config
import java.awt.Choice;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import org.jibble.pircbot.PircBot;
public class Config extends PircBot{
public static String left = "up", right = "right", up = "up", down = "down";
private static ArrayList<Choice> choices;
public Config() {
this.setName("Rex__Bot");
}
public void onMessage(String channel, String sender, String login, String hostname, String message) {
if(message.equals("up")) {
try {
Robot r = new Robot();
r.keyPress(KeyEvent.VK_W);
r.delay(300);
r.keyRelease(KeyEvent.VK_W);
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
public static void openConfig(JFrame frame){
choices = new ArrayList<Choice>();
JFrame options = new JFrame("Options");
options.setSize(600, 400);
options.setResizable(false);
options.setLocationRelativeTo(frame);
options.setLayout(null);
Choice left = addChoice("left", options, 30, 30);
left.select(Config.left);
Choice right = addChoice("right", options, 30, 80);
right.select(Config.right);
Choice up = addChoice("up", options, 150, 30);
up.select(Config.up);
Choice down = addChoice("down", options, 150, 80);
down.select(Config.down);
JButton done = new JButton("ok");
done.setBounds(150, 220, 100, 30);
done.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
options.dispose();
saveChanges();
}
});
options.add(done);
options.setVisible(true);
}
public static void saveChanges(){
Choice left = choices.get(0);
Choice right = choices.get(1);
Choice up = choices.get(2);
Choice down = choices.get(3);
Config.left = left.getSelectedItem();
Config.right = right.getSelectedItem();
Config.up = up.getSelectedItem();
Config.down = down.getSelectedItem();
try{
saveConfig();
}
catch(Exception e){
e.printStackTrace();
}
}
public static Choice addChoice(String name, JFrame options, int x, int y){
JLabel label = new JLabel(name);
label.setBounds(x, y - 20, 100, 20);
Choice key = new Choice();
for(String s: getKeyNames()){
key.add(s);
}
key.setBounds(x, y, 100, 20);
options.add(key);
options.add(label);
choices.add(key);
return key;
}
public static ArrayList<String> getKeyNames(){
ArrayList<String> result = new ArrayList<String>();
for(String s: KeyGetter.keyNames){
result.add(s);
if(s.equalsIgnoreCase("F24")){
break;
}
}
return result;
}
public static void loadConfig() throws Exception{
File directory = new File(getDefaultDirectory(), "/Twitchbot");
if(!directory.exists()){
directory.mkdirs();
}
File config = new File(directory,"config.txt");
if(!config.exists()){
config.createNewFile();
System.out.println("File not found, saving default");
saveConfig();
return;
}
#SuppressWarnings("resource")
Scanner s = new Scanner(config);
HashMap<String, String> values = new HashMap<String, String>();
while(s.hasNextLine()){
String[] entry = s.nextLine().split(":");
String key = entry[0];
String value = entry[1];
values.put(key, value);
}
if(!values.containsKey("left") || !values.containsKey("right") || !values.containsKey("up") || !values.containsKey("down")){
System.out.println("Invalid names in config, saving default config");
saveConfig();
return;
}
String left = values.get("left");
String right = values.get("right");
String up = values.get("up");
String down = values.get("down");
if(!(getKeyNames().contains(left) && getKeyNames().contains(right) && getKeyNames().contains(up) && getKeyNames().contains(down))){
System.out.println("Invalid key in config, saving default config");
}
Config.left = left;
Config.right = right;
Config.up = up;
Config.down = down;
}
public static void saveConfig() throws Exception{
File directory = new File(getDefaultDirectory(), "/Twitchbot");
if(!directory.exists()){
directory.mkdirs();
}
File config = new File(directory,"config.txt");
PrintWriter pw = new PrintWriter(config);
pw.println("left:" + left);
pw.println("right:" + right);
pw.println("up:" + up);
pw.println("down:" + down);
pw.close();
}
public static String getDefaultDirectory(){
String OS = System.getProperty("os.name").toUpperCase();
if(OS.contains("WIN")){
return System.getenv("APPDATA");
}
if(OS.contains("MAC")){
return System.getProperty("user.home") + "Library/Application Support";
}
return System.getProperty("user.home");
}
}
and here is my KeyGetter
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
public class KeyGetter {
public static HashMap<String, Integer> keys;
public static ArrayList<String> keyNames;
public static void LoadKeys(){
keys = new HashMap<String, Integer>();
keyNames = new ArrayList<String>();
Field[] fields = KeyEvent.class.getFields();
for(Field f: fields){
if(Modifier.isStatic(f.getModifiers())){
if(f.getName().startsWith("VK")){
try{
int num = f.getInt(null);
String name = KeyEvent.getKeyText(num);
keys.put(name, num);
keyNames.add(name);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
}
}
So is there anyway of changing the The last letter of VK_W with my config file?
I don't know if you can do this.
Why don't you just save int values. For example KeyEvent.VK_W transforms to:
public static final int VK_W = 87;
So it would be much easier if you would just save int walues to your configuration.
Here can you find the whole list:
KeyEvent.VK_W
So you can just use the following code:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 87) {
System.out.println("W pressed");
}
}
Instead of:
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W) {
System.out.println("W pressed");
}
}