禁用JFileChooser中的打开按钮?

4
我扩展了一个JFileChooser,并覆盖了approveSelection方法,因此当用户选择无效目录然后单击打开按钮时,将显示一个JOptionPane中的错误消息。但我想让我的JFileChooser更加用户友好,并使打开按钮在用户单击无效目录后变为禁用状态,当用户单击有效目录后重新启用。是否可能进一步定制我的JFileChooser,并访问打开按钮,以便可以相应地更改按钮的状态(可能是通过监听器来监听目录选择)?
public class MyFileChooser extends JFileChooser {

  private final JFrame mainFrame;

  public MyFileChooser(JFrame mainFrame) {
    this.mainFrame = mainFrame;
    setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
  }

  @Override
  public void approveSelection() {
    if (/* directory is valid */) {
      super.approveSelection();
      return;
    }
    JOptionPane.showMessageDialog(mainFrame, "Invalid directory", "Error", JOptionPane.ERROR_MESSAGE);
  }

}

2
为什么不使用FileFilter呢?这甚至不会让用户选择无效的目录。请参见http://docs.oracle.com/javase/6/docs/api/javax/swing/JFileChooser.html#setFileFilter%28javax.swing.filechooser.FileFilter%29。 - JB Nizet
3个回答

11
当检测到文件/目录的选择更改时,调用chooser.setControlButtonsAreShown(false)可以隐藏接受/取消按钮:

您可以通过调用chooser.setControlButtonsAreShown(false)来隐藏接受/取消按钮,在检测到文件/目录的选择更改时:

myChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
myChooser.addPropertyChangeListener(new PropertyChangeListener() {
  public void propertyChange(PropertyChangeEvent evt) {
        if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
            File file = (File) evt.getNewValue();
            if (file != null && file.isFile()) {    // your condition                  
                myChooser.setControlButtonsAreShown(false);
            }
            else if ( file != null ) {
                System.out.println(file.getName());
                myChooser.setControlButtonsAreShown(true);
            }
        }

        myChooser.repaint();
    }
});

但这可能会让用户感到困惑,最好制作自定义的FileFilter,并仅显示您需要的文件/目录:

public static class MyDirectoryFilter extends javax.swing.filechooser.FileFilter {
  @Override
  public boolean accept( File file ) {
    return file.isDirectory() && customeCondition(file) ;
  }

  @Override
  public String getDescription() {
    return "this only my custom dir";
  }
}

myChooser.setFileFilter( new MyDirectoryFilter () );

编辑:我找到了一种方法来禁用该按钮,通过迭代组件并获取打开按钮的句柄:

http://www.coderanch.com/t/468663/GUI/java/Disabling-Enabling-level-button-folder

示例:

myChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
myChooser.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
    if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
           File file = (File) evt.getNewValue();

           if (file != null && file.isFile()) { 
                setOpenButtonState(myChooser, false);

           }
           else if ( file != null ) {
                setOpenButtonState(myChooser, true);
                System.out.println(file.getName());
           }
        }

        myChooser.repaint();
    }
});

public static void setOpenButtonState(Container c, boolean flag) {
    int len = c.getComponentCount();
    for (int i = 0; i < len; i++) {
      Component comp = c.getComponent(i);

      if (comp instanceof JButton) {
        JButton b = (JButton) comp;

        if ( "Open".equals(b.getText()) ) {
            b.setEnabled(flag);
        }

      } else if (comp instanceof Container) {
          setOpenButtonState((Container) comp, flag);
      }
    }     
}

3
еҘҪзҡ„дҫӢеӯҗпјҢдҪҶдёҚиҰҒдҪҝз”Ёb.getText().equals("Open")пјҢиҖҢжҳҜдҪҝз”Ёb.getText().equals(chooser.getApproveButtonText())жқҘж”ҜжҢҒеӣҪйҷ…еҢ–гҖӮ - Stephan

1
如Wajdy Essam已经回答,您通常可以使用以下方法隐藏/显示控制按钮:

javax.swing.JFileChooser#setControlButtonsAreShown(boolean)

但是这种方法并不适用于所有的外观,至少不适用于我正在使用的外观。

我写了一个快速解决方案,它在大多数情况下都能起作用。

此外,您可以完全访问FileChooser的取消和批准按钮。

public class JFileChooserTest extends JFileChooser {

private JButton approveButton, cancelButton;

public JFileChooserTest() {
    // Lookup the Buttons
    if (approveButton == null) {
        approveButton = lookupButton(JFileChooserTest.this, getUI().getApproveButtonText(this));
    }
    if (cancelButton == null) {
        cancelButton = lookupButton(JFileChooserTest.this, UIManager.getString("FileChooser.cancelButtonText"));
    }

    setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

    //Creating the Listener
    PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            //Do action only if the selected file changed
            if (evt.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
                File newFile = (File) evt.getNewValue();
                //Validate the new File
                boolean validate = validateFile(newFile);

                //Enable/Disable the buttons
                if (approveButton != null) {
                    approveButton.setEnabled(validate);
                }
                if (cancelButton != null) {
                    cancelButton.setEnabled(validate);
                }
            }
        }
    };

    //Adding the listeners
    addPropertyChangeListener(SELECTED_FILE_CHANGED_PROPERTY, propertyChangeListener);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                JFileChooserTest test = new JFileChooserTest();
                test.showOpenDialog(null);
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                Logger.getLogger(JFileChooserTest.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    });

}

/**
 * Simple validation method; only for testing purpose
 *
 * @param f
 * @return
 */
private boolean validateFile(File f) {
    return f != null && !f.getName().startsWith("A");
}

/**
 * Looksup the first JButton in the specific Container (and sub-containers)
 * with the given text.
 *
 * @param c
 * @param text
 * @return
 */
private JButton lookupButton(Container c, String text) {
    JButton temp = null;
    for (Component comp : c.getComponents()) {
        if (comp == null) {
            continue;
        }
        if (comp instanceof JButton && (temp = (JButton) comp).getText() != null && temp.getText().equals(text)) {
            return temp;
        } else if (comp instanceof Container) {
            if ((temp = lookupButton((Container) comp, text)) != null) {
                return temp;
            }
        }
    }
    return temp;
}
}

我还建议使用javax.swing.filechooser.FileFilter来验证所选文件,而不是覆盖approveSelection()


1
禁用JFileChooser中的“打开”按钮?更好的方法是安装一个自定义的{{link1:FileSystemView}},它可以隐藏无效目录。请查看如何覆盖{{link2:isHiddenFile(File)}}。

2
我有同样的需求,但是对我来说,我只需要允许选择符合特定条件的目录。我不能使用文件过滤器,因为如果这样做,用户将无法在文件系统上导航到任何地方!我需要允许完整的目录导航,但只允许选择符合我的条件的目录,即点击“打开”按钮。有什么想法吗? - Matthew Wise
@MatthewWise FileSystemView 可以显示文件和目录。 - Andrew Thompson
1
是的,但我需要显示所有目录以允许完全导航,但只有其中某些目录可以通过单击“打开”按钮进行选择。我的解决方法是覆盖approveSelection(),将标准逻辑放在这里,并在所选目录不满足标准时显示错误消息。希望这样更清楚地说明我需要实现的内容... - Matthew Wise

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