JavaFX - Clicking inside GridPane prints out Pane instead of TextField - java

I'm trying to make a Sudoku Game in JavaFX. I made the 9x9 grid using GridPane and TextField.
Now I want to change the background color of the TextField when user clicks inside it. To check that everyting is fine I am prining the target od the MouseEvent.
My problem is that when I click in the center of TextField, the target is Pane and when i I click elsewhere the target is my GridPane and the background color is changing.
What should I do? I can't figure out how to do it!
public class SudokuGrid {
public static final int GRID_SIZE = 9;
private TextField[][] sudokuCells;
private GridPane sudokuGrid;
public SudokuGrid () {
sudokuCells = new TextField[GRID_SIZE][GRID_SIZE];
createSudokuGrid();
for (int row = 0; row < GRID_SIZE; row++) {
for(int col = 0; col < GRID_SIZE; col++) {
sudokuCells[row][col] = new TextField() {
#Override
public void replaceText(int start, int end, String text) {
// If the replaced text would end up being invalid, then simply
// ignore this call!
if (text.matches("[1-9]|\\s")) {
super.setText(text);
}
}
};
sudokuCells[row][col].setPrefSize(60, 60);
sudokuCells[row][col].setStyle("-fx-background-color: yellow;");
sudokuGrid.add(sudokuCells[row][col], col, row);
sudokuGrid.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
Object source = e.getTarget();
System.out.println(source);
if(source instanceof TextField) {
((TextField) source).setStyle("-fx-background-color: green;");
}
}
});
}
}
sudokuGrid.setPrefSize(270, 270); // 30 * 9
sudokuGrid.setGridLinesVisible(true);
}
private void createSudokuGrid() {
sudokuGrid = new GridPane();
for (int i = 0; i < GRID_SIZE; i++) {
RowConstraints rc = new RowConstraints();
rc.setVgrow(Priority.ALWAYS) ; // allow row to grow
rc.setFillHeight(true); // ask nodes to fill height for row
// other settings as needed...
sudokuGrid.getRowConstraints().add(rc);
ColumnConstraints cc = new ColumnConstraints();
cc.setHgrow(Priority.ALWAYS) ; // allow column to grow
cc.setFillWidth(true); // ask nodes to fill space for column
// other settings as needed...
sudokuGrid.getColumnConstraints().add(cc);
}
}

The source of the event is the object on which you set the event filter; i.e. in this case it is sudokuGrid. So the condition
if (source instanceof TextField)
in your handler will never be true, since the only possible source is the sudokuGrid.
If you want to change the background color of the text field, you can add the event filter to the text field itself:
TextField sudokuCell = sudokuCells[row][col];
sudokuCell.addEventFilter(MouseEvent.MOUSE_PRESSED, e ->
sudokuCell.setStyle("-fx-background-color: green;"));
Better still would be to respond to changes in the text field's focused property (because using a mouse listener will not change the background if the user uses the Tab key to navigate to different text fields):
TextField sudokuCell = sudokuCells[row][col];
sudokuCell.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (isNowFocused) {
sudokuCell.setStyle("-fx-background-color: green;");
} else {
sudokuCell.setStyle("");
}
});
And even better would just be to use an external css file to do this:
sudoku-grid.css:
.text-field:focused {
-fx-background-color: green ;
}
and then in your Java code associate the CSS file with the grid:
sudokuGrid.getStyleSheets().add("sudoku-grid.css");
and remove the handlers entirely.

Related

Why are all my ActionListener's added to JButtons in a loop identical?

Ok so I am trying to make a chess game in swing. I have a program that creates a 2d array of JButton's 8x8. I then create them all in a loop doing stuff like going back and forth between white/black and adding an action event. The problem i am having is that each button has the same action event and it is the event that is created last I.E. button on Row 8 column H is the action listener for all of the buttons in the array. Here is a snippet of code that is where I am creating the buttons and adding them.
I also have an Enum Columns that just goes from int to character 1 to H for example. selectPosition and targetPosition are objects that have two members columns and rows.
public void initializeGui(boolean isWhite) {
boolean shouldBeWhite = true;
for(int i = 0; i< 8; i++){
for(int j = 0; j < 8; j++){
column = i+1;
row = j+1;
JButton square = new JButton();
square.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
final int thisRow = row;
final int thisColumn = column;
selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
selectPosition.setRow(thisRow);
if(isSelecting){
System.out.print("Selecting square to move. Row: " + thisRow + " Column: " + Columns.getColumnsFromInt(thisColumn));
selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
selectPosition.setRow(thisRow);
} else{
System.out.print("Targeting square to move to. Row: " + thisRow + " Column: " + Columns.getColumnsFromInt(thisColumn) + "\n");
targetPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
targetPosition.setRow(thisRow);
}
System.out.println("");
isSelecting = !isSelecting;
}
});
if(shouldBeWhite){
square.setBackground(Color.WHITE);
shouldBeWhite = false;
}else{
square.setBackground(Color.BLACK);
shouldBeWhite = true;
}
if (j == 7){
shouldBeWhite = !shouldBeWhite;
}
chessBoardSquares[i][j] = square;
gui.add(chessBoardSquares[i][j]);
}
}
if(isWhite){
setInitialPiecesWhiteStart();
}else{
setInitialPiecesBlackStart();
}
}
Further up as a member of this class are the following:
int column = 0, row = 0;
When I click on any of these buttons i see printed
Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H
Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H
and so on. My question is why are these buttons all given the same action event? My logic walk through would be something like create the first button set column = i+1 and row = j+1 then add an action listener with an action event that sets the current row/column values to the inner final variables and then prints out the thisRow and thisColumn associated with that action event. Am i overriding the values at the end or do i have the scope wrong? Basically how am i creating these buttons actions listeners incorrectly?
You could...
Use the actionCommand API to pass information between the button and the ActionListener...
JButton btn = new JButton();
btn.setActionCommand(row + "x" + column);
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
//...
}
});
The problem here is you're relying on String parsing to extract the values, which can get messy quickly
You could...
Create a custom ActionListener which takes the values you want to use...
public class SquareActionListener implements ActionListener {
private int column;
private int row;
public SquareActionListener(int row, int column) {
this.row = row;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
//...
}
}
This de-couples the ActionListener from the rest of the code and provides you the information you need, although, you may need to pass additional information (such as the model) as well for it to work
You could...
Make use of the Action API which is designed to be provide self contained units of work, it's generally a more re-usable solution, but might be a little beyond what you need right now
public class SquareAction extends AbstractAction {
private int column;
private int row;
public SquareAction(int row, int column) {
this.row = row;
this.column = column;
}
#Override
public void actionPerformed(ActionEvent e) {
//...
}
}
This looks alot like the last suggestion, but instead of adding it as the button's ActionListener, you actually apply it to the button directly...
JButton btn = new JButton(new SquareAction(row, column));
The button then uses other properties (which I've not set) to set itself up
I had the same issue when making a tic-tac-toe game. I used each button's hashcode to trace back which button was actually pushed. This is what my button setup looked like:
hashcodes= new ArrayList<Integer>();
for (int i=1;i<=9;i++) {
JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setHash(button.hashCode());
testWinner();
testDraw();
}
});
hashcodes.add(button.hashCode());
panel.add(button);
}
}
private void setHash(int hashcode) {
for (int h:hashcodes) {
if (h==hashcode) {
//do stuff
}
}
}
This is my Test class, and it works perfectly.
public class Test extends javax.swing.JFrame {
private javax.swing.JButton[][] buttons;
private final int ROW = 8;
private final int COLUMN = 8;
public Test() {
initComponents();
}
private void initComponents() {
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);
this.buttons = new javax.swing.JButton[ROW][COLUMN];
this.setLayout(new java.awt.GridLayout(ROW, COLUMN));
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COLUMN; j++) {
final int row = i;
final int column = j;
buttons[i][j] = new javax.swing.JButton(
String.format("Button %d-%d", i, j));
buttons[i][j].addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
// System.out.println(
// String.format("You have just pressed the button at row %d and column %d", row, column));
javax.swing.JOptionPane.showMessageDialog(
Test.this, String.format("You have just pressed the button at row %d and column %d", row, column));
}
});
this.add(buttons[i][j]);
}
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Test().setVisible(true);
}
}

Javafx get text from textfields in gridpane

for a project I'm working on, I have to display the values of a matrix in a screen. I chose to do this by using text fields in a gridpane as following code indicates:
for(int row = 0; row < length; row++){
for(int column = 0; column < width; column++){
// Create a new TextField in each Iteration
TextField tf = new TextField();
tf.setPrefHeight(50);
tf.setPrefWidth(50);
tf.setAlignment(Pos.CENTER);
tf.setEditable(true);
tf.setText(String.valueOf(this.getElement(row, column)));
// Iterate the Index using the loops
setRowIndex(tf,row);
setColumnIndex(tf,column);
table.getChildren().add(tf);
}
}
If I change the values inside that screen for the text fields, I want to be able to save them. In order to do that, I have to be able to get the text from the text fields. I tried following code, but the iteration over the elements of the table are defined as Nodes, and therefor don't have a .getText() method.
OkButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle (ActionEvent event){
for (Node nd:table.getChildren()){
//Code goes here but Node does not have .getText() method
}
Stage stage = (Stage) OkButton.getScene().getWindow();
stage.close();
}
});
Does anyone know how to get those values?
Thanks a lot!
Assuming that table is of type GridPane, you should add your TextFields like this:
table.add(tf, column, row);
For accessing an element, when it's col and row indices are known there is no easy way:
public Node getNodeByRowColumnIndex(final int row,final int column,GridPane gridPane) {
Node result = null;
ObservableList<Node> childrens = gridPane.getChildren();
for(Node node : childrens) {
if(gridPane.getRowIndex(node) == row && gridPane.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
See also the answer to JavaFX: Get Node by row and column.

SWT Table checking box by selecting row or checking the box

I want to create table of elements with checkboxes in which one could change the state of checkbox by: 1) Clicking on checkbox, 2) Clicking on row. Unfailingly and fastly.
I've tried:
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
public class Example {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(280, 300);
shell.setText("FooTable");
Table table = new Table(shell, SWT.CHECK | SWT.BORDER | SWT.V_SCROLL| SWT.H_SCROLL);
String[] titles = { "Column" };
for (int loopIndex = 0; loopIndex < titles.length; loopIndex++) {
TableColumn column = new TableColumn(table, SWT.NULL);
column.setText(titles[loopIndex]);
}
for (int loopIndex = 0; loopIndex < 5; loopIndex++) {
TableItem item = new TableItem(table, SWT.NULL);
item.setText("Item " + loopIndex);
}
for (int loopIndex = 0; loopIndex < titles.length; loopIndex++) {
table.getColumn(loopIndex).pack();
}
table.setBounds(25, 25, 220, 200);
table.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
if (event.detail == SWT.CHECK) {
System.out.println("You checked " + event.item);
}
else {
System.out.println("You selected " + event.item);
TableItem ti = (TableItem)event.item;
ti.setChecked(!ti.getChecked());
}
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
But with this I've got at least 2 problems:
1) When a row is selected and I click on checbox, the two listeners will at the same time change the state of checkbox, so in the end there is no effect (bad).
2) When I double-click on a row, there again won't be any effect (bad), but when I double-click on checkbox (while row is not selected) I can clearly see checkbox changing it's state twice (good).
So how can I fix this or achieve it in another way?
Edit
I solved my problem by using multiple buttons instead of table, in this way
Button b = new Button(this, SWT.CHECK | SWT.WRAP);
b.setText("item");
But through it all, question remains open.
In order to solve your first problem, you can check if the checked item is also selected and revert the check in this case.
The resulting selection listener would look like this:
table.addListener( SWT.Selection, new Listener() {
public void handleEvent( Event event ) {
if( event.detail == SWT.CHECK ) {
System.out.println( "You checked " + event.item );
if( table.indexOf( ( TableItem )event.item ) == table.getSelectionIndex() ) {
TableItem ti = ( TableItem )event.item;
ti.setChecked( !ti.getChecked() );
}
} else {
System.out.println( "You selected " + event.item );
TableItem ti = ( TableItem )event.item;
ti.setChecked( !ti.getChecked() );
}
}
} );
To solve the double click issue, you can add a default selection listener that changes the check mark if the item (and not the check box) is double clicked
table.addListener( SWT.DefaultSelection, new Listener() {
#Override
public void handleEvent( Event event ) {
if( event.detail == SWT.NONE ) {
TableItem ti = ( TableItem )event.item;
ti.setChecked( !ti.getChecked() );
}
}
} );
Apart from the technical issues, I find the handling at least unusual and plain annoying when using the keyboard. Make sure that this behavior is what your users actually expect.
It works when clicking check box. It returns all selected row.
#Inject private AddSelectedItem addSelectedItem; //you can also create instance with new addSelectedItem()
...
table = new Table(shell, SWT.CHECK | SWT.BORDER);
table.addSelectionListener(addSelectedItem);
...
Class is created and implements SelectionListener.
public class AddSelectedItem implements SelectionListener
{
#Override
public void widgetSelected(SelectionEvent event)
{
((/*TypeCast - Your Return Type - YourTypeClass*/) event.item.getData()).switchSelected();
}
}
...
public class Test // YourTypeClass
{
private int a,b; // These are column variables at the table
private boolean flag;
public Test(){ //Constructor
...
this.flag=false;
}
public void switchSelected()
{
if (flag == false)
flag = true;
else
flag = false;
}
}
Also, implement arraylist and add your items into the list according to flag value. If it was selected (flag==true), add to the arraylist. Then you can reach every item in your arraylist.
List<Test > list = new ArrayList<Test >();
To sum up, you should define class with selection flag, then add list according to flag value. Then you can print list (selected items and their values) or write list to the file.
Example:
Selection a b
--------- --- ---
checkBox 1 2
checkBox 2 3
.......... .. ..
If checkBox is checked, flag returns true. Add it to the list.
SWT Table checking box by selecting row or checking the box
Table Column can add images like checked or unchecked
click column checked to all row can checked
and
click column unchecked to all row can unchecked
TableColumn tblclmnNewColumn_1 = new TableColumn(table, SWT.LEFT);
tblclmnNewColumn_1.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
System.out.println("Total Row Count:"+table.getItemCount());
TableItem item[] = table.getItems();
//get all the table items
for(int i=0;i<table.getItemCount();i++)
{
//Table_Column Checked or Not
if(item[i].getChecked())
{
//table items unchecked
item[i].setChecked(false);
tblclmnNewColumn_1.setImage(SWTResourceManager.getImage("D:\\Icon\\uncheck.png"));
}
else
{
//table items checked
item[i].setChecked(true);
tblclmnNewColumn_1.setImage(SWTResourceManager.getImage("D:\\Icon\\check.png"));
}
}
}
});
tblclmnNewColumn_1.setMoveable(true);
tblclmnNewColumn_1.setToolTipText("All Check");
tblclmnNewColumn_1.setImage(SWTResourceManager.getImage("D:\\Icon\\uncheck.png"));
tblclmnNewColumn_1.setWidth(36);
Fully describe visit this code :: de)select all” check box in an SWT Table header :
How can I put a "(de)select all" check box in an SWT Table header?

Add selectListener to table in SWT

In SWT I want to show a Table with 4 columns: 1st a number, 2nd a String, 3rd a checkBox and 4th a radio button.
Once all rows are set, I want to add another row for 3rd column (check all/none), and 4th column (clean radio selected).
This is the code (It compiles, but I haven't tested, yet):
//Create table
Table table = new Table(layoutComposite, SWT.BORDER);
table.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
String[] tableItems = new String[] {"", "Player", "Show", "Highlight"};
int[] tableSizes = new int[] {30, 150, 20, 20};
// Header Columns and sizes for table
for (int i = 0; i < tableItems.length; i++) {
TableColumn tableColumn = new TableColumn(table, SWT.NONE);
tableColumn.setText(tableItems[i]);
tableColumn.setWidth(tableSizes[i]);
}
table.setHeaderVisible(true);
table.setLinesVisible(false);
// Create items (void)
for (int i = 0; i < positions.size(); i++) {
new TableItem(table, SWT.NONE);
}
TableItem[] items = table.getItems();
// Check and Radio Buttons
Button[] checks = new Button[items.length + 1];
Button[] radios = new Button[items.length + 1];
// Add elements
for (int i = 0; i < items.length + 1; i++) {
// Pos and Player only in first items.length rows
if (i < items.length) {
items[i].setText(0, String.valueOf(positions.get(i).getPos()));
items[i].setText(1, positions.get(i).getPlayer().getPlayerName());
}
TableEditor editorCheck = new TableEditor(table);
checks[i] = new Button(table, SWT.CHECK);
checks[i].pack();
checks[i].setSelection(true);
editorCheck.minimumWidth = checks[i].getSize().x;
editorCheck.setEditor(checks[i], items[i], 2);
TableEditor radioCheck = new TableEditor(table);
radios[i] = new Button(table, SWT.RADIO);
radios[i].pack();
radios[i].setSelection(false);
radioCheck.minimumWidth = radios[i].getSize().x;
radioCheck.setEditor(radios[i], items[i], 3);
}
table.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
if (e.detail == SWT.CHECK) {
if (e.item instanceof Button) {
// TODO:
// Get checked item selected
// If last row (ie: == checks[items.length]), select or unselect all check related buttons
//
//((Button)e.item).get // Problem here!!!!
}
}
else if (e.detail == SWT.RADIO) {
// TODO:
// Get radio selected
// If last row (ie: radios[items.length]), clean selected item (if any)
}
// TODO Auto-generated method stub
super.widgetSelected(e);
}
});
Now I need to add a Listener over check and radio buttons. My question is: How do I know which check or radio button is selected?
should I do something like this?
for (int i = 0; i < checks.length; i++) {
if (e.item == checks[i]) { // found selected
if (i == checks.length -1 ) { // last one
// Select or unselect all
}
// doStuff () ;
}
}
If this is correct, Is there an easy way to know which is selected? If not, how can I do it?
Any other hint will be very welcome.
you can add a selection listener to each checkbox and radio button after you create them:
checks[i].addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
// your code here...
// get the current checkbox/radio button from the event:
Widget src = event.widget;
// ...
}
});
do the same with radio buttons:
radios[i].addSelectionListener(...);
i hope this helps you. enjoy.

How to identify ID of Labels in Java

I have created 9 JLabels by array. And it has common Event Listener with method of mouseClicked(MouseEvent src){... }, here i am finding problem is, how can I identify which JLabel is clicked?
Say, if label[0] is clicked then I want to show "Label-0 is clicked",
if label[1] is clicked then I want to show "Label-1 is clicked"
Can I perform this? if yes then How?
NOTE :- I found some answer stating that add Custom 'id' Property, I would but first, I prefer if there is any default method exist.
Add Label
JPanel pnl = new JPanel(new FlowLayout());
dd.add(pnl);
addlistener();
for (int i = 0; i < 10; i++) {
pnl.add(lbl[i] = new JLabel("" + i));
lbl[i].addMouseListener(listern);
}
Listener
public void mouseEnter(MouseEvent me) {
System.err.println("Hi");
me.getComponent();
if(me.getSource() instanceof JLabel){
System.out.println("lable"+ ((JLabel)me.getSource()).getText());
}
}
You could loop the array comparing the source of the event to each element in the array...
for (int index = 0; index < myLabelArray.length; index++) {
if (myLabelArray[index].equals(src.getSource())) {
System.out.println("Label-" + index + " was clicked");
break;
}
}
Or you could "name" each label...
JLabel[] myLabelArray = new JLabel[9];
for (int index = 0; index < 9; index++) {
JLabel label = new JLabel("...");
label.setName(Integer.toString(index));
label.addMouseListener(commonMouseListener);
myLabelArray[index] = label;
}
Then in your mouse listener...
public void mouseClicked(MouseEvent evt) {
System.out.println("Label-" + ((JLabel)evt.getSource()).getName() + " was clicked");
}
Or you could use a Map instead of an array or a List...

Categories

Resources