2

I want to create a new window that contains JTable as a result of pressing a JMenuItem, i tried creating a new class inside of the action listener, not sure how correct that is. Anyways it doesn't work, please advise.

...

help.add(currencyTable);
...

        //action listener for the currency table JMenuItem button

        currencyTable.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                class currencyJTableClass extends JFrame
                {
                    JTable currencyTable;

                    public currencyJTableClass()
                    {
                        setLayout(new FlowLayout());
                        String[] headLine = {"x","y","z"} ;
                        String [][] currencyData =
                                {
                                        {
                                          "a","b","c"
                                        },
                                        {
                                          "d","e","f"
                                        },
                                };
                        currencyJTable = new JTable(currencyData,headLine);
                    }


                } 
Roman C
  • 49,761
  • 33
  • 66
  • 176
Alex
  • 1,982
  • 4
  • 37
  • 70
  • This depends, do you want multiple windows open or not (ie, when the clicks the menu item, should it dispose of the any existing "child" windows or doesn't it care) – MadProgrammer Jan 11 '13 at 23:46
  • I have the main `JFrame` window with several `JMenuItem`s in it. I want to create another `JFrame` window that include a `JTable` in it (without closing or affecting other windows). thanks! – Alex Jan 12 '13 at 00:31

2 Answers2

2

Don't create a JFrame or JTable in your ActionListener. Rather, create a single JFrame with a JTable at startup, along with a TableModel. Then, in your ActionListener, update the model with the data you wish to display.

When starting to learn how to use table models start with the DefaultTableModel since it supports dynamic changes to the model by using addRow and removeRow.

Here is an example

Note: If you do need to create a separate window to display data, some possibilities are:

  • Use a modal JDialog — draws focus of user to content in window
  • Use CardLayout instead — allows easy display of many components.
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • Thanks for the answer. Why should not i create a new separated `JFrame`/`JTable` in the action listener? is it a bad practice or just wrong? – Alex Jan 11 '13 at 23:00
  • 2
    See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/questions/9554636/the-use-of-multiple-jframes-good-bad-practice) – Reimeus Jan 11 '13 at 23:01
  • I cant change my whole GUI now to implement `CardLayout`, and `JDialog` will freeze the main `JFrame`, cant allow that since the user interacts the whole time with it. I understand now that creating multiple `JFrame`s is a bad practice but i have no choice right now. More possibilities please? – Alex Jan 11 '13 at 23:34
  • Consider posting a [SSCCE](http://sscce.org/). This possibly belongs in a new question. – Reimeus Jan 11 '13 at 23:39
  • *"`JDialog` will freeze the main `JFrame`"* Only if it is modal. *"I cant change my whole GUI now to implement `CardLayout`"* Fixing a bad design is typically quicker than working around the problems with the current design. – Andrew Thompson Jan 13 '13 at 08:48
2

Seen as you seem to be determined to follow this path, you have a number of options...

The hard way...

public void actionPerfomed(ActionEvent e) {

    TableModel model = //... Create the new model based on you needs
    JTable table = new JTable(model);

    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.add(new JScrollPane(table));
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

}

This would require you duplicate this code each action listener...that's a lot of code...

Slightly Easier

Create yourself a simple implementation which wrappers all the required logic into a couple of basic classes...

public class ModelPane extends JPanel {

    private JTable table;

    public ModelPane(TableModel model) {
        setLayout(new BorderLayout());
        table = new JTable(model);
        add(new JScrollPane(table));
    }

}

public class ModelFrame extends JFrame {

    public ModelFrame(TableModel model) {
        setLayout(new BorderLayout());
        add(new ModelPane(model));
        pack();
        setLocationRelativeTo(null);
    }

}

Then in you actionPerformed methods you can simple do...

public void actionPerfomed(ActionEvent e) {
    TableModel model = //... Create the new model based on you needs
    ModelFrame frame = new ModelFrame(model);
    frame.setVisible(true);
}

This centralises the core logic for display and managing the tables and data

A little better

Using the second option, you could use the Action API to generate basic actions that provide the required information to generate the models, but allows a base action class to actually determine how the actionPerformed method should work...

public abstract class AbstractModelAction extends AbstractAction {

    public abstract TableModel getModel();

    @Override
    public void actionPerformed(ActionEvent e) {
        ModelFrame frame = new ModelFrame(getModel());
        frame.setVisible(true);
    }
}

public class CurrencyModelAction extends AbstractModelAction {

    @Override
    public TableModel getModel() {
        return //... Create the new model based on you needs
    }

}

Check out How to use Actions for more information...

Conclusion

Use the method that is most flexible and provides the best reuse. I very rarely create custom JFrames, simply because I prefer to create panels as this means I can re-use them in what ever context I want, flexible and reusable ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366