add drag sort

This commit is contained in:
Timi
2026-04-24 10:40:08 +08:00
parent d504c1ef68
commit 3941040362

View File

@@ -10,16 +10,22 @@ import com.imyeyu.lang.multi.ResourcesMultilingual;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.input.TransferMode;
import lombok.RequiredArgsConstructor;
/**
@@ -31,7 +37,10 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class HostTable extends TableView<Host> implements TimiFXUI {
private static final String DRAG_INDEX_KEY = "host-table-row-index";
private final ResourcesMultilingual multilingual;
private int dragSourceIndex = -1;
@PostConstruct
private void postConstruct() {
@@ -78,6 +87,10 @@ public class HostTable extends TableView<Host> implements TimiFXUI {
}
});
getColumns().add(activated);
TableColumn<Host, Void> drag = createDragColumn();
getColumns().add(drag);
// IP
TableColumn<Host, String> ip = new TableColumn<>("IP");
ip.setCellValueFactory(new PropertyValueFactory<>("ip"));
@@ -245,6 +258,7 @@ public class HostTable extends TableView<Host> implements TimiFXUI {
DoubleBinding db = widthProperty().subtract(8);
db = db.subtract(activated.widthProperty());
db = db.subtract(drag.widthProperty());
db = db.subtract(ip.widthProperty());
db = db.subtract(description.widthProperty());
db = db.subtract(delete.widthProperty());
@@ -256,5 +270,117 @@ public class HostTable extends TableView<Host> implements TimiFXUI {
// 滚动时编辑区主动失去焦点
addEventFilter(ScrollEvent.ANY, e -> requestFocus());
setRowFactory(table -> createDraggableRow());
}
/**
* 创建拖动排序列。
*
* @return 拖动排序列
*/
private TableColumn<Host, Void> createDragColumn() {
TableColumn<Host, Void> drag = new TableColumn<>("");
drag.setPrefWidth(40);
drag.setSortable(false);
drag.setResizable(false);
drag.setReorderable(false);
drag.setCellFactory(cell -> new TableCell<>() {
private final Button dragButton = new Button("::");
{
dragButton.getStyleClass().add(CSS.BORDER_N);
dragButton.setFocusTraversable(false);
dragButton.setOnDragDetected(this::startRowDrag);
setAlignment(Pos.CENTER);
}
@Override
protected void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
setGraphic(null);
} else {
setGraphic(dragButton);
}
}
/**
* 从拖动按钮发起行拖拽。
*
* @param event 鼠标事件
*/
private void startRowDrag(MouseEvent event) {
TableRow<Host> row = getTableRow();
if (row == null || row.isEmpty()) {
return;
}
dragSourceIndex = row.getIndex();
Dragboard dragboard = row.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
content.putString(DRAG_INDEX_KEY.formatted());
dragboard.setContent(content);
event.consume();
}
});
return drag;
}
/**
* 创建支持拖动排序的表格行。
*
* @return 表格行
*/
private TableRow<Host> createDraggableRow() {
TableRow<Host> row = new TableRow<>();
row.setOnDragOver(event -> {
if (dragSourceIndex < 0 || row.getIndex() == dragSourceIndex) {
return;
}
if (event.getDragboard().hasString()) {
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
}
});
row.setOnDragDropped(event -> {
if (dragSourceIndex < 0) {
return;
}
int targetIndex = row.isEmpty() ? getItems().size() : row.getIndex();
moveItem(dragSourceIndex, targetIndex);
event.setDropCompleted(true);
event.consume();
});
row.setOnDragDone(event -> dragSourceIndex = -1);
return row;
}
/**
* 调整条目顺序。
*
* @param fromIndex 原索引
* @param toIndex 目标索引
*/
private void moveItem(int fromIndex, int toIndex) {
ObservableList<Host> items = getItems();
if (fromIndex < 0 || items.size() <= fromIndex) {
return;
}
if (toIndex < 0) {
toIndex = 0;
}
if (items.size() < toIndex) {
toIndex = items.size();
}
if (fromIndex == toIndex) {
return;
}
Host movedItem = items.remove(fromIndex);
if (fromIndex < toIndex) {
toIndex--;
}
items.add(toIndex, movedItem);
getSelectionModel().clearAndSelect(toIndex);
scrollTo(toIndex);
}
}