【问题标题】:Javafx - Side-by-side TabPanes. How to find which Tab has focus/selectionJavafx - 并排的 TabPanes。如何找到哪个选项卡具有焦点/选择
【发布时间】:2013-05-31 10:18:19
【问题描述】:

我有一个具有以下节点布局的 JavaFX 应用程序:

  • 拆分窗格
    • 文本区域
    • 拆分窗格
      • 选项卡窗格
      • 选项卡窗格

示例代码:

SplitPane topBottomSplitPane = new SplitPane();

TextArea displayTextArea = new TextArea();
SplitPane leftRightSplitPane = new SplitPane();

topBottomSplitPane.getItems().addAll(displayTextArea, leftRightSplitPane);

TabPane leftTabPane = new TabPane();
TabPane rightTabPane = new TabPane();

leftRightSplitPane.getItems().addAll(leftTabPane, rightTabPane);

TextArea,displayTextArea,是一个不可编辑的文本区域,它显示一些文本数据,具体取决于两个 TabPanes(leftTabPane 和 rightTabPane)内打开的 Tab 对象中存在的数据。 TabPane 的 SelectionModel 是单数的,因此每个 TabPane 一次只能选择一个选项卡。

我的限制之一是只有一个打开的 Tab 对象数据应该影响 displayTextArea 的文本。当只有一个 TabPane 对象时,这很容易实现,方法是设置 OnSelectionChanged EventHandler 并使用 isSelected() 来确定选择的更改是进入还是退出选择。并且选定的选项卡将是影响 displayTextArea 的选项卡。

当有两个 TabPanes 时,我希望内容节点当前具有焦点的 Tab,例如 TextField 或用户正在输入将影响 displayTextArea 文本的数据的表单。从用户的角度来看,他们将单击 TabPanes 中打开的选项卡,而他们最后一次单击的选项卡将影响 displayTextArea。但这就是我撞墙的地方。

尝试和失败的方法:

  1. 设置某种侦听器,以便在焦点从一个选项卡的内容节点更改为另一个选项卡的内容节点时收到通知,无论它们位于哪个 TabPane,然后相应地更新 displayTextArea。 - 没有 AddFocusListener 方法,我不确定如何使用可用的面向焦点的方法和功能来实现此行为。

  2. 在多个 TabPanes 之间的任意时间强制只选择 1 个选项卡,并坚持使用上述 OnSelectionChanged EventHandler 方法。 - 我不知道从哪里开始,也找不到任何东西。

question 中,有一个主题是将焦点更改为选项卡内容节点中的 TextField 对象,但我无法从该帖子中获取任何对我的目的有用的内容。

我迷路了,不知道如何实现这个显示的必要功能。

【问题讨论】:

    标签: tabs event-handling focus javafx-2


    【解决方案1】:

    由于 displayTextArea 一次只能显示与四个选项卡之一相关的内容,因此您无需尝试将两组选项卡链接在一起。相反,每个选项卡窗格都可以对选择更改有自己的响应。它们之间唯一的共同点是所有选择更改都将调用填充 displayTextArea 的相同方法。出于本示例的目的,我们调用该方法 setDisplayTextAreaContent,还假设通过将该方法传递给最近选择的选项卡,它将知道如何填充 displayTextArea。在做出这些假设以及我正确理解您的问题的假设之后,解决方案可能看起来像这样......

        TabPane tabPane1 = new TabPane();
        final Tab tab1 = new Tab();
        final Tab tab2 = new Tab();
        tabPane1.getTabs().addAll(tab1, tab2);
        tabPane1.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>()
        {
            @Override
            public void changed(ObservableValue<? extends Tab> arg0, Tab arg1, Tab mostRecentlySelectedTab)
            {
                if (mostRecentlySelectedTab.equals(tab1))
                {
                    setDisplayTextAreaContent(tab1);
                }
                if (mostRecentlySelectedTab.equals(tab2))
                {   
                    setDisplayTextAreaContent(tab2);
                }
            }
        });
    
        TabPane tabPane2 = new TabPane();
        final Tab tab3 = new Tab();
        final Tab tab4 = new Tab();
        tabPane2.getTabs().addAll(tab1, tab2);
        tabPane2.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>()
        {
            @Override
            public void changed(ObservableValue<? extends Tab> arg0, Tab arg1, Tab mostRecentlySelectedTab)
            {
                if (mostRecentlySelectedTab.equals(tab3))
                {
                    setDisplayTextAreaContent(tab3);
                }
                if (mostRecentlySelectedTab.equals(tab4))
                {   
                    setDisplayTextAreaContent(tab4);
                }
            }
        });
    

    您可以改为向 TabPanes 的 selectedIndexProperty 添加一个侦听器,如果这对您更有效(假设您知道哪些选项卡位于其各自 TabPanes 内的哪个索引处)。我希望这个答案可以帮助你。如果您有任何问题,请告诉我,如果可以,我很乐意回答。

    【讨论】:

    • 我忘了提到两个 TabPanes 之间可以有任意数量的选项卡。图片只是整体布局的一个例子。尽管可以更改您的方法以考虑到这一点,但仍然会出现一个问题。检查此用例:用户单击 leftTabPane 的 tab2,然后单击 rightTabPane 的 tab2。然后用户想回到leftTabPane的tab2,但它已经是当前选择的选项卡,因此不会抛出选择事件的变化。当前选择了两个 TabPanes 的 tab2,因此从一个到另一个不会引发事件。
    【解决方案2】:

    我想出了一个合理且相当简单的解决方案:

    问题用例:(请参阅相关图片以获取用例参考)

    1. 目前 Tab1(位于左侧 TabPane 中)正在影响显示。
    2. 用户单击 Tab4(位于右侧 TabPane 中)。

    上述用例的问题是Tab1 和Tab4 都是它们各自的TabPanes 当前选择的Tab。因此,没有 Tab 的 isSelected 布尔值发生变化,并且它们的 onSelectionChanged EventHandler 不会被触发。

    解决办法:

    1. 设置对 Tab 的全局引用,该引用指向影响 TextArea 显示的当前 Tab。
    2. 对于每个选项卡,在两个选项卡窗格中,设置一个 onSelectionChanged 事件处理程序,它首先检查此选项卡是否成为选定选项卡或只是失去选择。
      1. 如果它刚刚成为选定的选项卡
        1. 将全局引用 Tab 设置为指向自身
        2. 根据其内容更新 TextArea 显示
      2. 如果不是选中的选项卡
        1. 什么都不做
    3. 在两个 TabPanes 上设置 OnMouseClicked EventHandler
      1. 如果全局引用 Tab 不包含在此 TabPane 中
        1. 将全局引用 Tab 设置为指向此 TabPane 的当前选中的 Tab
        2. 根据此 TabPane 当前选择的 Tab 的内容更新 TextArea 显示
      2. 如果全局引用 Tab 包含在此 TabPane 中,则什么也不做。选项卡上的 onSelectionChanged EventHandler 本身已经正确更新了 TextArea 显示

    如果有人需要更多解释或希望从该算法的编码示例实现中受益,请留言询问,我会尽快为您整理一份。

    【讨论】:

      【解决方案3】:

      我使用 FXML onSelectionChange 方法实现了一个简单的解决方案,如下所示。

      首先,我认为整个窗格只有一个控制器,因此无论您在哪里使用或使用多少个选项卡都没有关系。

      对于每个选项卡,在 FXML(可以编码)上,我添加了一个 onSelectionChanged 侦听器方法。问题是,在任何选项卡选择之后,JavaFX 都会通知两个涉及的选项卡(按此顺序):新选择的选项卡和先前选择的选项卡。所以,我只是放了一个布尔变量来标记这是第一次还是第二次调用。

      注意:请注意,如果此通知政策在未来发生变化,此解决方案可能会有风险。

      我的控制器代码的一部分:

      private boolean tabSelection = false;
      
      @FXML void reportsTabSelected(Event e) {
          if (checkTab()) {
              System.out.println("Reports Tab is Now Selected");
          }
      }
      @FXML void configTabSelected(Event e) {
          if (checkTab()) {
              System.out.println("Configs Tab is Now Selected");
          }
      }
      
      private boolean checkTab() {
          tabSelection = !tabSelection;
          return tabSelection;
      }
      

      部分选项卡 FXML:

      <Tab text="REPORTS" fx:id="reportsTab" onSelectionChanged="#reportsTabSelected">
      </Tab>
      <Tab text="CONFIGURATIONS" fx:id="configurationsTab" onSelectionChanged="#configTabSelected">
      </Tab>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-06
        • 1970-01-01
        • 2014-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-16
        • 1970-01-01
        相关资源
        最近更新 更多