1

I am developing a custom search component. When clicked on the button(search image icon) inside the text field, a table is displayed. The code is in very nascent stage so lots of things is not there.

As of now, I am stuck because I am not able to navigate the table with the arrow keys. Neither am I able to move to the next text field with "tab" key, once I select a row in the table.

The objective of the component is to select a row from the table and then with the help of the supporting methods(yet to be written) values from other labels and text fields would be defaulted while defaulting 1 st column value in the text field it is attached to.

Would really appreciate your help. Thanks !!

    package myTableCombo;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class SearchBox extends JPanel {

        private static final long serialVersionUID = 1L;
        private JTextField editor;
        private JButton arrowButton;
        private JWindow jWindow;
        private Component userComponent;

        public SearchBox() {
                super(new FlowLayout(FlowLayout.LEFT, 0, 0));
                editor = new JTextField();
                editor.setPreferredSize(new Dimension(250, 25));
                initialize();
                addListeners();
                setBorders();
        }

        private void addListeners() {
                arrowButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                                showWindow();
                        }
                });
        }

        protected void showWindow() {
                if (null != getWindowComponent()) {
                        jWindow = new JWindow();
                        jWindow.getContentPane().add(getWindowComponent());
                        jWindow.setLocation(new Point(SearchBox.this.getLocationOnScreen().x, SearchBox.this.getLocationOnScreen().y + 25));
                        jWindow.pack();
                        jWindow.setVisible(true);
                }
        }

        private Component getWindowComponent() {
                return userComponent;
        }

        public void setWindowComponent(Component component) {
                userComponent = component;
        }

        private void initialize() {
                arrowButton = new BasicArrowButton(SwingConstants.SOUTH);//In my code there is an icon here
                arrowButton.setBorder(null);
                arrowButton.setContentAreaFilled(false);
        }

        private void setBorders() {
                add(editor);
                add(arrowButton);
                setBackground(editor.getBackground());
                setBorder(editor.getBorder());
                editor.setBorder(null);
        }

        public JTextField getTextComponent() {
                return editor;
        }

        public JButton getActionButton() {
                return arrowButton;
        }

        public static void main(String args[]) {
                EventQueue.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                                createAndShowGUI();
                        }
                });
        }

        protected static void createAndShowGUI() {
                JFrame frame = new JFrame();
                JPanel panel = new JPanel();

                frame.setPreferredSize(new Dimension(500, 400));
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

                panel.add(new JLabel("Test Table Combo"));
                SearchBox searchBox = new SearchBox();
                searchBox.userComponent = searchBox.new SearchBoxTable();
                panel.add(searchBox);

                frame.getContentPane().add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
        }

        private class SearchBoxTable extends JScrollPane implements DocumentListener {

                private static final long serialVersionUID = 1L;
                private JTable table;
                private Object[] columnNames;
                private DefaultTableModel tableModel;
                private Object[][] sheetDataInString;
                private TableRowSorter<DefaultTableModel> rowSorter;

                public SearchBoxTable() {
                        columnNames = new Object[]{"Column 1", "Column 2", "Column 3", "Column 4", "Column 5", "Column 6"};
                        sheetDataInString = new Object[21][6];
                        for(int i =0; i < sheetDataInString.length; i++) {
                                for(int j = 0; j< 6; j++) {
                                        sheetDataInString[i][j] = "Row Value : " + i + ", Column Value : " + j;
                                }
                        }

                        tableModel = new DefaultTableModel(sheetDataInString, columnNames) {
                                private static final long serialVersionUID = 1L;

                                @Override
                                public boolean isCellEditable(int row, int column) {
                                        return false;
                                }
                        };
                        rowSorter = new TableRowSorter<DefaultTableModel>(tableModel);

                        table = new JTable(tableModel);
                        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                        table.setAutoCreateRowSorter(true);
                        table.setFillsViewportHeight(true);
                        table.getTableHeader().setFont(new Font(null, Font.PLAIN, 13));

                        setPreferredSize(new Dimension(500, 225));
                        setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
                        setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                        getViewport().add(table);
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                        newFilter(e);
                }

                @Override
                public void insertUpdate(DocumentEvent e) {
                        newFilter(e);
                }

                @Override
                public void removeUpdate(DocumentEvent e) {
                        newFilter(e);
                }

                /**
                 * Update the row filter regular expression from the expression/string/data in the text box.
                 * 
                 * @param documentEvent
                 */
                private void newFilter(DocumentEvent documentEvent) {
                        RowFilter<DefaultTableModel, Object> rowFilter = null;
                        Document document = documentEvent.getDocument();
                        String filterText;

                        try {
                                filterText = document.getText(0, document.getLength()).trim();
                                rowFilter = RowFilter.regexFilter("(?i)" + filterText);
                        } catch (java.util.regex.PatternSyntaxException e) {
                                return;
                        } catch (BadLocationException badLocationException) {
                                return;
                        }
                        rowSorter.setRowFilter(rowFilter);
                        table.setRowSorter(rowSorter);

                }

        }

}
dareurdream
  • 241
  • 4
  • 13
  • @AndrewThompson - Its there.. – dareurdream Dec 31 '12 at 13:35
  • 1
    sorry (flamewar) your acceting rate protect me anything, much luck and happy new year – mKorbel Dec 31 '12 at 13:35
  • @HovercraftFullOfEels - Do I need to write key released code for JTable. JTable have that by default in BasicTableUI. – dareurdream Dec 31 '12 at 13:37
  • All I have accepted your answers earlier too. Its just that I was off for a long time now due to personal problems. So have not checked for previous posts and answers. PLz help guys !! – dareurdream Dec 31 '12 at 13:38
  • *"So have not checked for previous posts and answers."* It is a good time to review [past questions](http://stackoverflow.com/users/1683873/dareurdream?tab=questions), right now. :) – Andrew Thompson Dec 31 '12 at 13:40
  • Guys, the two files are sufficient to show the probelms. As I am developing a framework, I have to take out a lot of things and simply them in two files. You can copy and run them, to see the probelm. Thanks a lot – dareurdream Dec 31 '12 at 13:40
  • did you heard about [ColumnClass](http://stackoverflow.com/search?q=user%3A714968+[jtable]+columnclass) – mKorbel Dec 31 '12 at 13:42
  • *"You can copy and run them"* You can merge them into one. Why should 2 or more people do 2 copy/pastes, when one (who is asking the question) can do the merge? – Andrew Thompson Dec 31 '12 at 13:42
  • @AndrewThompson, HovercraftFullOfEels, I think you made your point clear, no need to press it further. – Olaf Dietsche Dec 31 '12 at 13:43
  • question issue is to hold the sorting orders after filtering or not – mKorbel Dec 31 '12 at 13:44
  • You are right, a standard displayed JTable should have arrow key functionality already in it. If it's not working for you, then consider simplifying/reducing your code until you isolate the problem. That I think is the main motivation for creating an sscce -- it forces you to isolate the problem, making it easier for you to discover its source and solve it. If not, then you're still able to post smaller code volume that reproduces the problem. – Hovercraft Full Of Eels Dec 31 '12 at 13:53
  • Guys, I have looked into the previous solutions, and accepted the solutions which I have implemented in the framework. And I also ask you to please excuse for the delayed acceptance, but I was not in a situation to accept them earlier. I look forward for your continued support. Thanks all – dareurdream Dec 31 '12 at 13:55
  • @mKorbel - No am not aware of ColumnClass. I woulk look at the link now.. – dareurdream Dec 31 '12 at 13:57
  • @mKorbel - Are you talking about the getColumnClass method. As am using DefaultTableModel, will it not treat the cells as String. In this particular case, I want everything to be treated as String, so I have not overriden the method believing it will automatically send everything as String. – dareurdream Dec 31 '12 at 14:02
  • @HovercraftFullOfEels - Yes you are right, I did try to isolate and solve the problem, but my very very limited knowledge of Swing is not helping me. – dareurdream Dec 31 '12 at 14:06
  • I am wondering if it is a focus issue since focus never leaves the JTextField when the JWindow with the JTable is displayed. This is suggested by behavior and I have proven it with a FocusListener. Thus all key presses, including the arrow keys, will go to the JTextField, not the JTable. – Hovercraft Full Of Eels Dec 31 '12 at 14:09
  • @HovercraftFullOfEels - Yes you are right. What should I do then? – dareurdream Dec 31 '12 at 14:11
  • I'm not sure since you're doing things I have never done. A kludge would be to use key bindings on the text field, something I do not recommend. I would experiment for ways to get the focus to the JTable or try key bindings on the jtable. – Hovercraft Full Of Eels Dec 31 '12 at 14:13
  • @HovercraftFullOfEels - Thanks. In the meantime I would also try something different. – dareurdream Dec 31 '12 at 14:20

1 Answers1

4

do you meaning

  • use undecorated JDialog instead of JWindow, otherwise JTextComponets aren't editable

  • JDialog has better support for AlwaysOnTop and ModalityTypes (only hardcoded to the setAlwaysOnTop)

  • don't to recreate basic setting again and again, don't to recreate a popup windod, use lolac variable, remove all contents and add a new ony, define all setting for JDialog once time, see exception (The dialog is displayable.) in the case that popup is hidden and value in JTextField isn't empty

  • missed action for hide JDialog on ESC key event, hide JDialog, if is JFrame minimalized

  • missed moving with JDialog if JFrame is resized, moved over screen on another Point,

  • attach Document to the JTextField directly, not lost somwhere in to the JScrollPane definitions

  • your code missing a few good practicies, then everything is possible but not with this code (after my edit too)

  • search for JCalendar by Kay Toedter (best popup workaround as I saw for popup window)

only removed uselles methods, moved from- to, notice non_optimized_code, simple put to the recyclebin and wrote that again

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class SearchBox extends JPanel {

    private static final long serialVersionUID = 1L;
    private static JFrame frame = new JFrame();
    private JTextField editor;
    private JButton arrowButton;
    //private JToggleButton arrowButton;
    private JDialog popupWindow = new JDialog(frame);
    private Component userComponent;
    private JTable table;
    private TableRowSorter<DefaultTableModel> rowSorter;
    private Object[] columnNames;
    private DefaultTableModel tableModel;
    private Object[][] sheetDataInString;

    public SearchBox() {
        super(new FlowLayout(FlowLayout.LEFT, 0, 0));
        editor = new JTextField();
        editor.setPreferredSize(new Dimension(250, 25));
        editor.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void changedUpdate(DocumentEvent e) {
                newFilter();
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                newFilter();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                newFilter();
            }

            private void newFilter() {
                RowFilter<DefaultTableModel, Object> rowFilter = null;
                Document document = editor.getDocument();
                String filterText;
                try {
                    filterText = document.getText(0, document.getLength()).trim();
                    rowFilter = RowFilter.regexFilter("(?i)" + filterText);
                } catch (java.util.regex.PatternSyntaxException e) {
                    return;
                } catch (BadLocationException badLocationException) {
                    return;
                }
                rowSorter.setRowFilter(rowFilter);
                table.setRowSorter(rowSorter);
            }
        });
        initialize();
        addListeners();
        setBorders();
    }

    private void addListeners() {
        arrowButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (!popupWindow.isVisible()) {
                    showWindow();
                } else {
                    hideWindow();
                }
            }
        });
    }

    protected void showWindow() {
        if (null != getWindowComponent()) {
            popupWindow.getContentPane().add(getWindowComponent());
            popupWindow.setLocation(new Point(SearchBox.this.getLocationOnScreen().x, SearchBox.this.getLocationOnScreen().y + 25));
            popupWindow.setUndecorated(true);
            popupWindow.setAlwaysOnTop(true);
            popupWindow.pack();
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    popupWindow.setVisible(true);
                }
            });
        }
    }

    protected void hideWindow() {
        popupWindow.setVisible(false);
    }

    private Component getWindowComponent() {
        return userComponent;
    }

    public void setWindowComponent(Component component) {
        userComponent = component;
    }

    private void initialize() {
        arrowButton = new BasicArrowButton(SwingConstants.SOUTH);//In my code there is an icon here
        arrowButton.setBorder(null);
        arrowButton.setContentAreaFilled(false);
    }

    private void setBorders() {
        add(editor);
        add(arrowButton);
        setBackground(editor.getBackground());
        setBorder(editor.getBorder());
        editor.setBorder(null);
    }

    public JTextField getTextComponent() {
        return editor;
    }

    public JButton getActionButton() {
        return arrowButton;
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    protected static void createAndShowGUI() {
        JPanel panel = new JPanel();

        frame.setPreferredSize(new Dimension(500, 400));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        panel.add(new JLabel("Test Table Combo"));
        SearchBox searchBox = new SearchBox();
        searchBox.userComponent = searchBox.new SearchBoxTable();
        panel.add(searchBox);

        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private class SearchBoxTable extends JScrollPane {

        private static final long serialVersionUID = 1L;

        public SearchBoxTable() {
            columnNames = new Object[]{"Column 1", "Column 2", "Column 3", "Column 4", "Column 5", "Column 6"};
            sheetDataInString = new Object[21][6];
            for (int i = 0; i < sheetDataInString.length; i++) {
                for (int j = 0; j < 6; j++) {
                    sheetDataInString[i][j] = "Row Value : " + i + ", Column Value : " + j;
                }
            }

            tableModel = new DefaultTableModel(sheetDataInString, columnNames) {

                private static final long serialVersionUID = 1L;

                @Override
                public boolean isCellEditable(int row, int column) {
                    return true;
                }
            };
            rowSorter = new TableRowSorter<DefaultTableModel>(tableModel);
            table = new JTable(tableModel);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            table.setAutoCreateRowSorter(true);
            table.setFillsViewportHeight(true);
            table.getTableHeader().setFont(new Font(null, Font.PLAIN, 13));
            table.setPreferredScrollableViewportSize(table.getPreferredSize());
            setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
            setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            getViewport().add(table);
        }
    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • But I have one question. Can I not destroy the popup and create again and again? Will it not consume a lot of resources to keep holding the popup windows resources. In a single GUI if a user have 20 such components, then will it not hold lots of resources. Thanks – dareurdream Jan 01 '13 at 05:01
  • [create popup window only oce time](http://stackoverflow.com/questions/6309407/remove-top-level-container-on-runtime), use CardLayout for switching betweens views, then this idea to required to clear / set only value for JComponent in current view – mKorbel Jan 01 '13 at 07:48
  • Okie will do that for sure, as it will save the effort for creating them again and again. But how about resource consumption about them.... – dareurdream Jan 01 '13 at 08:36
  • I went through the link you provided, and what I comprehend is that simply disposing it will not release resources. So what should I do to release all resources when user moves away from one business functionality to another. Since it is a stand alone application, which is also caching at-least 15000 rows of excel data (15 columns) memory management is important for me. I have to do so as this data is mostly for dropdown, data table and lists(All static data). – dareurdream Jan 01 '13 at 08:41
  • @dareurdream by default (`15000 rows of excel data (15 columns) memory management is important for me`) no issue to hold in memory, but could be issue to filtering (searching in all rows & columns any combinations in text), first and second char typed in JTextField can causing freeze of GUI, have to apply RowFilter after 3rd chars is typed in JTextField, then number combinations are reduced – mKorbel Jan 01 '13 at 08:48
  • Filtering is done when value changes in combo boxes, table row selection and list element selection. And most of the data is saved in HashMap as key value/objects created(based on component type it would be used with). No filtering is done for dynamic data. All the data is loaded into memory when the application starts. Is that a good approach? Till date, I have no issue of performance/GUI freeze and memory but I am worried about what happens when the application has to 30000 rows(with say 30 columns) – dareurdream Jan 01 '13 at 09:35