I am using JavaFX for my application. In my application I have a button,on click on that button should display the results on textarea, that I am able to do. Now I would like to select the entire line on click from the text area. But The code which I have written is able to select only the value which I click which means like only word on which I have clicked. Please suggest me to modify this.
#FXML
public void find_btn_action(ActionEvent event) throws MWException
{
double[] peaks= {1.2,5.6,8.0,9.0};
StringBuilder sb = new StringBuilder(peaks.length);
for(int i= 0; i < peaks.length ; i++)
{
result[i] = peaks[i];
sb.append(result[i]+"\n");
}
auto.setText(sb.toString());
auto.setOnMouseClicked(new EventHandler<Event>()
{
#Override
public void handle(Event arg0)
{
selectedVal = auto.getSelectedText();
System.out.println("selected text:"+ selectedVal);
}
});
}
In your mouse click listener check, if the click was inside the content area and if this is the case, use the caret position to determine the next/previous line break in the TextArea's text and select this range:
textArea.setOnMouseClicked(evt -> {
if (evt.getButton() == MouseButton.PRIMARY) {
// check, if click was inside the content area
Node n = evt.getPickResult().getIntersectedNode();
while (n != textArea) {
if (n.getStyleClass().contains("content")) {
// find previous/next line break
int caretPosition = textArea.getCaretPosition();
String text = textArea.getText();
int lineBreak1 = text.lastIndexOf('\n', caretPosition - 1);
int lineBreak2 = text.indexOf('\n', caretPosition);
if (lineBreak2 < 0) {
// if no more line breaks are found, select to end of text
lineBreak2 = text.length();
}
textArea.selectRange(lineBreak1, lineBreak2);
evt.consume();
break;
}
n = n.getParent();
}
}
});
Related
I would like to begin editing cells on my TableView on a single click rather than a double click.
I tried the following, but it does not work.
tableView.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
TablePosition selectedCellPosition = tableView.getFocusModel().getFocusedCell();
if ( selectedCellPosition != null ) {
tableView.edit(selectedCellPosition.getRow(), selectedCellPosition.getTableColumn());
}
}
});
How can I make it so the table cell begins editing on the first click rather than on a double click?
This worked for me. The Platform.runLater() was necessary for some reason.
tableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
int row = tableView.getSelectionModel().getSelectedCells().get(0).getRow();
Platform.runLater(() -> tableView.edit(row, columnToEdit));
}
});
i have a problem with my searching method.
With this method, I can enter a word in the textfield and display the word in the textarea. However, this only happens once if i let it run. I need to expand it so, that every time I click on "enter," the program should continue with searching in the textarea. How can i do this?
And please give me code examples. i have only 2 days left for my presentation.
Thanks a lot for the helps
textfield.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER) {
String text = textarea.getText();
Labeled errorText = null;
if (textfield.getText() != null && !textfield.getText().isEmpty()) {
index = textarea.getText().indexOf(textfield.getText());
textarea.getText();
if (index == -1) {
errorText.setText("Search key Not in the text");
} else {
// errorText.setText("Found");
textarea.selectRange(index, index + textfield.getLength());
}
}
}
}
});
There's an overloaded version of the indexOf method allowing you to search starting at a specific index. Keep track of the index of your last find and start searching from this position:
#Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField("foo");
TextArea textarea = new TextArea();
for (int i = 0; i < 10; i++) {
textarea.appendText("foo\nbarfoobarfoofoo\n");
}
textField.setOnAction(evt -> {
String searchText = textField.getText();
if (searchText.isEmpty()) {
return; // searching for empty text doesn't make sense
}
int index = textarea.getSelection().getEnd();
// in case of the first search, start at the beginning
// TODO: adjust condition/starting index according to needs
if (textarea.getSelection().getLength() == 0) {
index = 0;
}
// find next occurrence
int newStartIndex = textarea.getText().indexOf(searchText, index);
// mark occurrence
if (newStartIndex >= 0) {
textarea.selectRange(newStartIndex, newStartIndex + searchText.length());
}
});
Scene scene = new Scene(new VBox(textField, textarea));
primaryStage.setScene(scene);
primaryStage.show();
}
Edit
If you are not satisfied with searching the element after the selection ( or after the cursor, if there is no range selected), you could save the data of the end of the last match:
#Override
public void start(Stage primaryStage) throws Exception {
TextField textField = new TextField("foo");
TextArea textarea = new TextArea();
for (int i = 0; i < 10; i++) {
textarea.appendText("foo\nbarfoobarfoofoo\n");
}
class SearchHandler implements EventHandler<ActionEvent> {
int index = 0;
#Override
public void handle(ActionEvent event) {
String searchText = textField.getText();
String fullText = textarea.getText();
if (index + searchText.length() > fullText.length()) {
// no more matches possible
// TODO: notify user
return;
}
// find next occurrence
int newStartIndex = textarea.getText().indexOf(searchText, index);
// mark occurrence
if (newStartIndex >= 0) {
index = newStartIndex + searchText.length();
textarea.selectRange(newStartIndex, index);
} else {
index = fullText.length();
// TODO: notify user
}
}
}
SearchHandler handler = new SearchHandler();
textField.setOnAction(handler);
// reset index to search from start when changing the text of the TextField
textField.textProperty().addListener((o, oldValue, newValue) -> handler.index = 0);
Scene scene = new Scene(new VBox(textField, textarea));
primaryStage.setScene(scene);
primaryStage.show();
}
How do I sort through an array of buttons to see if only one is left enabled? I am creating a Sudoku solver and need to check if there is only one button left unselected in each row, column, or box and if it is to highlight the last remaining option. I can't find a command that will allow me to check each individual cell in the row to see if ONLY one is left. This is what I have so far
public class SudoHelper extends Application
{
public boolean [][][] DisabledCell = new boolean[3][9][9]; // Creates our array
Scene scene;
Pane pane;
Pane main;
BookMark bane;
#Override
public void start (Stage primaryStage)
{
for(int a = 0;a<3;a++)
{
for(int b=0;b<9;b++)
{
for(int c=0; c<9;c++)
{
DisabledCell[a][b][c]=false;
}
}
}
mouseClicks = new MouseEvent[0];
SmartCell[] currentGame = new SmartCell[81];
pane = new Pane();
pane.setPrefSize(684, 702);
int x,y;
x=y=0;
main = new Pane();
for(int i=0; i<81; i++)
{
currentGame[i]= new SmartCell(i);
currentGame[i].setLayoutX(x);
currentGame[i].setLayoutY(y);
pane.getChildren().add(currentGame[i]);
x+=76; // Sets the layout for out array of SmartCells
if(x==684) // and puts our additional buttons on the screen
{ // With our scene and stage
x=0;
y+=78;
}
}
main.setPrefSize(1100, 702);
main.getChildren().add(pane);
bane= new BookMark();
scene = new Scene(main);
main.getChildren().add(bane);
bane.setPrefSize(416, 702);
bane.setLayoutX(685);
bane.setLayoutY(0);
primaryStage.setScene(scene);
primaryStage.setTitle("Sudoku Helper");
primaryStage.show();
}
public static void main(String[] args)
{
Application.launch(args); // Starts the game
}
class BookMark extends Pane
{
class List
{
String[] MyList=new String[0];
public void Add(String Add)
{
if(this.MyList.length>0)
{
String[] Resize = new String[this.MyList.length+1];
for(int i=0;i<this.MyList.length;i++)
{
Resize[i]=this.MyList[i];
}
Resize[this.MyList.length+1]=Add;
}
else
{
this.MyList = new String[1];
this.MyList[0]=Add;
}
}
public void Clear()
{
this.MyList = new String[0];
}
}
Button lkm = new Button("Load Bookmark"); // Creates our load bookmark button
Button bkm = new Button("Save Bookmark"); // Creates out save bookmark button'
final ToggleGroup group1 = new ToggleGroup();
final ToggleGroup group2 = new ToggleGroup();
RadioButton rl1a = new RadioButton("Rule One All"); // Creates rule one radiobutton
RadioButton rl1s = new RadioButton("Rule One Click"); // Creates Rule one click radiobutton
RadioButton rl2s = new RadioButton("Rule Two Click"); // Creates rule two click radiobutton
RadioButton rl2a = new RadioButton("Rule Two All"); // Create rule two radiobutton
void ruleTwo()
{
}
void ruleOne()
{
int _x,_y;
int B=10;
String[]Getloc = name.split("~");
int loc = Integer.parseInt(Getloc[1]);
_y = loc%9;
if(loc<8) // checking which row we are looking at
{
_x=0;
for(_x=0; loc<8;)
{
if()
{
}
}
}
else if(loc<18)
{
_x=1;
}
else if(loc<27)
{
_x=2;
}
else if(loc<36)
{
_x=3;
}
else if(loc<45)
{
_x=4;
}
else if(loc<54)
{
_x=5;
}
else if(loc<63)
{
_x=6;
}
else if(loc<72)
{
_x=7;
}
else
{
_x=8; // checks blocks were looking at
}
if(_y>=0&&_y<=2) // checks which block we are in
{
if(_x>=0&&_x<=2)
{
B=0;
}
else if(_x>=3&&_x<=5)
{
B=1;
}
else if(_x>=6&&_x<=8)
{
B=2;
}
}
else if(_y>=3&&_y<=5)
{
if(_x>=0&&_x<=2)
{
B=3;
}
else if(_x>=3&&_x<=5)
{
B=4;
}
else if(_x>=6&&_x<=8)
{
B=5;
}
}
else if(_y>=6&&_y<=8)
{
if(_x>=0&&_x<=2)
{
B=6;
}
else if(_x>=3&&_x<=5)
{
B=7;
}
else if(_x>=6&&_x<=8)
{
B=8;
}
}
}
BookMark() // Our buttons specifications (Location font ect)
{
this.bkm = new Button("Save Bookmark");
this.lkm = new Button("Load Bookmark");
this.bkm.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.bkm.setLayoutX(10);
this.bkm.setLayoutY(10);
this.lkm.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.lkm.setLayoutX(150);
this.lkm.setLayoutY(10);
this.rl1a.setLayoutX(10);
this.rl1a.setLayoutY(250);
this.rl2a.setLayoutX(10);
this.rl2a.setLayoutY(500);
this.rl2s.setLayoutX(250);
this.rl1s.setLayoutY(250);
this.rl1s.setLayoutX(250);
this.rl2s.setLayoutY(500);
this.rl1a.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl1s.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl2a.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.rl2s.setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
this.group1.getToggles().add(this.rl1a);
this.group1.getToggles().add(this.rl1s);
this.group2.getToggles().add(this.rl2a);
this.group2.getToggles().add(this.rl2s);
BookMark.this.getChildren().add(this.lkm);
BookMark.this.getChildren().add(this.bkm);
BookMark.this.getChildren().add(this.rl1a);
BookMark.this.getChildren().add(this.rl1s);
BookMark.this.getChildren().add(this.rl2a);
BookMark.this.getChildren().add(this.rl2s);
// bkm.setOnMouseClicked(e -> Save(e));
}
}
private MouseEvent[] mouseClicks;
class SmartCell extends StackPane
{
GridPane buttonPane;
Pane valPane;
Text textVal;
Button [] btn;
String name;
SmartCell(int nameint)
{
buttonPane = new GridPane();
btn = new Button[10];
for(int i = 1; i <= 9; i++)
{
btn[i] = new Button(i+""); // Turns i into a String
btn[i].setFont(Font.font("Ariel", FontWeight.BOLD, FontPosture.REGULAR, 12));
btn[i].setOnMouseClicked(e -> mouseHandler(e));
buttonPane.add(btn[i], (i-1)%3, (i-1)/3);
}
// When the user clicks one of the 9 buttons, we want to take the number of the button
// they clicked, and set the text on the text pane to that number, hide the 9 buttons,
// and show the text pane.
name = "SmartCell~"+String.valueOf(nameint);
textVal = new Text(25, 55, "");
textVal.setFont(Font.font("Arial", 48));
textVal.setTextAlignment(TextAlignment.CENTER);
valPane = new Pane();
valPane.setStyle("-fx-border-color:black; -fx-border-stroke-width:1");
valPane.getChildren().add(textVal);
getChildren().add(buttonPane); // Add the pane with the 9 buttons to the cell
getChildren().add(valPane); // Add the pane with the one piece of text to the cell
buttonPane.setVisible(true); // We start out showing the 9 buttons
valPane.setVisible(false); // ...NOT showing the pane with the single text
} // end constructor
void disqual(MouseEvent e)
{
MouseEvent[] ResizeMouse = new MouseEvent[SudoHelper.this.mouseClicks.length+1];
ResizeMouse[ResizeMouse.length-1]=e;
SudoHelper.this.mouseClicks = ResizeMouse;
int _x,_y;
int B=10;
String[]Getloc = name.split("~");
int loc = Integer.parseInt(Getloc[1]);
_y = loc%9;
if(loc<8) // checking which row we are looking at
{
_x=0;
}
else if(loc<18)
{
_x=1;
}
else if(loc<27)
{
_x=2;
}
else if(loc<36)
{
_x=3;
}
else if(loc<45)
{
_x=4;
}
else if(loc<54)
{
_x=5;
}
else if(loc<63)
{
_x=6;
}
else if(loc<72)
{
_x=7;
}
else
{
_x=8; // checks blocks were looking at
}
if(_y>=0&&_y<=2) // checks which block we are in
{
if(_x>=0&&_x<=2)
{
B=0;
}
else if(_x>=3&&_x<=5)
{
B=1;
}
else if(_x>=6&&_x<=8)
{
B=2;
}
}
else if(_y>=3&&_y<=5)
{
if(_x>=0&&_x<=2)
{
B=3;
}
else if(_x>=3&&_x<=5)
{
B=4;
}
else if(_x>=6&&_x<=8)
{
B=5;
}
}
else if(_y>=6&&_y<=8)
{
if(_x>=0&&_x<=2)
{
B=6;
}
else if(_x>=3&&_x<=5)
{
B=7;
}
else if(_x>=6&&_x<=8)
{
B=8;
}
};
int CellNum =Integer.parseInt(((Button)e.getSource()).getText());
if(DisabledCell[0][_x][CellNum-1]==true||DisabledCell[1][_y][CellNum-1]==true||DisabledCell[2][B][CellNum-1]==true)
{
disqualify(Integer.parseInt(((Button)e.getSource()).getText()));
return;
}
DisabledCell[0][_x][CellNum-1]=true;
DisabledCell[1][_y][CellNum-1]=true;
DisabledCell[2][B][CellNum-1]=true;
textVal.setText(((Button)e.getSource()).getText());
buttonPane.setVisible(false);
valPane.setVisible(true);
for(int i = 1; i <= 9; i++)disqualify(i); // Since we have locked in, all others are out of play
// in this cell
int c = 0;
int z = 0;
switch(B)
{ // Figures out which block our selected number is in.
case 0: z=0;
break; // ^
case 1: z=27;
break; // ^
case 2: z=54;
break; // ^
case 3: z=3;
break; // ^
case 4: z=30;
break; // ^
case 5: z=57;
break; // ^
case 6: z=6;
break; // ^
case 7: z=33;
break; // ^
case 8: z=60;
break; // ^
}
for(int w = 0; w<9; w++)
{
Object xob =SudoHelper.this.pane.getChildren().get((_x*9)+w);
SmartCell d =SmartCell.class.cast(xob); // Disqualifies x cells
d.disqualify(CellNum);
xob=d;
Object yob =SudoHelper.this.pane.getChildren().get(_y+(9*w));
SmartCell b =SmartCell.class.cast(yob); // Disqualifies Y Cells
b.disqualify(CellNum);
yob=b;
Object zob =SudoHelper.this.pane.getChildren().get(z+c);
SmartCell a =SmartCell.class.cast(zob);
a.disqualify(CellNum); // Disqualifies boxes
zob=a;
c++;
if(c==3)
{
z+=9;
c=0;
}
}
}
void mouseHandler(MouseEvent e)
{
// When any button gets clicked, we take the text from the button, put it on the Text
// shape, hide the pane with the 9 buttons, and show the text pane, making it look like
// the 9 buttons have "gone", and the new value that we have "locked in" has taken their place.
//
if(e.getSource() instanceof Button)
{
// If this was a right click, then just disable this button; If it was a left click then lock
// in the value this button represents.
if(e.getButton() == MouseButton.SECONDARY)
{
disqualify(Integer.parseInt(((Button)e.getSource()).getText()));
// disables button after clicked
return;
}
// System.out.print("A button was clicked"); // for debugging
disqual(e);
} // end if source was a button
} // end mouseHandler
void disqualify(int buttonNo)
{
// When we are called, we disable button #buttonNo in this cell
btn[buttonNo].setDisable(true);
btn[buttonNo].setStyle("-fx-base:black; -fx-text-fill:black; -fx-opacity:1.0"); // Sets color of cells and numbers after disabled.
}
public String toString()
{
// The toString representation of a cell is a string containing a list of
// the values "still in play" --- the remaining candidate values --- for the cell
//
// Start with an empty string. Visit all 9 buttons, and if a given button is
// not disabled (i.e still in play), then add its number (from the text on the
// button) to our string
//
String result = "";
for(int i = 1; i <= 9; i++)
if(!btn[i].isDisabled())
result += i;
return result;
}
}
private boolean[] InitalizeTile() // Initalizes our board of 81 cells
{
boolean[] newbool = new boolean[81];
for(int i=0; i<81; i++)
{
newbool[i] = false;
}
Random R = new Random();
for(int j=0; j<0; j++)
{
while(true)
{
int W = R.nextInt(81);
if(newbool[W]==false)
{
newbool[W]=true;
break;
}
}
}
return newbool;
}
}
All I really need to know is how to look at an array of buttons and see if only one is left enabled.
Arrays.stream(buttons).filter(button -> !button.isDisabled()).count() == 1
Sample application:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.util.Arrays;
public class DisabledButtonCount extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button[] buttons = {
new Button("1"),
new Button("2"),
new Button("3")
};
buttons[1].setDisable(true);
buttons[2].setDisable(true);
System.out.println(
"Only one button enabled? " +
(Arrays.stream(buttons).filter(button -> !button.isDisabled()).count() == 1)
);
Platform.exit();
}
}
I've created a TableView where each cell contains a TextField or a CheckBox. In the TableView you're supposed to be able to navigate left and right between cells using TAB and SHIFT+TAB, and up and down between cells using the UP and DOWN keys.
This works perfectly when a text field cell is focused. But when a check box cell is focused, the tab funcationality behaves strange. You can tab in the opposite direction of the cell you tabbed from, but you can't switch tab direction.
So for instance if you tabbed to the check box cell using only the TAB key, then SHIFT+TAB wont work. But if you tab to the next cell using the TAB key, and then TAB back using SHIFT+TAB (assuming the next cell is a text field cell), then TAB wont work.
I've tried running any code handling focus on the UI thread using Platform.runLater(), without any noteable difference. All I know is that the TAB KeyEvent is properly catched, but the check box cell and the check box never loses focus in the first place anyway. I've tried for instance removing its focus manually by doing e.g. getParent().requestFocus() but that just results in the parent being focused instead of the next cell. What makes it strange is that the same code is executed and working properly when you tab in the opposite direction of the cell you came from.
Here's a MCVE on the issue. Sadly it does not really live up to the "M" of the abbreviation:
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class AlwaysEditableTable extends Application {
public void start(Stage stage) {
TableView<ObservableList<StringProperty>> table = new TableView<>();
table.setEditable(true);
table.getSelectionModel().setCellSelectionEnabled(true);
table.setPrefWidth(510);
// Dummy columns
ObservableList<String> columns = FXCollections.observableArrayList("Column1", "Column2", "Column3", "Column4",
"Column5");
// Dummy data
ObservableList<StringProperty> row1 = FXCollections.observableArrayList(new SimpleStringProperty("Cell1"),
new SimpleStringProperty("Cell2"), new SimpleStringProperty("0"), new SimpleStringProperty("Cell4"),
new SimpleStringProperty("0"));
ObservableList<StringProperty> row2 = FXCollections.observableArrayList(new SimpleStringProperty("Cell1"),
new SimpleStringProperty("Cell2"), new SimpleStringProperty("1"), new SimpleStringProperty("Cell4"),
new SimpleStringProperty("0"));
ObservableList<StringProperty> row3 = FXCollections.observableArrayList(new SimpleStringProperty("Cell1"),
new SimpleStringProperty("Cell2"), new SimpleStringProperty("1"), new SimpleStringProperty("Cell4"),
new SimpleStringProperty("0"));
ObservableList<ObservableList<StringProperty>> data = FXCollections.observableArrayList(row1, row2, row3);
for (int i = 0; i < columns.size(); i++) {
final int j = i;
TableColumn<ObservableList<StringProperty>, String> col = new TableColumn<>(columns.get(i));
col.setCellValueFactory(param -> param.getValue().get(j));
col.setPrefWidth(100);
if (i == 2 || i == 4) {
col.setCellFactory(e -> new CheckBoxCell(j));
} else {
col.setCellFactory(e -> new AlwaysEditingCell(j));
}
table.getColumns().add(col);
}
table.setItems(data);
Scene scene = new Scene(table);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
/**
* A cell that contains a text field that is always shown.
*/
public static class AlwaysEditingCell extends TableCell<ObservableList<StringProperty>, String> {
private final TextField textField;
public AlwaysEditingCell(int columnIndex) {
textField = new TextField();
this.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
setGraphic(null);
} else {
setGraphic(textField);
}
});
// The index is not changed until tableData is instantiated, so this
// ensure the we wont get a NullPointerException when we do the
// binding.
this.indexProperty().addListener((obs, oldValue, newValue) -> {
ObservableList<ObservableList<StringProperty>> tableData = getTableView().getItems();
int oldIndex = oldValue.intValue();
if (oldIndex >= 0 && oldIndex < tableData.size()) {
textField.textProperty().unbindBidirectional(tableData.get(oldIndex).get(columnIndex));
}
int newIndex = newValue.intValue();
if (newIndex >= 0 && newIndex < tableData.size()) {
textField.textProperty().bindBidirectional(tableData.get(newIndex).get(columnIndex));
setGraphic(textField);
} else {
setGraphic(null);
}
});
// Every time the cell is focused, the focused is passed down to the
// text field and all of the text in the textfield is selected.
this.focusedProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
textField.requestFocus();
textField.selectAll();
System.out.println("Cell focused!");
}
});
// Switches focus to the cell below if ENTER or the DOWN arrow key
// is pressed, and to the cell above if the UP arrow key is pressed.
// Works like a charm. We don't have to add any functionality to the
// TAB key in these cells because the default tab behavior in
// JavaFX works here.
this.addEventFilter(KeyEvent.KEY_RELEASED, e -> {
if (e.getCode().equals(KeyCode.UP)) {
getTableView().getFocusModel().focus(getIndex() - 1, this.getTableColumn());
e.consume();
} else if (e.getCode().equals(KeyCode.DOWN)) {
getTableView().getFocusModel().focus(getIndex() + 1, this.getTableColumn());
e.consume();
} else if (e.getCode().equals(KeyCode.ENTER)) {
getTableView().getFocusModel().focus(getIndex() + 1, this.getTableColumn());
e.consume();
}
});
}
}
/**
* A cell containing a checkbox. The checkbox represent the underlying value
* in the cell. If the cell value is 0, the checkbox is unchecked. Checking
* or unchecking the checkbox will change the underlying value.
*/
public static class CheckBoxCell extends TableCell<ObservableList<StringProperty>, String> {
private final CheckBox box;
public CheckBoxCell(int columnIndex) {
this.box = new CheckBox();
this.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
setGraphic(null);
} else {
setGraphic(box);
}
});
this.indexProperty().addListener((obs, oldValue, newValue) -> {
// System.out.println("Row: " + getIndex() + ", Column: " +
// columnIndex + ". Old index: " + oldValue
// + ". New Index: " + newValue);
ObservableList<ObservableList<StringProperty>> tableData = getTableView().getItems();
int newIndex = newValue.intValue();
if (newIndex >= 0 && newIndex < tableData.size()) {
// If active value is "1", the check box will be set to
// selected.
box.setSelected(tableData.get(getIndex()).get(columnIndex).equals("1"));
// We add a listener to the selected property. This will
// allow us to execute code every time the check box is
// selected or deselected.
box.selectedProperty().addListener((observable, oldVal, newVal) -> {
if (newVal) {
// If newValue is true the checkBox is selected, and
// we set the corresponding cell value to "1".
tableData.get(getIndex()).get(columnIndex).set("1");
} else {
// Otherwise we set it to "0".
tableData.get(getIndex()).get(columnIndex).set("0");
}
});
setGraphic(box);
} else {
setGraphic(null);
}
});
// If I listen to KEY_RELEASED instead, pressing tab next to a
// checkbox will make the focus jump past the checkbox cell. This is
// probably because the default TAB functionality is invoked on key
// pressed, which switches the focus to the check box cell, and then
// upon release this EventFilter catches it and switches focus
// again.
this.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode().equals(KeyCode.UP)) {
System.out.println("UP key pressed in checkbox");
getTableView().getFocusModel().focus(getIndex() - 1, this.getTableColumn());
e.consume();
} else if (e.getCode().equals(KeyCode.DOWN)) {
System.out.println("DOWN key pressed in checkbox");
getTableView().getFocusModel().focus(getIndex() + 1, this.getTableColumn());
e.consume();
} else if (e.getCode().equals(KeyCode.TAB)) {
System.out.println("Checkbox TAB pressed!");
TableColumn<ObservableList<StringProperty>, ?> nextColumn = getNextColumn(!e.isShiftDown());
if (nextColumn != null) {
getTableView().getFocusModel().focus(getIndex(), nextColumn);
}
e.consume();
// ENTER key will set the check box to selected if it is
// unselected and vice versa.
} else if (e.getCode().equals(KeyCode.ENTER)) {
box.setSelected(!box.isSelected());
e.consume();
}
});
// Tracking the focused property of the check box for debug
// purposes.
box.focusedProperty().addListener((obs, oldValue, newValue) ->
{
if (newValue) {
System.out.println("Box focused on index " + getIndex());
} else {
System.out.println("Box unfocused on index " + getIndex());
}
});
// Tracking the focused property of the check box for debug
// purposes.
this.focusedProperty().addListener((obs, oldValue, newValue) ->
{
if (newValue) {
System.out.println("Box cell focused on index " + getIndex());
box.requestFocus();
} else {
System.out.println("Box cell unfocused on index " + getIndex());
}
});
}
/**
* Gets the column to the right or to the left of the current column
* depending no the value of forward.
*
* #param forward
* If true, the column to the right of the current column
* will be returned. If false, the column to the left of the
* current column will be returned.
*/
private TableColumn<ObservableList<StringProperty>, ?> getNextColumn(boolean forward) {
List<TableColumn<ObservableList<StringProperty>, ?>> columns = getTableView().getColumns();
// If there's less than two columns in the table view we return null
// since there can be no column to the right or left of this
// column.
if (columns.size() < 2) {
return null;
}
// We get the index of the current column and then we get the next
// or previous index depending on forward.
int currentIndex = columns.indexOf(getTableColumn());
int nextIndex = currentIndex;
if (forward) {
nextIndex++;
if (nextIndex > columns.size() - 1) {
nextIndex = 0;
}
} else {
nextIndex--;
if (nextIndex < 0) {
nextIndex = columns.size() - 1;
}
}
// We return the column on the next index.
return columns.get(nextIndex);
}
}
}
After some digging in the TableView source code I found the issue. Here's the source code for the focus(int row, TableColumn<S, ?> column) method:
#Override public void focus(int row, TableColumn<S,?> column) {
if (row < 0 || row >= getItemCount()) {
setFocusedCell(EMPTY_CELL);
} else {
TablePosition<S,?> oldFocusCell = getFocusedCell();
TablePosition<S,?> newFocusCell = new TablePosition<>(tableView, row, column);
setFocusedCell(newFocusCell);
if (newFocusCell.equals(oldFocusCell)) {
// manually update the focus properties to ensure consistency
setFocusedIndex(row);
setFocusedItem(getModelItem(row));
}
}
}
The issue arises when newFocusCell is compared to oldFocusCell. When tabbing to a checkbox cell the cell would for some reason not get set as the focused cell. Hence the focusedCell property returned by getFocusedCell() will be the cell we focused before the check box cell. So when we then try to focus that previous cell again, newFocusCell.equals(oldFocusCell) will return true, and the focus will be set to the currently focused cell again by doing:
setFocusedIndex(row);
setFocusedItem(getModelItem(row));`
So what I had to do was make sure that the cell isn't be the value of the focusedCell property when we want to focus it. I solved this by setting the focus manually to the whole table before trying to switch the focus from the check box cell:
table.requestFocus();
I have a TextField where the user can type. I would like to show a ContextMenu below cursor when the user hit Ctrl+Space key combination.
codeArea.setOnKeyPressed(event -> {
if( event.getCode().equals( KeyCode.SPACE ) && event.isControlDown() ) {
int cursorX = ?;
int cursorY = ?;
cm.show(codeArea, x, y);
} else {
cm.hide();
}
});
How I get the cursor current position? I must give it's (screen) XY coords to the show() function.
I'd like use it for auto completion.
Thanks.
Add a MouseListener and save the last position in a Variable :)
You might wanna use getScreenX() and getScreenY() not sure of the difference at the moment.
codeArea.setOnMouseMoved(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
this.cursorX = event.getX();
this.cursorY = event.getY();
}
});