5
\$\begingroup\$

I am currently working on a course project and have been assigned to write a GUI. I've written it and it's about 2000 lines of code. It will be bigger when I add the SQL codes and new panels. So, I've successfully divided it into different classes for each screen. My question is: how do I improve that solution? Here is the first shape of code. I'll just write a small part of code for better clarity.

        /**
        *When the program starts, first I call passScreen. GUI class extends the JFrame by the way.
        */
 public class GUI extends JFrame{
            public GUI() {    
                    passScreen();
                    setSize(700,700);
                    setResizable(true);
                    setTitle("KARGO");
                    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    setLocationRelativeTo(null);
                }
            /**
             *When a user clicks login button, I simply making panelG invisible, calling client method and 
             *then removing it. I am not writing user_id and password control codes for the sake of clarity
             */
            private void passScreen(){
                        final JPanel panelG = new JPanel();
                        ...
                        ...
                        JButton login = new JButton("Login");
                        login.addActionListener(new ActionListener){
                               panelG.setVisible(false);
                               client();
                               getContentPane().remove(panelG);
                               panelG.removeAll();

                        }};

                        setContentPane(panelG);
    }
             /**
             *When the user clicks exit, I make the current pane invisible, calling
             *passScreen method.
             */
             private void client(){
                     final JPanel panelG = new JPanel();
                     ...
                     ...  
                     JButton exit = new JButton();
                     exit.addActionListener(new ActionListener){
                               panelG.setVisible(false);
                               passScreen();
                               getContentPane().remove(panelG);
                               panelG.removeAll();

                        }};
                     setContentPane(panelG);
             }
}

Then, I put passScreen() and client() methods to separate classes and modified GUI and the methods slightly:

GUI:

public class GUI extends JFrame{ 

    public GUI() {    
        new PassScreen().passScreen(this);// I sent current frame object to passScreen method
        setSize(700,700);
        setResizable(true);
        setTitle("KARGO");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
    }
}

PassScreen:

public class PassScreen{
   /**
    *I made changes and set the content pane via JFrame object coming from GUI class.
   */
    public void passScreen(final JFrame g){
        final JPanel panelG = new JPanel();
        ...
        ...
        JButton login = new JButton("Login");
        login.addActionListener(new ActionListener){
            panelG.setVisible(false);
            new Client().client(g);// Sending current frame object to Client class-->
            g.getContentPane().remove(panelG);//for changing screen
            panelG.removeAll();

        }};

        g.setContentPane(panelG);
    }
}         

Client:

public class Client{

    public void client(final JFrame g){

        final JPanel panelG = new JPanel();
        ...
        ...  
        JButton exit = new JButton();
        exit.addActionListener(new ActionListener){
            panelG.setVisible(false);
            new PassScreen().passScreen(g);
            g.getContentPane().remove(panelG);
            panelG.removeAll();

        }};
        g.setContentPane(panelG);
    }
}

I don't like it because, for access, I have to make passScreen and client methods public. Is there any better way of separating GUI parts?

\$\endgroup\$
3
\$\begingroup\$

I have to disagree with rolfl's approach here. I do not think it is necessary to extend the classes. I have brought this issue up in an answer here.

I would say that your first version of code is better than the second version. What you are doing in your new code is that you are creating new Client() and then directly calling a method on that object (Client isn't the only example here).

Instead, you could create an utility method anywhere that either can give you a JPanel without actually adding it to the JFrame (in my opinion, this is better, it should be up to the caller to determine what to do with the returned object) or a method can work like you are using it now (both creating and adding it - although I do not recommend this). You don't need to extend any classes for this (or create one class for each utility method, which is essentially what you have done). These utility method does not need to be public, and they can all be placed within the same class!

Here is an example (since I do not know all your code, this is similar to the way you used it).

Because you say that you want to avoid having methods public, and also you want to avoid having everything in the same class, you can create a MyComponents class where you can put static methods.

public class MyComponents {
    // using default visibility so that it is only visible to the same package
    static void createClientPanel(final JFrame g){

        final JPanel panelG = new JPanel();
        ...
        ...  
        JButton exit = new JButton();
        exit.addActionListener(new ActionListener){
            panelG.setVisible(false);
            new PassScreen().passScreen(g);
            g.getContentPane().remove(panelG);
            panelG.removeAll();

        }};
        g.setContentPane(panelG);
    }
}

Now you just need to call this method, so new Client().client(g); could be changed to MyComponents.createClientPanel(g);

I do think you should apply this on your classes so that in the end, the GUI class and this MyComponents class is all that you have left.

\$\endgroup\$
  • \$\begingroup\$ thanks firstly, should createClientPanel return panelG object or is there a syntax mistake ? \$\endgroup\$ – nihirus Nov 29 '13 at 17:53
  • \$\begingroup\$ @nihirus Sorry, my mistake. I do think returning the panelG object would be better, and use g.setContentPane(MyComponents.createClientPanel()); - this is the more flexible approach. I think you should try to avoid passing your JFrame to these utility methods entirely. Try to make your methods that create components independent from the rest of your code (if possible). \$\endgroup\$ – Simon Forsberg Nov 29 '13 at 17:57
  • \$\begingroup\$ Hmm it seems its better to use your first approach. if I made the method static, have to define all class variables static.In addition, where should I use g frame object if I dont take it as a parameter? \$\endgroup\$ – nihirus Nov 29 '13 at 18:18
  • \$\begingroup\$ @nihirus Yes, static class variables is a good thing to avoid. How many class variables do you have? (And which ones?) \$\endgroup\$ – Simon Forsberg Nov 29 '13 at 18:22
  • \$\begingroup\$ Actually, all buttons,labels etc. but I can define it in the method. I defined as a class variable to see them(buttons,labels) easily and modify them without going through the whole code. Also, maybe you miss out my edit, where to define and use g frame object(g.setContentPane(MyComponents....)) if I don't take it as a parameter? \$\endgroup\$ – nihirus Nov 29 '13 at 18:28
1
\$\begingroup\$

Typically with Swing (and other GUI) applications the way to do it is to make your smaller class extend the component you are working on. For example, your PassScreen class should rather be something like:

class PassPanel extends JPanel {
    public PassPanel(....) {
        // set up all your pass panel sub-components.....
    }
} 

then in your calling class you can:

....
PassPanel passpane = new PassPanel(...);
....

There is a lot of code-simplicity that can be gained by extending the component rather than creating a seperate instance of it... for example, the complicated internal action-listener setVisible(false) becomes passpane.setVisible(false), and you can still create your own methods on the child classes that do 'compound' operations, like accept, and validate the password.

EDIT: to extend my answer, and to show you real examples of what I mean, consider the examples in the Swing tutorials...

\$\endgroup\$
  • \$\begingroup\$ cant upvote you because of low rating, thank you for your answer \$\endgroup\$ – nihirus Nov 29 '13 at 17:29
  • \$\begingroup\$ The examples you linked don't extend JFrame though, which the OP already has done. This means that basically they still have only one class for all the GUI functionality. \$\endgroup\$ – Simon Forsberg Nov 29 '13 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.