禁止在JTabbedPane中更改选项卡

6

我希望防止用户在当前选项卡无效时更改选项卡。所以当他点击选项卡时,我想检查当前选项卡是否“有效”,如果不是,则留在当前选项卡上。我尝试使用VetoableChangeListener但失败了,代码从未进入vetoableChange方法:

jTabbedPane.addVetoableChangeListener(new VetoableChangeListener() {

  @Override
  public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
    if (!isCurrentTabValid()) {
      throw new PropertyVetoException("test", evt);
    }
  }
});

我应该如何正确地做这件事?

谢谢!

3个回答

16

VetoableChangeListener只有在注册了它的类触发vetoable属性更改时才有用。JComponents及其子类中的大多数(全部?从未遇到过)属性都不能否决。此外,选择由SingleSelectionModel处理,而不是组件本身。

该模型是支持vetoable更改的钩子

  • 实现一个自定义模型,在选择更改时触发vetoablePropertyChange
  • 如果没有侦听器反对,则执行更改,否则不执行任何操作
  • 将自定义模型设置为tabbedPane
  • 实现包含验证逻辑的VetoablePropertyChangeListener
  • 将vetoableListener注册到模型上

在代码中,类似于以下内容:

public static class VetoableSingleSelectionModel extends
        DefaultSingleSelectionModel {

    private VetoableChangeSupport vetoableChangeSupport;

    @Override
    public void setSelectedIndex(int index) {
        if (getSelectedIndex() == index)
            return;
        try {
            fireVetoableChange(getSelectedIndex(), index);
        } catch (PropertyVetoException e) {
            return;
        }
        super.setSelectedIndex(index);
    }

    private void fireVetoableChange(int oldSelectionIndex,
            int newSelectionIndex) throws PropertyVetoException {
        if (!isVetoable())
            return;
        vetoableChangeSupport.fireVetoableChange("selectedIndex",
                oldSelectionIndex, newSelectionIndex);

    }

    private boolean isVetoable() {
        if (vetoableChangeSupport == null)
            return false;
        return vetoableChangeSupport.hasListeners(null);
    }

    public void addVetoableChangeListener(VetoableChangeListener l) {
        if (vetoableChangeSupport == null) {
            vetoableChangeSupport = new VetoableChangeSupport(this);
        }
        vetoableChangeSupport.addVetoableChangeListener(l);
    }

    public void removeVetoableChangeListener(VetoableChangeListener l) {
        if (vetoableChangeSupport == null)
            return;
        vetoableChangeSupport.removeVetoableChangeListener(l);
    }

}

// usage
JTabbedPane pane = new JTabbedPane();
VetoableSingleSelectionModel model = new VetoableSingleSelectionModel();
VetoableChangeListener validator = new VetoableChangeListener() {

    @Override
    public void vetoableChange(PropertyChangeEvent evt)
            throws PropertyVetoException {
        int oldSelection = (int) evt.getOldValue();
        if ((oldSelection == -1) || isValidTab(oldSelection)) return;

        throw new PropertyVetoException("change not valid", evt);

    }

    private boolean isValidTab(int oldSelection) {
        // implement your validation logic here
        return false;
    }
};
model.addVetoableChangeListener(validator);
pane.setModel(model);
pane.addTab("one", new JLabel("here we are and stay"));
pane.addTab("other", new JLabel("poor me, never shown"));

这对于选项卡切换非常有效,但是如何否决选项卡关闭?vetoableChange在选项卡关闭后和前一个选项卡被选择时被调用。我搜索了一下关于vetoableClose的信息,但没有结果。 - Alex Burdusel
请提供一个包含最小可重现代码的问题。 - kleopatra
没问题,我解决了。我在每个选项卡上添加了一个按钮组件来关闭它们。它调用了 JTabbedPane.remove(tabIndex) 方法。我设法解决了这个问题。在关闭当前选项卡之前,我会选择前一个选项卡,这样就会调用 valueChanged 方法。 - Alex Burdusel

1

听起来你想先禁用选项卡。然后当当前页面有效时启用选项卡。同时,你可能需要考虑使用 CardLayout 代替选项卡。然后在当前页面有效时使用“下一步”或“继续”按钮。


1
禁用第二个选项卡可能对用户来说不太直观。但是卡片布局可以胜任此工作。不要忘记添加一些提示,让用户知道为什么无法继续到下一个屏幕。 - svz
我不想禁用任何选项卡。这意味着我需要在用户执行每个操作后检查选项卡是否有效,这是不可能的。 - Nanocom

0

看起来vetoableChange是java.beans包的一部分。尝试添加javax.swing.event.ChangeListener

bodyTabbedPane.addChangeListener(new javax.swing.event.ChangeListener() {
        public void stateChanged(javax.swing.event.ChangeEvent evt) {
            bodyTabbedPaneStateChanged(evt);
        }
    });


private void bodyTabbedPaneStateChanged(javax.swing.event.ChangeEvent evt) {
    if (!isCurrentTabValid()) {             
         throw new PropertyVetoException("test", evt);           
     }
}

4
我猜你没有尝试过那个方法;-) 在选择变化通知的那一刻,选择已经被改变,所以你唯一能做的就是撤销更改 - 但宝宝已经掉进井里死了... - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接