Java 如何拖放同一选项卡窗格的选项卡?
关于如何将选项卡窗格的选项卡拖动到另一个选项卡窗格,我已经看到了很多,但我不认为这有什么意义,我想这在某种程度上是有用的,但最自然的应用应该是重新排序同一选项卡窗格的选项卡,这在互联网上似乎没有人谈论 我喜欢几乎所有浏览器都实现的行为 我试过一些东西,但它不是我想要的。主要问题来自这样一个事实:Java 如何拖放同一选项卡窗格的选项卡?,java,events,javafx,tabs,drag-and-drop,Java,Events,Javafx,Tabs,Drag And Drop,关于如何将选项卡窗格的选项卡拖动到另一个选项卡窗格,我已经看到了很多,但我不认为这有什么意义,我想这在某种程度上是有用的,但最自然的应用应该是重新排序同一选项卡窗格的选项卡,这在互联网上似乎没有人谈论 我喜欢几乎所有浏览器都实现的行为 我试过一些东西,但它不是我想要的。主要问题来自这样一个事实:选项卡不能与setOnDragDetected、setOnDragOver等方法绑定(由于某种原因,顺便提一下……),这导致算法过于复杂,无法弥补库的这一弱点 这是我的代码,它没有做我想做的事情,因为(这
选项卡
不能与setOnDragDetected
、setOnDragOver
等方法绑定(由于某种原因,顺便提一下……),这导致算法过于复杂,无法弥补库的这一弱点
这是我的代码,它没有做我想做的事情,因为(这只是一个解决办法)我只在投放后检测到“投放目标”,因此它没有用。是的,出于某种原因,在按住单击按钮的同时悬停对象不会导致鼠标悬停事件
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class DragAndDrop extends Application
{
public void start(Stage primaryStage)
{
TabPane tabPane = new TabPane();
final int[] target = {0};
for(int i = 0 ; i < 2 ; i ++)
{
Tab tab = new Tab();
tab.setClosable(false);
int index[] = {i};
tabPane.getTabs().add(tab);
Label label = new Label("Tab " + (i + 1), new Rectangle(16, 16, Color.TRANSPARENT));
tab.setGraphic(label);
tab.getGraphic().setOnMouseEntered(event ->
{
target[0] = index[0];
System.out.println("target : " + target[0]);
});
}
tabPane.setOnDragDetected(event ->
{
Dragboard dragboard = tabPane.startDragAndDrop(TransferMode.ANY);
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(Integer.toString(tabPane.getSelectionModel().getSelectedIndex()));
System.out.println("source : " + tabPane.getSelectionModel().getSelectedIndex());
dragboard.setContent(clipboardContent);
event.consume();
});
tabPane.setOnDragOver(event ->
{
if(event.getDragboard().hasString())
{
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
});
tabPane.setOnDragDropped(event ->
{
Dragboard dragboard = event.getDragboard();
boolean success = false;
if(dragboard.hasString())
{
System.out.println("from " + dragboard.getString() + " to " + target[0]);
success = true;
}
event.setDropCompleted(success);
event.consume();
});
tabPane.setOnDragDone(event ->
{
if(event.getTransferMode() == TransferMode.MOVE)
{
// tabPane.setText("");
}
event.consume();
});
primaryStage.setScene(new Scene(tabPane, 300, 200));
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
导入javafx.application.application;
导入javafx.scene.scene;
导入javafx.scene.control.Label;
导入javafx.scene.control.Tab;
导入javafx.scene.control.TabPane;
导入javafx.scene.input.ClipboardContent;
导入javafx.scene.input.Dragboard;
导入javafx.scene.input.TransferMode;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Rectangle;
导入javafx.stage.stage;
公共类DragAndDrop扩展了应用程序
{
公共无效开始(阶段primaryStage)
{
TabPane TabPane=新建TabPane();
最终int[]目标={0};
对于(int i=0;i<2;i++)
{
Tab Tab=新选项卡();
tab.setClosable(false);
int索引[]={i};
tabPane.getTabs().add(tab);
标签标签=新标签(“标签”+(i+1),新矩形(16,16,颜色.透明));
tab.设置图形(标签);
tab.getGraphic().setOnMouseCentered(事件->
{
目标[0]=指数[0];
System.out.println(“目标:+target[0]);
});
}
tabPane.setOnDragDetected(事件->
{
Dragboard Dragboard=tabPane.startdragandrop(TransferMode.ANY);
ClipboardContent ClipboardContent=新的ClipboardContent();
clipboardContent.putString(Integer.toString(tabPane.getSelectionModel().getSelectedIndex());
System.out.println(“来源:+tabPane.getSelectionModel().getSelectedIndex());
dragboard.setContent(剪贴板内容);
event.consume();
});
tabPane.setOnDragOver(事件->
{
if(event.getDragboard().haString())
{
事件.acceptTransferModes(TransferMode.COPY\u或\u MOVE);
}
event.consume();
});
tabPane.setOnDragDrop(事件->
{
Dragboard Dragboard=event.getDragboard();
布尔成功=假;
if(dragboard.hastring())
{
System.out.println(“从“+dragboard.getString()+”到“+target[0]);
成功=真实;
}
事件。setDropCompleted(成功);
event.consume();
});
tabPane.setOnDragDone(事件->
{
if(event.getTransferMode()==TransferMode.MOVE)
{
//tabPane.setText(“”);
}
event.consume();
});
设置场景(新场景(tabPane,300200));
primaryStage.show();
}
公共静态void main(字符串[]args)
{
发射(args);
}
}
我认为最简单的方法是使用与选项卡关联的图形注册拖动处理程序,而不是使用选项卡窗格。这使得管理选项卡的索引等变得更容易一些,并且您不依赖于鼠标拖动操作和选择之间的相互作用(您真的不知道它们将以什么顺序发生)。这种方法的缺点是,您必须以某种方式确保每个选项卡都有一个图形(您可以使用标签作为图形来显示文本)
这是一个通用的“选项卡窗格拖动支持”类。无论如何,这并不意味着产品质量,但基本要素似乎起了作用。这里的想法是创建一个DraggingTabPaneSupport
实例,并使用它向一个或多个TabPane
s添加拖动支持。然后可以在这些窗格内或窗格之间拖动选项卡。如果希望只能在每个选项卡窗格内拖动,请为每个选项卡窗格创建一个DraggingTabPaneSupport
实例
import java.util.concurrent.atomic.AtomicLong;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
public class DraggingTabPaneSupport {
private Tab currentDraggingTab ;
private static final AtomicLong idGenerator = new AtomicLong();
private final String draggingID = "DraggingTabPaneSupport-"+idGenerator.incrementAndGet() ;
public void addSupport(TabPane tabPane) {
tabPane.getTabs().forEach(this::addDragHandlers);
tabPane.getTabs().addListener((Change<? extends Tab> c) -> {
while (c.next()) {
if (c.wasAdded()) {
c.getAddedSubList().forEach(this::addDragHandlers);
}
if (c.wasRemoved()) {
c.getRemoved().forEach(this::removeDragHandlers);
}
}
});
// if we drag onto a tab pane (but not onto the tab graphic), add the tab to the end of the list of tabs:
tabPane.setOnDragOver(e -> {
if (draggingID.equals(e.getDragboard().getString()) &&
currentDraggingTab != null &&
currentDraggingTab.getTabPane() != tabPane) {
e.acceptTransferModes(TransferMode.MOVE);
}
});
tabPane.setOnDragDropped(e -> {
if (draggingID.equals(e.getDragboard().getString()) &&
currentDraggingTab != null &&
currentDraggingTab.getTabPane() != tabPane) {
currentDraggingTab.getTabPane().getTabs().remove(currentDraggingTab);
tabPane.getTabs().add(currentDraggingTab);
currentDraggingTab.getTabPane().getSelectionModel().select(currentDraggingTab);
}
});
}
private void addDragHandlers(Tab tab) {
// move text to label graphic:
if (tab.getText() != null && ! tab.getText().isEmpty()) {
Label label = new Label(tab.getText(), tab.getGraphic());
tab.setText(null);
tab.setGraphic(label);
}
Node graphic = tab.getGraphic();
graphic.setOnDragDetected(e -> {
Dragboard dragboard = graphic.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
// dragboard must have some content, but we need it to be a Tab, which isn't supported
// So we store it in a local variable and just put arbitrary content in the dragbaord:
content.putString(draggingID);
dragboard.setContent(content);
dragboard.setDragView(graphic.snapshot(null, null));
currentDraggingTab = tab ;
});
graphic.setOnDragOver(e -> {
if (draggingID.equals(e.getDragboard().getString()) &&
currentDraggingTab != null &&
currentDraggingTab.getGraphic() != graphic) {
e.acceptTransferModes(TransferMode.MOVE);
}
});
graphic.setOnDragDropped(e -> {
if (draggingID.equals(e.getDragboard().getString()) &&
currentDraggingTab != null &&
currentDraggingTab.getGraphic() != graphic) {
int index = tab.getTabPane().getTabs().indexOf(tab) ;
currentDraggingTab.getTabPane().getTabs().remove(currentDraggingTab);
tab.getTabPane().getTabs().add(index, currentDraggingTab);
currentDraggingTab.getTabPane().getSelectionModel().select(currentDraggingTab);
}
});
graphic.setOnDragDone(e -> currentDraggingTab = null);
}
private void removeDragHandlers(Tab tab) {
tab.getGraphic().setOnDragDetected(null);
tab.getGraphic().setOnDragOver(null);
tab.getGraphic().setOnDragDropped(null);
tab.getGraphic().setOnDragDone(null);
}
}
import java.util.concurrent.AtomicLong;
导入javafx.collections.ListChangeListener.Change;
导入javafx.scene.Node;
导入javafx.scene.control.Label;
导入javafx.scene.control.Tab;
导入javafx.scene.control.TabPane;
导入javafx.scene.input.ClipboardContent;
导入javafx.scene.input.Dragboard;
导入javafx.scene.input.TransferMode;
公共类绘图窗格支持{
私有选项卡CurrentDragingTab;
私有静态最终AtomicLong idGenerator=新AtomicLong();
私有最终字符串draggingID=“DraggingTabPanesSupport-”+idGenerator.incrementAndGet();
public void addSupport(选项卡窗格选项卡窗格){
tabPane.getTabs().forEach(this::addDragHandlers);
tabPane.getTabs().addListener((更改)您是否尝试过直接在选项卡图形上设置拖动处理程序?我认为这会使逻辑更加清晰。在这种情况下,您不必依赖选择模型。遗憾的是,这在javafx()中还不可用。尽管它非常旧(请求链接用于javafx-2.x),答案中的网络日志链接给出了一个很好的解释,并举例说明了您可能希望如何实现目标。@James\u D我认为这不会改变任何问题,因为我仍然无法检测到第二个选项卡的悬停
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class DraggingTabPaneExample extends Application {
private final Random rng = new Random();
@Override
public void start(Stage primaryStage) {
TabPane[] panes = new TabPane[] {new TabPane(), new TabPane(), new TabPane() };
VBox root = new VBox(10, panes);
for (int i = 1 ; i <= 15; i++) {
Tab tab = new Tab("Tab "+i);
tab.setGraphic(new Rectangle(16, 16, randomColor()));
Region region = new Region();
region.setMinSize(100, 150);
tab.setContent(region);
panes[(i-1) % panes.length].getTabs().add(tab);
}
DraggingTabPaneSupport support1 = new DraggingTabPaneSupport();
support1.addSupport(panes[0]);
support1.addSupport(panes[1]);
DraggingTabPaneSupport support2 = new DraggingTabPaneSupport();
support2.addSupport(panes[2]);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private Color randomColor() {
return Color.rgb(rng.nextInt(256), rng.nextInt(256), rng.nextInt(256));
}
public static void main(String[] args) {
launch(args);
}
}