Drag & Drop in JavaFX table? - drag-and-drop

I am using a JavaFX 2 table for some kind of playlist and I want to be able to drag & drop rows in the table, e.g. drag row 3 before row 2, like the drag & drop stuff you know from the playlists in typical media players like e.g. Winamp, AIMP...
Is that possible? Any code samples for that? Thank you very much!

try this one :)
#FXML
TableView<String> tableView;
private ObservableList<String> tableContent = FXCollections.observableArrayList();
//...
tableView.setOnMouseClicked(new EventHandler<MouseEvent>() { //click
#Override
public void handle(MouseEvent event) {
if(event.getClickCount()==2){ // double click
String selected = tableView.getSelectionModel().getSelectedItem();
if(selected !=null){
System.out.println("select : "+selected);
...
}
}
}
});
tableView.setOnDragDetected(new EventHandler<MouseEvent>() { //drag
#Override
public void handle(MouseEvent event) {
// drag was detected, start drag-and-drop gesture
String selected = tableView.getSelectionModel().getSelectedItem();
if(selected !=null){
Dragboard db = tableView.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.putString(selected);
db.setContent(content);
event.consume();
}
}
});
tableView.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
// data is dragged over the target
Dragboard db = event.getDragboard();
if (event.getDragboard().hasString()){
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
}
});
tableView.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
boolean success = false;
if (event.getDragboard().hasString()) {
String text = db.getString();
tableContent.add(text);
tableView.setItems(tableContent);
success = true;
}
event.setDropCompleted(success);
event.consume();
}
});

Related

Tableview drag and drop a song in a row to a playlist button on the side bar javafx

I have a javafx TableView populated with a class called Song. I have a sidebar in my border pane populated with Buttons that represent a class called Playlist. my (currently basic) UI looks like this:
I want to make it so that if I drag a song and drop it in to one of the buttons on the left, it adds that song to the playlist. Also I have looked and searched around the internet for an answer and haven't found anything useful. That being said, please don't link me to something. I have already tried implementing the code from the following link: http://docs.oracle.com/javase/8/javafx/events-tutorial/drag-drop.htm#CHDJFJDH
If you have any suggestions please help me! thanks!
UPDATE:
Here's my code, my naming conventions are pretty easily understandable:
musicTable.setOnMouseClicked(new EventHandler<MouseEvent>() { //click
#Override
public void handle(MouseEvent event) {
if (event.getClickCount() == 2) { // double click
Song selected = (Song)musicTable.getSelectionModel().getSelectedItem();
dragged = selected;
if (selected != null) {
System.out.println("select : " + selected);
}
}
}
});
musicTable.setOnDragDetected(new EventHandler<MouseEvent>() { //drag
#Override
public void handle(MouseEvent event) {
// drag was detected, start drag-and-drop gesture
Song selected = (Song)musicTable.getSelectionModel().getSelectedItem();
dragged = selected;
if (selected != null) {
Dragboard db = musicTable.startDragAndDrop(TransferMode.ANY);
ClipboardContent content = new ClipboardContent();
content.putString(selected.pointer.toString());
db.setContent(content);
event.consume();
}
}
});
musicTable.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
// data is dragged over the target
Dragboard db = event.getDragboard();
if (event.getDragboard().hasString()) {
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
}
});
musicTable.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
boolean success = false;
if (event.getDragboard().hasString()) {
String text = db.getString();
//tableContent.add(text);
//musicTable.setItems(tableContent);
success = true;
}
event.setDropCompleted(success);
event.consume();
}
});
playlistTable.setRowFactory(cb -> {
TableRow<Playlist> row = new TableRow<>();
row.setOnMouseClicked(ev -> {
musicTable.setItems(row.getItem().playlist);
row.setOnDragDropped( new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
boolean success = false;
row.getItem().add(dragged);
System.out.println("ACCEPED TRANSFER");
success = true;
event.setDropCompleted(success);
event.consume();
}
});
});
return row;
});
dragged is a song that keeps track of which song is being dragged, if you have any other way of doing that please tell me, musicTable is what I'm dragging from, playlist table is where I'm dragging to.
Ok, this is the smallest example I could create:
#Override
public void start(Stage primaryStage) throws IOException {
ObservableList<String> tableData = FXCollections
.observableList(IntStream.range(0, 1000)
.mapToObj(Integer::toString)
.collect(Collectors.toList()));
TableView<String> stringTable = new TableView<>(tableData);
TableColumn<String, String> column1 = new TableColumn<>();
column1.setCellValueFactory(cb -> new ReadOnlyStringWrapper(cb
.getValue()));
stringTable.getColumns().add(column1);
stringTable.setRowFactory(cb -> {
TableRow<String> row = new TableRow<>();
row.setOnDragDetected(ev -> {
Dragboard db = row.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(row.getItem());
db.setContent(content);
ev.consume();
});
return row;
});
VBox leftSide = new VBox();
leftSide.setPrefWidth(300);
leftSide.setOnDragOver(ev -> {
if (ev.getGestureSource() != leftSide && ev.getDragboard().hasString()) {
ev.acceptTransferModes(TransferMode.COPY);
}
ev.consume();
});
leftSide.setOnDragDropped(ev -> {
Dragboard db = ev.getDragboard();
boolean success = false;
if (db.hasString()) {
Label label = new Label(db.getString());
leftSide.getChildren().add(label);
success = true;
}
ev.setDropCompleted(success);
ev.consume();
});
BorderPane root = new BorderPane(stringTable);
root.setLeft(leftSide);
Scene scene = new Scene(root, 700, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
This is a BorderPane where the center is a TableView and the left side is a VBox.
Now I added your requested Drag and Drop handlers so you can drag rows (thus this is done in the row factory) to the left side, where they are added as new Labels to the VBox as new children.
Edit: Second example with ListView as drop target:
#Override
public void start(Stage primaryStage) {
ObservableList<String> tableData = FXCollections
.observableList(IntStream.range(0, 1000)
.mapToObj(Integer::toString)
.collect(Collectors.toList()));
TableView<String> stringTable = new TableView<>(tableData);
TableColumn<String, String> column1 = new TableColumn<>();
column1.setCellValueFactory(cb -> new ReadOnlyStringWrapper(cb
.getValue()));
stringTable.getColumns().add(column1);
stringTable.setRowFactory(cb -> {
TableRow<String> row = new TableRow<>();
row.setOnDragDetected(ev -> {
Dragboard db = row.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.putString(row.getItem());
db.setContent(content);
ev.consume();
});
return row;
});
ObservableList<String> leftSideItems = FXCollections
.observableList(IntStream.range(0, 1000)
.mapToObj(Integer::toString)
.collect(Collectors.toList()));
ListView<String> leftSideDropTarget = new ListView<String>(
leftSideItems);
leftSideDropTarget.setPrefWidth(200);
leftSideDropTarget.setCellFactory(cb -> {
ListCell<String> cell = new TextFieldListCell<>();
cell.setOnDragOver(ev -> {
if (ev.getGestureSource() != cell
&& ev.getDragboard().hasString()) {
ev.acceptTransferModes(TransferMode.COPY);
}
ev.consume();
});
cell.setOnDragDropped(ev -> {
Dragboard db = ev.getDragboard();
boolean success = false;
if (db.hasString()) {
cell.setText("Got Item: " + db.getString());
success = true;
}
ev.setDropCompleted(success);
ev.consume();
});
return cell;
});
BorderPane root = new BorderPane(stringTable);
root.setLeft(leftSideDropTarget);
Scene scene = new Scene(root, 700, 400);
primaryStage.setScene(scene);
primaryStage.show();
}

Items does not sets disabled after first click on ListBox in Chrome

Here is my code:
listbox.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
serv.getSlotStatusesStrings(clientFactory.getWorkspaceId(), new AsyncCallback<SlotStatusGwtStruct>() {
#Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
#Override
public void onSuccess(SlotStatusGwtStruct result) {
List<String> statusList = Arrays.asList(result.styleName);
int emtyCounter = 0;
boolean passFlag = false;
boolean failFlag = false;
for(String status : statusList){
if(status.equals("empty")){
emtyCounter++;
}else if(status.equals("pass")){
passFlag = true;
}else if(status.equals("fail")){
failFlag = true;
}
}
if(emtyCounter == statusList.size()){
listbox.getElement().<SelectElement>cast().getOptions().getItem(0).setDisabled(true);
}
if(passFlag == false){
listbox.getElement().<SelectElement>cast().getOptions().getItem(1).setDisabled(true);
}
if(failFlag == false){
listbox.getElement().<SelectElement>cast().getOptions().getItem(2).setDisabled(true);
}
}
});
}
});
}
In Firefox it works ok, but in Chrome browser when I click on listbox at the first time all my items are enabled (by condition they should be disabled), and after I made one more click I have the expected result.
Could yo please give me some advice how to resolve this issue.

DoubleClick on a row in JfaceTable to get the details of object on that row

In eclipse e4.
On double clicking on a row in jface table I want to see the data on that row as a dialog.
Existing Code
orgTable.addDoubleClickListener(new IDoubleClickListener() {
#Override
public void doubleClick(DoubleClickEvent event) {
System.out.println("Double CLikc works");
}
});
OrgTable.addDoubleClickListener(new IDoubleClickListener() {
#Override
public void doubleClick(DoubleClickEvent event) {
System.out.println("Double CLikc works");
IStructuredSelection sel = (IStructuredSelection) event.getSelection();
OrgDetails org = (OrgDetails) sel.getFirstElement();
if(org != null){
System.out.println("Double-click on : "+ org.getOrgName()+ " " + org.getTin());
}
System.out.println(orgTable.getElementAt());
}
});

How to move items with in VBox(Change order by Dragging) in JavaFX?

i want to drag TitledPane with in a VBox.I have n number of Titlepane's in a VBox. I want to change the order of them when dragded.I tried with some of MouseEvents and DragEvents. But its not working for me.
But i need the indexes of which Titledpane is moved to which place. Based on that i need to do something in backend. Please help me.
Thanks
This works for me...
private static final String TAB_DRAG_KEY = "titledpane";
private ObjectProperty<TitledPane> draggingTab;
#Override
public void start(Stage primaryStage) throws Exception {
draggingTab = new SimpleObjectProperty<TitledPane>();
VBox vbox=new VBox();
for(int i=0;i<4;i++) {
final TitledPane pane=new TitledPane();
pane.setText("pane"+(i+1));
vbox.getChildren().add(pane);
pane.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
final Dragboard dragboard = event.getDragboard();
if (dragboard.hasString()
&& TAB_DRAG_KEY.equals(dragboard.getString())
&& draggingTab.get() != null) {
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
}
}
});
pane.setOnDragDropped(new EventHandler<DragEvent>() {
public void handle(final DragEvent event) {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
Pane parent = (Pane) pane.getParent();
Object source = event.getGestureSource();
int sourceIndex = parent.getChildren().indexOf(source);
int targetIndex = parent.getChildren().indexOf(pane);
List<Node> nodes = new ArrayList<Node>(parent.getChildren());
if (sourceIndex < targetIndex) {
Collections.rotate(
nodes.subList(sourceIndex, targetIndex + 1), -1);
} else {
Collections.rotate(
nodes.subList(targetIndex, sourceIndex + 1), 1);
}
parent.getChildren().clear();
parent.getChildren().addAll(nodes);
success = true;
}
event.setDropCompleted(success);
event.consume();
}
});
pane.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Dragboard dragboard = pane.startDragAndDrop(TransferMode.MOVE);
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(TAB_DRAG_KEY);
dragboard.setContent(clipboardContent);
draggingTab.set(pane);
event.consume();
}
});
}
TitledPane pane=new TitledPane("MAIN",vbox);
primaryStage.setScene(new Scene(pane, 890, 570));
primaryStage.show();
}

javafx drag-and-drop moving icon

I am working with drag and drop on JavaFX2. It's possible that the dragged-Object (maybe clone of the dragged object) following the mousecursor like on the JavaFX Scene Builder.
This is my sample sourcecode:
Pane pane;
private void dragAndDropExample() {
pane = new Pane();
pane.setPrefSize(800, 600);
TitledPane titlePane = new TitledPane("Partial Order", pane);
add(titlePane, 0, 2);
pane.getChildren().add(createCircle(350, 300, Color.RED));
pane.getChildren().add(createCircle(250, 300, Color.BROWN));
pane.setOnMouseMoved(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (circleToMove != null) {
circleToMove.setCenterX(event.getX());
circleToMove.setCenterY(event.getY());
}
}
});
}
Circle circleToMove;
private Circle createCircle(double x, double y, Color color) {
final Circle c = new Circle(x, y, 25);
c.setFill(color);
c.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
System.out.println("SetOnDragDetected");
c.setFill(Paint.valueOf("blue"));
Dragboard db = c.startDragAndDrop(TransferMode.COPY_OR_MOVE);
ClipboardContent content = new ClipboardContent();
content.putString("foo " + c.hashCode());
db.setContent(content);
arg0.consume();
circleToMove = c;
}
});
c.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Mouse clicked");
}
});
c.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Mouse Released");
circleToMove = null;
}
});
c.setOnDragExited(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
System.out.println("SetOnDragExited");
System.out.println(event.getGestureSource());
}
});
c.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
System.out.println("setOnDragOver " + c.hashCode());
c.setFill(Paint.valueOf("white"));
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
event.consume();
}
});
c.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent arg0) {
System.out.println("setOnDragDropped");
c.setFill(Paint.valueOf("black"));
if (arg0.getGestureSource() instanceof Circle) {
if (arg0.getDragboard().hasString()) {
System.out.println(c.hashCode() + " hat jetzt " + arg0.getDragboard().getString());
}
}
}
});
c.setOnDragEntered(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent arg0) {
System.out.println("setOnDragEntered");
}
});
return c;
}
I tried with the mouseEvent on the pane, but this event does not get fired during drag and drop.
You are using wrong handlers. There drag events are used to drag items between panes. If you want to just move handled object use next code:
private Circle createCircle(double x, double y, Color color) {
final Circle c = new Circle(x, y, 25);
c.setFill(color);
c.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
c.relocate(event.getSceneX() - c.getRadius(), event.getSceneY() - c.getRadius());
}
});
return c;
}
Also you can try to look at next subsample in the Ensemble demo: