Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JavaFX中创建一个合适的选项卡式界面?_Java_User Interface_Javafx_Tabs_User Experience - Fatal编程技术网

在JavaFX中创建一个合适的选项卡式界面?

在JavaFX中创建一个合适的选项卡式界面?,java,user-interface,javafx,tabs,user-experience,Java,User Interface,Javafx,Tabs,User Experience,我正在用JavaFX编写一个应用程序,它将使用制表符。用户可能希望同时打开彼此旁边的选项卡(而不是一次只打开一个选项卡)。理想情况下,这可以通过将选项卡拖动到屏幕的一侧来实现 最初,我认为制作一个只有一个网格的网格面板是一个好主意,然后在用户拖动选项卡时添加网格。我认为那行不通。有什么好办法吗?JavaFX的布局和窗格控件真的缺少这样的功能吗 在C#中,我可能会使用类似的方法来实现我想要的行为: 问题是:如何在JavaFX中使用选项卡实现正确的用户体验,允许用户拖动选项卡以获得“拆分”布局 编辑

我正在用JavaFX编写一个应用程序,它将使用制表符。用户可能希望同时打开彼此旁边的选项卡(而不是一次只打开一个选项卡)。理想情况下,这可以通过将选项卡拖动到屏幕的一侧来实现

最初,我认为制作一个只有一个网格的网格面板是一个好主意,然后在用户拖动选项卡时添加网格。我认为那行不通。有什么好办法吗?JavaFX的布局和窗格控件真的缺少这样的功能吗

在C#中,我可能会使用类似的方法来实现我想要的行为:

问题是:如何在JavaFX中使用选项卡实现正确的用户体验,允许用户拖动选项卡以获得“拆分”布局


编辑:目前我正在考虑用HBox复制我的上述想法。有人知道我如何在HBox中实现标签拖动到另一个象限吗?

所以你的问题有点模糊,我可能不应该回答,因为老实说,我真的不知道“适当的标签界面”到底意味着什么

这是一个允许选项卡彼此并排打开的系统。右键单击选项卡,弹出上下文菜单,选择垂直或水平拆分。选项卡内容将以所需的方向在拆分窗格内的新选项卡窗格中复制

这绝对不是一个完整的对接解决方案,甚至可能不接近您想要的,但您可能会发现它很有用(可能不是;-)。该解决方案只完成拆分,但不在拆分区域之间拖放选项卡(如果您自己无法理解,可能需要了解拖放部分的信息)

下面的解决方案只是将拆分选项卡的内容复制到新拆分区域中的新选项卡。进一步的增强可以实现类似于通用同步文档模型的功能,该模型允许并行编辑在不同选项卡中复制的文件(类似于Intellij Idea的编辑器实现,该拆分系统概念就是从该编辑器实现中派生出来的)

导入javafx.application.application;
导入javafx.geometry.Orientation;
导入javafx.scene.Node;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
导入java.util.HashMap;
导入java.util.Optional;
导入java.util.stream.collector;
导入java.util.stream.IntStream;
公共类SplitTabs扩展了应用程序{
最终Lorem Lorem=新Lorem();
final HashMap splitPanes=新HashMap();
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公众假期开始(阶段){
TabPane TabPane=新建TabPane();
//无检查结果方法Callignored
IntStream.range(0,5)
.mapToObj(i->createTab(lorem.nextString(1),lorem.nextString(200)))
.collect(collector.toCollection(tabPane::getTabs));
stage.setScene(新场景(新StackPane(tabPane));
stage.show();
}
私有选项卡createTab(字符串标题、字符串文本){
TextArea TextArea=新的TextArea(文本);
textArea.setWrapText(true);
Tab Tab=新选项卡(标题);
tab.设置内容(文本区域);
tab.setOnCloseRequest(事件->{
TabPane TabPane=tab.getTabPane();

if(tabPane.getTabs().size())没有预定义任何内容。可能有一些第三方库实现了类似的功能(例如,我认为有停靠功能)。否则,您只需使用适当的鼠标处理程序等自行实现。我认为使用TabPane不可能做到这一点,因为您无法知道鼠标操作发生在哪个选项卡上。我可能会创建“fake”使用ToggleButtons的选项卡,我将使用StackPane作为内容区域,将每个选项卡内容节点的可见性绑定到特定ToggleButton的选定状态。@VGR另一种解决方法是使用
标签作为
选项卡上的图形(而不是设置选项卡的文本),并使用标签注册鼠标处理程序。(如果你真的有雄心壮志,也可以写一本新的
TabPaneSkin
。)有很多LIB,只需搜索可分离的tabpane即可。例如,谢谢!我现在将此设置为答案,因为它比我现有的更好。我对没有更好的解决方案感到困惑。我想没有人希望选项卡式文档放在彼此旁边?嗯,有东西(请参阅其他注释中链接的解决方案),我只是不知道它们是否是你想要的。我认为对于成熟的桌面对接界面和应用程序框架,Swing和SWT已经存在了一段时间,人们已经为此创造了很多东西(例如)。您可以在其中任何一个平台中使用JavaFX,因此,与其在JavaFX中创建如此规模的新平台,不如在这些平台中嵌入JavaFX程序,尽管为这些平台编写代码需要相当高的复杂度。
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.util.HashMap;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SplitTabs extends Application {
    final Lorem lorem = new Lorem();

    final HashMap<Node, SplitPane> splitPanes = new HashMap<>();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        TabPane tabPane = new TabPane();
        //noinspection ResultOfMethodCallIgnored
        IntStream.range(0, 5)
                .mapToObj(i -> createTab(lorem.nextString(1), lorem.nextString(200)))
                .collect(Collectors.toCollection(tabPane::getTabs));

        stage.setScene(new Scene(new StackPane(tabPane)));
        stage.show();
    }

    private Tab createTab(String title, String text) {
        TextArea textArea = new TextArea(text);
        textArea.setWrapText(true);

        Tab tab = new Tab(title);
        tab.setContent(textArea);
        tab.setOnCloseRequest(event -> {
            TabPane tabPane = tab.getTabPane();
            if (tabPane.getTabs().size() <= 1) {
                SplitPane splitPane = splitPanes.get(tabPane);
                if (splitPane == null) {
                    // don't allow the last tab to be closed.
                    event.consume();
                    return;
                }

                int siblingIdx = (splitPane.getItems().indexOf(tabPane) + 1) % 2;
                Node siblingItem = splitPane.getItems().get(siblingIdx);


                Optional<SplitPane> optionalParentSplitPane =
                        splitPanes.values().stream()
                                .filter(searchPane -> searchPane.getItems().contains(splitPane))
                                .findFirst();

                // make the last TabPane the root.
                if (!optionalParentSplitPane.isPresent()) {
                    StackPane stackPane = (StackPane) splitPane.getParent() ;
                    stackPane.getChildren().setAll(siblingItem);
                    splitPanes.clear();
                    return;
                }

                // graft sibling under parent.
                SplitPane parentSplitPane = optionalParentSplitPane.get();

                int idx = parentSplitPane.getItems().indexOf(splitPane);
                parentSplitPane.getItems().set(idx, siblingItem);
                splitPane.getItems().forEach(splitPanes::remove);
                splitPanes.put(siblingItem, parentSplitPane);
            }
        });

        MenuItem splitVertically = new MenuItem("Split Vertically");
        splitVertically.setOnAction(event -> split(title, text, tab, Orientation.HORIZONTAL));
        MenuItem splitHorizontally = new MenuItem("Split Horizontally");
        splitHorizontally.setOnAction(event -> {
            split(title, text, tab, Orientation.VERTICAL);
        });

        tab.setContextMenu(new ContextMenu(
                splitVertically,
                splitHorizontally
        ));

        return tab;
    }

    private void split(String title, String text, Tab tab, Orientation orientation) {
        TabPane tabPane = tab.getTabPane();
        Tab tabCopy = createTab(title, text);
        TabPane newTabPane = new TabPane(tabCopy);
        SplitPane splitPane = new SplitPane(tabPane, newTabPane);
        splitPane.setOrientation(orientation);

        if (splitPanes.isEmpty()) {
            StackPane stackPane = (StackPane) tabPane.getParent();
            stackPane.getChildren().setAll(splitPane);
            splitPanes.put(tabPane, splitPane);
            splitPanes.put(newTabPane, splitPane);
        } else {
            SplitPane parentSplit = splitPanes.get(tabPane);
            int idx = parentSplit.getItems().indexOf(tabPane);
            parentSplit.getItems().set(idx, splitPane);
            splitPanes.remove(tabPane);
            splitPanes.put(splitPane, parentSplit);
            splitPanes.put(tabPane, splitPane);
            splitPanes.put(newTabPane, splitPane);
        }
    }
}

class Lorem {
    private static final String[] IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque hendrerit imperdiet mi quis convallis. Pellentesque fringilla imperdiet libero, quis hendrerit lacus mollis et. Maecenas porttitor id urna id mollis. Suspendisse potenti. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras lacus tellus, semper hendrerit arcu quis, auctor suscipit ipsum. Vestibulum venenatis ante et nulla commodo, ac ultricies purus fringilla. Aliquam lectus urna, commodo eu quam a, dapibus bibendum nisl. Aliquam blandit a nibh tincidunt aliquam. In tellus lorem, rhoncus eu magna id, ullamcorper dictum tellus. Curabitur luctus, justo a sodales gravida, purus sem iaculis est, eu ornare turpis urna vitae dolor. Nulla facilisi. Proin mattis dignissim diam, id pellentesque sem bibendum sed. Donec venenatis dolor neque, ut luctus odio elementum eget. Nunc sed orci ligula. Aliquam erat volutpat.".split(" ");
    private int idx = 0;

    public String nextString(int nWords) {
        int end = Math.min(idx + nWords, IPSUM.length);

        StringBuilder result = new StringBuilder();
        for (int i = idx; i < end; i++) {
            result.append(IPSUM[i]).append(" ");
        }

        idx += nWords;
        idx = idx % IPSUM.length;

        return result.toString();
    }
}