Vasiliy Sokolov
Vasiliy Sokolov

Reputation: 15

How to Edit JTextField Background in JFileChooser for File/Folder Name Editing

enter image description hereenter image description here

I'm working with a Java Swing application and facing a challenge with customizing the JFileChooser component. Specifically, I need to change the background color of the JTextField used for editing file or folder names within the JFileChooser.

The file and folder list in JFileChooser is represented by a JList, which, as far as I know, does not provide a direct method to access or modify the cell editor.

I attempted to override the getListCellRendererComponent() method of DefaultListCellRenderer to achieve this, but this approach does not grant me access to the JTextField component.

Is there a way to customize the JTextField within JFileChooser for editing file or folder names, specifically to change its background color?

Upvotes: 0

Views: 93

Answers (3)

Vasiliy Sokolov
Vasiliy Sokolov

Reputation: 15

Also I find out alternative solution.

public static void main(String[] args) {
    JFileChooser chooser = new JFileChooser();
    
    UIManager.put("TextField.selectionBackground", Color.YELLOW);
    UIManager.put("TextField.background", Color.GRAY);
    UIManager.put("TextField.foreground", Color.BLACK);
    
    chooser.showOpenDialog(null);
}

Upvotes: 0

camickr
camickr

Reputation: 324078

You can add a ContainerListener to the JList of the JFileChooser to be notified when the text field is added to the JList to edit the file name:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class FileChooserEditField
{
    private static void createAndShowUI()
    {
        JFileChooser  fileChooser = new JFileChooser(".");

        //  Access the JList and add a ContainerListener to the list

        JList list = SwingUtils.getDescendantsOfType(JList.class, fileChooser).get(0);

        list.addContainerListener( new ContainerAdapter()
        {
            @Override
            public void componentAdded(ContainerEvent e)
            {
                Component c = e.getChild();
                c.setBackground( Color.YELLOW );
            }
        });

        fileChooser.showOpenDialog(null);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(() -> createAndShowUI());
    }
}

This solution uses the Swing Utils class to search the file chooser for the JList component.

Upvotes: 1

Michael
Michael

Reputation: 711

The JTextField in question is editCell. You could obtain it via reflection, however I don't think this is a good idea.

Here's a rough prototype (currently only the second selection sets the background correctly):

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileSystemView;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;

public class Demo {

    private Demo() {
        JFrame jframe = new JFrame("Test");
        JButton button = new JButton("Click me");
        final JFileChooser fc = new JFileChooser();

        fc.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                Object filepane = fc.getComponent(2);
                try {
                    Field field = filepane.getClass().getDeclaredField("editCell");
                    field.setAccessible(true);
                    JTextField textfield = (JTextField) field.get(filepane);
                    if (textfield != null) {
                        textfield.setBackground(Color.yellow);
                    }
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int returnVal = fc.showOpenDialog((Component) e.getSource());
            }
        });

        jframe.add(button, BorderLayout.CENTER);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.pack();
        jframe.setSize(400, 300);
        jframe.setVisible(true);
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Demo();
            }
        });
    }

}

If you are using an SDK greater than Java 9, you also need to make packages from sun.swing.* available in your run configuration:

--add-opens=java.desktop/sun.swing=ALL-UNNAMED

Upvotes: 0

Related Questions