Drag and drop with JavaFX TreeView - events

I implemented Drag and Drop feature as recommended in other threads in this forum. I have a cellFactory on a TreeView and set the events on the cells.
tvProject.setCellFactory(new Callback<TreeView<PlanningItem>, TreeCell<PlanningItem>>() {
#Override
public PlanningCheckBoxTreeCell call(TreeView<PlanningItem> siTreeView) {
final PlanningCheckBoxTreeCell source = new PlanningCheckBoxTreeCell();
final PlanningCheckBoxTreeCell target = new PlanningCheckBoxTreeCell();
source.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
/* drag was detected, start drag-and-drop gesture */
System.out.println("onDragDetected");
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* put a string on dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
event.consume();
}
});
target.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* data is dragged over the target */
System.out.println("onDragOver");
...
event.consume();
}
});
The setOnDragDetected is executed/hit as wanted but all other events are NOT (I did not post them all here: setOnDragOver,setOnDragEntered,setOnDragExited,setOnDragDropped,setOnDragDone).
The PlanningCheckBoxTreeCell is a custom implementation of a treecell as follows:
public class PlanningCheckBoxTreeCell extends CheckBoxTreeCell<PlanningItem> {
public PlanningCheckBoxTreeCell() {
}
#Override
public void updateItem(PlanningItem item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setText(null);
}
}
}
UPDATE PlanningItem:
package at.v2c2.testplaygroundui;
import java.io.Serializable;
public class PlanningItem implements Serializable {
private static final long serialVersionUID = 1L;
private Double scene = null;
private Integer path = null;
private String move = null;
/**
* #return the scene
*/
public Double getScene() {
return scene;
}
/**
* #param scene the scene to set
*/
private void setScene(Double scene) {
this.scene = scene;
}
/**
* #return the path
*/
public Integer getPath() {
return path;
}
/**
* #param path the path to set
*/
private void setPath(Integer path) {
this.path = path;
}
/**
* #return the move
*/
public String getMove() {
return move;
}
/**
* #param move the move to set
*/
private void setMove(String move) {
this.move = move;
}
public PlanningItem(Object item) {
super();
if (item instanceof Double) {
setScene((Double) item);
} else if (item instanceof Integer) {
setPath((Integer) item);
} else if (item instanceof String) {
setMove((String) item);
}
}
}
UPDATE The MCVE:
package at.v2c2.testplaygroundui;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public final class TestplaygroundUi extends Application {
private final DataFormat objectDataFormat = new DataFormat("application/x-java-serialized-object");
/**
* Constructor.
*/
public TestplaygroundUi() {
// empty.
}
/**
* #param args Program arguments.
*/
public static void main(final String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) throws Exception {
TreeItem<PlanningItem> treeItemRoot = new TreeItem<>(new PlanningItem(1.0));
TreeItem<PlanningItem> nodeItemA = new TreeItem<>(new PlanningItem(2));
TreeItem<PlanningItem> nodeItemB = new TreeItem<>(new PlanningItem(2));
treeItemRoot.getChildren().addAll(nodeItemA, nodeItemB);
TreeItem<PlanningItem> nodeItemA1 = new TreeItem<>(new PlanningItem("A1"));
TreeItem<PlanningItem> nodeItemB1 = new TreeItem<>(new PlanningItem("B1"));
nodeItemA.getChildren().addAll(nodeItemA1);
nodeItemB.getChildren().addAll(nodeItemB1);
TreeView<PlanningItem> treeView = new TreeView<>(treeItemRoot);
treeView.setCellFactory(new Callback<TreeView<PlanningItem>, TreeCell<PlanningItem>>() {
#Override
public TreeCell<PlanningItem> call(TreeView<PlanningItem> siTreeView) {
final TreeCell<PlanningItem> cell = new TreeCell<>();
cell.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
/* drag was detected, start drag-and-drop gesture */
System.out.println("onDragDetected");
/* allow any transfer mode */
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
/* put a string on dragboard */
ClipboardContent content = new ClipboardContent();
content.put(objectDataFormat, cell.getItem());
// content.putString("Hello");// cell.getText());
db.setContent(content);
event.consume();
}
});
cell.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* data is dragged over the target */
System.out.println("onDragOver");
/*
* accept it only if it is not dragged from the same node and if it has a string data
*/
if (event.getGestureSource() != cell && event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
}
});
cell.setOnDragEntered(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* the drag-and-drop gesture entered the target */
System.out.println("onDragEntered");
/* show to the user that it is an actual gesture target */
if (event.getGestureSource() != cell && event.getDragboard().hasString()) {
// target.setFill(Color.GREEN);
}
event.consume();
}
});
cell.setOnDragExited(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
System.out.println("onDragExited");
/* mouse moved away, remove the graphical cues */
// target.setFill(Color.BLACK);
event.consume();
}
});
cell.setOnDragDropped(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* data dropped */
System.out.println("onDragDropped");
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
cell.setText(db.getString());
success = true;
}
/*
* let the source know whether the string was successfully transferred and used
*/
event.setDropCompleted(success);
event.consume();
}
});
cell.setOnDragDone(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* the drag-and-drop gesture ended */
System.out.println("onDragDone");
/* if the data was successfully moved, clear it */
if (event.getTransferMode() == TransferMode.MOVE) {
cell.setText("");
}
event.consume();
}
});
return cell;
};
});
StackPane root = new StackPane();
root.getChildren().add(treeView);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.setTitle("Test TreeView");
primaryStage.show();
}
}
Thanks in advance

Related

How to filter hyperlink cells in swt tableviewer

I have a problem i can't solve and I have spent a lot of time. I have a table and I have a column with hyperlinks. I have some filters added to the table and when I activate one of those filters, the hyperlink column doesn't refresh correctly. The code I implemented is showing above. This is an example you can copy&paste, run & reproduce the bug:
The Table class:
package borrar;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
public class Example {
private static TableViewer tViewer = null;
private static Table tblTrades = null;
private static Text txtTicker;
public static TickerFilter2 tickerFilter = new TickerFilter2();
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Composite parent = new Composite(shell, SWT.NONE);
parent.setLayout(new FillLayout());
parent.setLayout(new GridLayout(1, true));
Label lblTicker = new Label(parent, SWT.NONE);
lblTicker.setText("Search: ");
txtTicker = new Text(parent, SWT.NONE);
txtTicker.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
txtTicker.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent ke) {
tickerFilter.setSearchText(txtTicker.getText());
tViewer.refresh();
}
});
tViewer = new TableViewer(parent, SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CENTER);
String[] titles = { "Ticker", "Hyperlinks" };
createColumns(titles);
tblTrades = tViewer.getTable();
tViewer.setContentProvider(new ArrayContentProvider());
List<DataTable> dt = Arrays.asList(new DataTable("AAA", "ImagePath"), new DataTable("ABBBBBB", "ImagePath"),
new DataTable("BBBBBBB", "ImagePath"));
tViewer.setInput(dt);
tblTrades.setHeaderVisible(true);
tViewer.addFilter(tickerFilter);
shell.open();
shell.pack();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private static void createColumns(String[] titles) {
TableViewerColumn col = createTableViewerColumn(titles[0], 70);
col.setLabelProvider(new ColumnLabelProvider() {
#Override
public String getText(Object element) {
DataTable op = (DataTable) element;
if (op.getTicker() != null) {
return op.getTicker();
} else {
return "";
}
}
});
col = createTableViewerColumn(titles[1], 80);
col.setLabelProvider(new ColumnLabelProvider() {
Map<Object, Hyperlink> hyperlinks = new HashMap<Object, Hyperlink>();
#Override
public void update(ViewerCell cell) {
TableItem item = (TableItem) cell.getItem();
final Hyperlink hyperlink;
if (hyperlinks.containsKey(cell.getElement()) && !hyperlinks.get(cell.getElement()).isDisposed()) {
hyperlink = hyperlinks.get(cell.getElement());
} else {
hyperlink = new Hyperlink((Composite) (cell.getViewerRow().getControl()), SWT.NONE);
if (cell.getElement() instanceof DataTable) {
DataTable trade = (DataTable) cell.getElement();
if (trade.getPath() != null && !trade.getPath().equals("")) {
hyperlink.setText(trade.getPath() + "-" + trade.getTicker());
hyperlink.setHref(trade.getPath());
}
}
hyperlink.addHyperlinkListener(new HyperlinkAdapter() {
public void linkActivated(HyperlinkEvent e) {
org.eclipse.swt.program.Program.launch(hyperlink.getHref().toString());
}
});
hyperlinks.put(cell.getElement(), hyperlink);
}
TableEditor editor = new TableEditor(item.getParent());
editor.grabHorizontal = true;
editor.grabVertical = true;
editor.setEditor(hyperlink, item, cell.getColumnIndex());
editor.layout();
}
});
}
private static TableViewerColumn createTableViewerColumn(String title, int bound) {
final TableViewerColumn viewerColumn = new TableViewerColumn(tViewer, SWT.CENTER);
final TableColumn column = viewerColumn.getColumn();
column.setText(title);
column.setWidth(bound);
column.setResizable(true);
column.setMoveable(true);
return viewerColumn;
}
public void refreshTable() {
tViewer.refresh();
}
}
My filter class:
package borrar;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
public class TickerFilter2 extends ViewerFilter {
private String searchString;
public void setSearchText(String s) {
// ensure that the value can be used for matching
this.searchString = ".*" + s + ".*";
}
#Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (searchString == null || searchString.length() == 0) {
return true;
}
DataTable trade = (DataTable) element;
if (trade.getTicker().matches(searchString)) {
return true;
}
return false;
}
}
The data table object:
package borrar;
public class DataTable {
String ticker;
String path;
public DataTable(String ticker, String path) {
super();
this.ticker = ticker;
this.path = path;
}
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
If you put in the search field a "z" or "l" for example, you can see that the hyperlink column does not filter.
The filter class filters data correctly but the hyperlinks column doesn't filter fine.
Here you have an image with the bad result:
The TableViewer doesn't really know about the TableEditor code so it doesn't deal with them when filtering.
You could perhaps use the EditingSupport code. The following code defines a cell editor which does an action as soon as you click on the column cell.
For the column definition replace your code with something like:
col.setLabelProvider(new ColumnLabelProvider() {
#Override
public String getText(final Object element) {
// Whatever you want for the cell text here
final DataTable op = (DataTable) element;
return op.getPath();
}
});
col.setEditingSupport(new HyperlinkEditingSupport(tViewer));
The editing support class:
public class HyperlinkEditingSupport extends EditingSupport
{
private final HyperlinkCellEditor _editor;
public HyperlinkEditingSupport(final TableViewer viewer)
{
super(viewer);
_editor = new HyperlinkCellEditor(viewer.getTable());
}
#Override
protected CellEditor getCellEditor(final Object element)
{
return _editor;
}
#Override
protected boolean canEdit(final Object element)
{
return true;
}
#Override
protected Object getValue(final Object element)
{
// Return the value you want launched
return ((DataTable)element).getPath();
}
#Override
protected void setValue(final Object element, final Object value)
{
// no action
}
}
And the CellEditor. This is a bit odd because we are just going to launch as soon as the editor is invoked so we don't really need a separate editor:
public class HyperlinkCellEditor extends CellEditor
{
public HyperlinkCellEditor(final Composite parent)
{
super(parent);
}
#Override
protected Control createControl(final Composite parent)
{
return new Composite(parent, SWT.None);
}
#Override
protected Object doGetValue()
{
return new Object[0];
}
#Override
protected void doSetFocus()
{
// no action
}
#Override
protected void doSetValue(final Object value)
{
final String path = (String)value;
// TODO Open the link
}
}
I have modified #greg-449 solution to show a link appearance in the cell only modifying the LabelProvider:
col.setLabelProvider(new StyledCellLabelProvider() {
#Override
public void update(ViewerCell cell) {
DataTable op = (DataTable) cell.getItem().getData();
StyledString ss = new StyledString();
StyleRange sr = new StyleRange(0, 80, Display.getCurrent().getSystemColor(SWT.COLOR_BLUE), null);
sr.underline = true;
ss.append(op.getPath(), StyledString.DECORATIONS_STYLER);
cell.setText("Open Image");
StyleRange[] range = { sr };
cell.setStyleRanges(range);
}
});
col.setEditingSupport(new HyperlinkEditingSupport(tViewer));

Edit next row on tab

When i put all code in a SSCCE, it works as expected i.e first and third cells are editable. When tab on last column, takes to next row.
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Yunus
*/
public class CollectionForm extends Application{
private TableView table = new TableView();
private ObservableList<Collection> collectionList = FXCollections.<Collection>observableArrayList();
ListProperty<Collection> collectionListProperty = new SimpleListProperty<>();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
// single cell selection mode
table.getSelectionModel().setCellSelectionEnabled(true);
//Create a custom cell factory so that cells can support editing.
Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditableTableCell();
}
};
//A custom cell factory that creates cells that only accept numerical input.
Callback<TableColumn, TableCell> numericFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new NumericEditableTableCell();
}
};
Button b = createSaveCollectionBtn();
//Create columns
TableColumn colMNO = createMNOColumn(editableFactory);
TableColumn colName = createNameColumn(editableFactory);
TableColumn colQty = createQuantityColumn(numericFactory);
table.getColumns().addAll(colMNO, colName, colQty);
//Make the table editable
table.setEditable(true);
collectionListProperty.set(collectionList);
table.itemsProperty().bindBidirectional(collectionListProperty);
collectionList.add(new Collection());
collectionList.add(new Collection());
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(b, table);
vbox.setPadding(new Insets(10, 0, 0, 10));
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private void handleCollection(ActionEvent event){
for (Collection collection : collectionList) {
System.out.println("MNO: "+collection.getMno()+" Quantity: "+collection.getQuantity());
}
}
private Button createSaveCollectionBtn(){
Button btn = new Button("Save Collection");
btn.setId("btnSaveCollection");
btn.setOnAction(this::handleCollection);
return btn;
}
private TableColumn createQuantityColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colQty = new TableColumn("Quantity");
colQty.setMinWidth(25);
colQty.setId("colQty");
colQty.setCellValueFactory(new PropertyValueFactory("quantity"));
colQty.setCellFactory(editableFactory);
colQty.setOnEditCommit(new EventHandler<CellEditEvent<Collection, Long>>() {
#Override
public void handle(CellEditEvent<Collection, Long> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setQuantity(t.getNewValue());
}
});
return colQty;
}
private TableColumn createMNOColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colMno = new TableColumn("M/NO");
colMno.setMinWidth(25);
colMno.setId("colMNO");
colMno.setCellValueFactory(new PropertyValueFactory("mno"));
colMno.setCellFactory(editableFactory);
colMno.setOnEditCommit(new EventHandler<CellEditEvent<Collection, String>>() {
#Override
public void handle(CellEditEvent<Collection, String> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setMno(t.getNewValue());
}
});
return colMno;
}
private TableColumn createNameColumn(Callback<TableColumn, TableCell> editableFactory) {
TableColumn colName = new TableColumn("Name");
colName.setEditable(false);
colName.setMinWidth(100);
colName.setId("colName");
colName.setCellValueFactory(new PropertyValueFactory<Collection, String>("name"));
colName.setCellFactory(editableFactory);
//Modifying the firstName property
colName.setOnEditCommit(new EventHandler<CellEditEvent<Collection, String>>() {
#Override
public void handle(CellEditEvent<Collection, String> t) {
((Collection) t.getTableView().getItems().get(t.getTablePosition().getRow())).setName(t.getNewValue());
}
});
return colName;
}
/**
*
* #author Graham Smith
*/
public class EditableTableCell<S extends Object, T extends String> extends AbstractEditableTableCell<S, T> {
public EditableTableCell() {
}
#Override
protected String getString() {
return getItem() == null ? "" : getItem().toString();
}
#Override
protected void commitHelper( boolean losingFocus ) {
commitEdit(((T) textField.getText()));
}
}
/**
*
* #author Graham Smith
*/
public class NumericEditableTableCell<S extends Object, T extends Number> extends AbstractEditableTableCell<S, T> {
private final NumberFormat format;
private boolean emptyZero;
private boolean completeParse;
/**
* Creates a new {#code NumericEditableTableCell} which treats empty strings as zero,
* will parse integers only and will fail if is can't parse the whole string.
*/
public NumericEditableTableCell() {
this( NumberFormat.getInstance(), true, true, true );
}
/**
* The integerOnly and completeParse settings have a complex relationship and care needs
* to be take to get the correct result.
* <ul>
* <li>If you want to accept only integers and you want to parse the whole string then
* set both integerOnly and completeParse to true. Strings such as 1.5 will be rejected
* as invalid. A string such as 1000 will be accepted as the number 1000.</li>
* <li>If you only want integers but don't care about parsing the whole string set
* integerOnly to true and completeParse to false. This will parse a string such as
* 1.5 and provide the number 1. The downside of this combination is that it will accept
* the string 1x and return the number 1 also.</li>
* <li>If you want to accept decimals and want to parse the whole string set integerOnly
* to false and completeParse to true. This will accept a string like 1.5 and return
* the number 1.5. A string such as 1.5x will be rejected.</li>
* <li>If you want to accept decimals and don't care about parsing the whole string set
* both integerOnly and completeParse to false. This will accept a string like 1.5x and
* return the number 1.5. A string like x1.5 will be rejected because ti doesn't start
* with a number. The downside of this combination is that a string like 1.5x3 will
* provide the number 1.5.</li>
* </ul>
*
* #param format the {#code NumberFormat} to use to format this cell.
* #param emptyZero if true an empty cell will be treated as zero.
* #param integerOnly if true only the integer part of the string is parsed.
* #param completeParse if true an exception will be thrown if the whole string given can't be parsed.
*/
public NumericEditableTableCell( NumberFormat format, boolean emptyZero, boolean integerOnly, boolean completeParse ) {
this.format = format;
this.emptyZero = emptyZero;
this.completeParse = completeParse;
format.setParseIntegerOnly(integerOnly);
}
#Override
protected String getString() {
return getItem() == null ? "" : format.format(getItem());
}
/**
* Parses the value of the text field and if matches the set format
* commits the edit otherwise it returns the cell to it's previous value.
*/
#Override
protected void commitHelper( boolean losingFocus ) {
if( textField == null ) {
return;
}
try {
String input = textField.getText();
if (input == null || input.length() == 0) {
if(emptyZero) {
setText( format.format(0) );
commitEdit( (T)new Integer( 0 ));
}
return;
}
int startIndex = 0;
ParsePosition position = new ParsePosition(startIndex);
Number parsedNumber = format.parse(input, position);
if (completeParse && position.getIndex() != input.length()) {
throw new ParseException("Failed to parse complete string: " + input, position.getIndex());
}
if (position.getIndex() == startIndex ) {
throw new ParseException("Failed to parse a number from the string: " + input, position.getIndex());
}
commitEdit( (T)parsedNumber );
} catch (ParseException ex) {
//Most of the time we don't mind if there is a parse exception as it
//indicates duff user data but in the case where we are losing focus
//it means the user has clicked away with bad data in the cell. In that
//situation we want to just cancel the editing and show them the old
//value.
if( losingFocus ) {
cancelEdit();
}
}
}
}
/**
* Provides the basis for an editable table cell using a text field. Sub-classes can provide formatters for display and a
* commitHelper to control when editing is committed.
*
* #author Graham Smith
*/
public abstract class AbstractEditableTableCell<S, T> extends TableCell<S, T> {
protected TextField textField;
public AbstractEditableTableCell() {
}
/**
* Any action attempting to commit an edit should call this method rather than commit the edit directly itself. This
* method will perform any validation and conversion required on the value. For text values that normally means this
* method just commits the edit but for numeric values, for example, it may first parse the given input. <p> The only
* situation that needs to be treated specially is when the field is losing focus. If you user hits enter to commit the
* cell with bad data we can happily cancel the commit and force them to enter a real value. If they click away from the
* cell though we want to give them their old value back.
*
* #param losingFocus true if the reason for the call was because the field is losing focus.
*/
protected abstract void commitHelper(boolean losingFocus);
/**
* Provides the string representation of the value of this cell when the cell is not being edited.
*/
protected abstract String getString();
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
Platform.runLater(new Runnable() {
#Override
public void run() {
textField.selectAll();
textField.requestFocus();
}
});
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
//Once the edit has been cancelled we no longer need the text field
//so we mark it for cleanup here. Note though that you have to handle
//this situation in the focus listener which gets fired at the end
//of the editing.
textField = null;
}
#Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitHelper(false);
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
} else if (t.getCode() == KeyCode.TAB) {
commitHelper(false);
TableColumn nextColumn = getNextColumn(!t.isShiftDown());
TablePosition focusedCellPosition = getTableView().getFocusModel().getFocusedCell();
if (nextColumn != null) {
//if( focusedCellPosition.getColumn() ){}focusedCellPosition.getTableColumn()
System.out.println("Column: "+focusedCellPosition.getColumn());
System.out.println("nextColumn.getId();: "+nextColumn.getId());
if( nextColumn.getId().equals("colMNO") ){
collectionList.add(new Collection());
getTableView().edit((getTableRow().getIndex())+1,getTableView().getColumns().get(0) );
getTableView().layout();
} else {
getTableView().edit(getTableRow().getIndex(), nextColumn);
}
}else{
getTableView().edit((getTableRow().getIndex())+1,getTableView().getColumns().get(0) );
}
}
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
//This focus listener fires at the end of cell editing when focus is lost
//and when enter is pressed (because that causes the text field to lose focus).
//The problem is that if enter is pressed then cancelEdit is called before this
//listener runs and therefore the text field has been cleaned up. If the
//text field is null we don't commit the edit. This has the useful side effect
//of stopping the double commit.
if (!newValue && textField != null) {
commitHelper(true);
}
}
});
}
/**
*
* #param forward true gets the column to the right, false the column to the left of the current column
* #return
*/
private TableColumn<S, ?> getNextColumn(boolean forward) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
for (TableColumn<S, ?> column : getTableView().getColumns()) {
columns.addAll(getLeaves(column));
}
//There is no other column that supports editing.
if (columns.size() < 2) {
return null;
}
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;
}
}
return columns.get(nextIndex);
}
private List<TableColumn<S, ?>> getLeaves(TableColumn<S, ?> root) {
List<TableColumn<S, ?>> columns = new ArrayList<>();
if (root.getColumns().isEmpty()) {
//We only want the leaves that are editable.
if (root.isEditable()) {
columns.add(root);
}
return columns;
} else {
for (TableColumn<S, ?> column : root.getColumns()) {
columns.addAll(getLeaves(column));
}
return columns;
}
}
}
public class Collection {
private int id;
private String mno;
private String name;
private float quantity;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMno() {
return mno;
}
public void setMno(String mno) {
this.mno = mno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getQuantity() {
return quantity;
}
public void setQuantity(float quantity) {
this.quantity = quantity;
}
}
}
The problem is when i take the same code to a controller and add this table programmatically, does not work as before: it jumps next line and go to third.
Before asking the TableView to edit the cell it's important to make sure that it has focus, that the cell in question is in view, and that the view layout is up to date. This is probably because of the way TableView uses virtual cells.
Add these three lines before any call to TableView#edit:
getTableView().requestFocus();
getTableView().scrollTo(rowToEdit);
getTableView().layout();
// getTableView().edit goes here.
This solved this problem for me.

Panel background color won't change on menuitem mouse click

below is my code. It's fairly simple, just changing a panel color upon selecting one of three menu items, I think it's setup right(?) but it doesn't seem to be doing anything, also no errors. Any tips?
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Joe
*/
public class menuframe extends javax.swing.JFrame {
/**
* Creates new form menuframe
*/
public menuframe() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
panel = new javax.swing.JPanel();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenuItem1 = new javax.swing.JMenuItem();
jMenuItem2 = new javax.swing.JMenuItem();
jMenuItem3 = new javax.swing.JMenuItem();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout panelLayout = new javax.swing.GroupLayout(panel);
panel.setLayout(panelLayout);
panelLayout.setHorizontalGroup(
panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
panelLayout.setVerticalGroup(
panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 279, Short.MAX_VALUE)
);
jMenu1.setText("Color");
jMenuItem1.setText("Red");
jMenuItem1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jMenuItem1MouseClicked(evt);
}
});
jMenu1.add(jMenuItem1);
jMenuItem2.setText("Green");
jMenuItem2.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jMenuItem2MouseClicked(evt);
}
});
jMenu1.add(jMenuItem2);
jMenuItem3.setText("Blue");
jMenuItem3.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jMenuItem3MouseClicked(evt);
}
});
jMenu1.add(jMenuItem3);
jMenuBar1.add(jMenu1);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(panel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
private void jMenuItem1MouseClicked(java.awt.event.MouseEvent evt) {
panel.setBackground(Color.red);
}
private void jMenuItem2MouseClicked(java.awt.event.MouseEvent evt) {
panel.setBackground(Color.green);
}
private void jMenuItem3MouseClicked(java.awt.event.MouseEvent evt) {
panel.setBackground(Color.blue);
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(menuframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(menuframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(menuframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(menuframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new menuframe().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JMenu jMenu1;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem jMenuItem1;
private javax.swing.JMenuItem jMenuItem2;
private javax.swing.JMenuItem jMenuItem3;
private javax.swing.JPanel panel;
// End of variables declaration
}

how to receive user data in a new window in javafx2

I want to show a new window by clicking (say )on a menu item. The new window would contain two TextFields and one cancel button and one Ok button. When user gives data in the text fields and press Ok then in the parent window i should receive the values given by the user.
How can i do this?
Please show me with an example code.
Thanks
here is the solution, you click window menu then click new window, new window opens with two text fields and ok and cancel button, I get the text value from first text field and display it in the parent window. Let me know if you have any questions, I used singleton design pattern along with MVC. Let me know if you have any questions to run the code.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
/**
*
* #author Burak Firik
*/
public class ButtonListener implements MouseListener{
String value;
public ButtonListener(String str){
value=str;
}
#Override
public void mouseClicked(MouseEvent e) {
MainSingleton singleton=MainSingleton.getMainSingleton();
InputFrame inputFrame=singleton.getinputGUI();
MainFrame mainGUI=singleton.getGUI();
mainGUI.setLabelValue(inputFrame.getTextField1().getText());
mainGUI.repaint();
}
#Override
public void mousePressed(MouseEvent e) {
MainSingleton singleton=MainSingleton.getMainSingleton();
InputFrame inputFrame=singleton.getinputGUI();
inputFrame.setVisible(false);
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
And cancel button listener for the popup window
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
*
* #author Burak Firik
*/
public class CancelButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
MainSingleton singleton=MainSingleton.getMainSingleton();
InputFrame inputFrame=singleton.getinputGUI();
inputFrame.setVisible(false);
}
}
And inputFrame where the popup jframe will display two text fields and two button for OK and Cancel
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
*
* #author Burak Firik
*/
public class InputFrame extends JFrame {
JTextField txt1;
JTextField txt2;
JButton btnOk;
JButton btnCancel;
public InputFrame(){
initGUI();
initHandlers();
}
void initGUI(){
this.setLayout(new BorderLayout());
this.setSize(300,300);
this.setLocation(200,200);
txt1=new JTextField(10);
txt2=new JTextField(10);
btnOk=new JButton("OK");
btnCancel=new JButton("Cancel");
JPanel northPanel=new JPanel();
northPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
northPanel.add(txt1);
northPanel.add(txt2);
JPanel centerPanel=new JPanel();
centerPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
centerPanel.add(btnOk);
centerPanel.add(btnCancel);
add(northPanel,BorderLayout.NORTH );
add(centerPanel, BorderLayout.CENTER);
}
void initHandlers(){
ButtonListener btnListern=new ButtonListener(txt1.getText());
btnOk.addMouseListener(btnListern);
CancelButtonListener btnCancelListen=new CancelButtonListener();
btnCancel.addActionListener(btnCancelListen);
}
JFrame getInputFrame(){
return this;
}
JTextField getTextField1(){
return this.txt1;
}
JTextField getTextField2(){
return this.txt2;
}
public static void main(){
InputFrame frame=new InputFrame();
frame.setVisible(false);
}
}
mainframe where the newWindow ManuItem located;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
/**
*
* #author Burak Firik
*/
public class MainFrame extends JFrame{
private JMenuBar menuBar;
private JMenu menuWindow;
private JMenuItem menunewWindow;
private JLabel labelInputValue;
public MainFrame(){
this.setVisible(true);
this.setSize(300,300);
initGUI();
initHandlers();
}
private void initGUI() {
// Create the menu bar
this.setLayout(new BorderLayout());
menuBar = new JMenuBar();
menuWindow = new JMenu( "Window" );
menuWindow.setMnemonic( 'N' );
menuBar.add( menuWindow );
menunewWindow = CreateMenuItem( menuWindow, ITEM_PLAIN,
"New Window", null, 'N', null );
add(menuBar, BorderLayout.NORTH);
labelInputValue=new JLabel("SELAM");
add(labelInputValue, BorderLayout.CENTER);
}
public JMenuItem CreateMenuItem( JMenu menu, int iType, String sText,
ImageIcon image, int acceleratorKey,
String sToolTip )
{
// Create the item
JMenuItem menuItem;
switch( iType )
{
case ITEM_RADIO:
menuItem = new JRadioButtonMenuItem();
break;
case ITEM_CHECK:
menuItem = new JCheckBoxMenuItem();
break;
default:
menuItem = new JMenuItem();
break;
}
// Add the item test
menuItem.setText( sText );
// Add the optional icon
if( image != null )
menuItem.setIcon( image );
// Add the accelerator key
if( acceleratorKey > 0 )
menuItem.setMnemonic( acceleratorKey );
// Add the optional tool tip text
if( sToolTip != null )
menuItem.setToolTipText( sToolTip );
// Add an action handler to this menu item
menu.add( menuItem );
return menuItem;
}
private final int ITEM_PLAIN = 0; // Item types
private final int ITEM_CHECK = 1;
private final int ITEM_RADIO = 2;
private void initHandlers() {
MenuListener menuListen=new MenuListener();
menunewWindow.addActionListener(menuListen);
}
public void setLabelValue(String str){
labelInputValue.setText(str);
this.repaint();
}
}
this class contains the singleton object it is very quick for lazy programmers :))
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
/**
*
* #author Burak Firik
*/
public class MainSingleton {
private static MainSingleton singleton=null;
private MainFrame gui;
private InputFrame inputGUI;
//private constructor for singleton design pattern
private MainSingleton(){}
public static MainSingleton getMainSingleton()
{
// ONLY CONSTRUCT THE SINGLETON THE FIRST TIME
if (singleton == null)
{
singleton = new MainSingleton();
}
// GET THE SINGLETON NO MATTER WHAT
return singleton;
}
public static void main(String[] args) {
MainSingleton mainFrame=MainSingleton.getMainSingleton();
mainFrame.init();
}
public void init(){
// INITALIZE THE GUI
gui = new MainFrame();
inputGUI=new InputFrame();
}
public void requestExit()
{
// WE MAY HAVE TO SAVE CURRENT WORK
boolean continueToExit = true;
// IF THE USER REALLY WANTS TO EXIT THE APP
if (continueToExit)
{
// EXIT THE APPLICATION
System.exit(0);
}
}
public MainFrame getGUI() { return gui; }
public InputFrame getinputGUI() { return inputGUI; }
}
this is the menu listener, when you click new Window this listener will be invoked.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package stackoverflow;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
/**
*
* #author Burak Firik
*/
public class MenuListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
MainSingleton singleton=MainSingleton.getMainSingleton();
InputFrame inputFrame=singleton.getinputGUI();
inputFrame.setVisible(true);
}
}

how to add Zoom in/out functionality on bitmapfield?

I want to add functionality for the zoom in/out image that display by the bitmapfield.
I have search for this but couldn't get any useful tips for that,
can any one tell me how to add UI and functionality for the zooming image in/out.
Try this code
public final class ZoomScreenDemo extends UiApplication
{
public static void main(final String[] args)
{
// Create a new instance of the application and make the currently
// running thread the application's event dispatch thread.
UiApplication app = new ZoomScreenDemo();
app.enterEventDispatcher();
}
/**
* Creates a new ZoomScreenDemo object
*/
public ZoomScreenDemo()
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Click trackball or screen to zoom");
}
});
pushScreen(new ZoomScreenDemoScreen());
}
public final static class ZoomScreenDemoScreen extends MainScreen
{
private EncodedImage _image;
/**
* Creates a new ZoomScreenDemoScreen object
*/
public ZoomScreenDemoScreen()
{
setTitle("Zoom Screen Demo");
_image = EncodedImage.getEncodedImageResource("img/building.jpg");
BitmapField bitmapField = new BitmapField(_image.getBitmap(), FIELD_HCENTER | FOCUSABLE);
add(bitmapField);
}
/**
* #see Screen#navigationClick(int, int)
*/
protected boolean navigationClick(int status, int time)
{
// Push a new ZoomScreen if track ball or screen is clicked
UiApplication.getUiApplication().pushScreen(new ZoomScreen(_image));
return true;
}
/**
* #see Screen#touchEvent(TouchEvent)
*/
protected boolean touchEvent(TouchEvent message)
{
if(message.getEvent() == TouchEvent.CLICK)
{
UiApplication.getUiApplication().pushScreen(new ZoomScreen(_image));
}
return super.touchEvent(message);
}
}
}

Resources