2

I am making a program that includes a GUI. For some reason, the JButton objects that I have created are not showing up onto my JFrame when I run the program. Here is the code:

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

public class ReverseAStringMain extends JPanel {
private JButton enterButton, exitButton;
private JTextField textField;
private JPanel buttonPanel;
private JTextArea textArea;


public ReverseAStringMain(){
    JButton enterButton = new JButton("Enter");
    JButton exitButton = new JButton("Exit");
    enterButton.setPreferredSize(new Dimension(60,60));
    exitButton.setPreferredSize(new Dimension(60,60));

    ButtonListener listener = new ButtonListener();
    enterButton.addActionListener(listener);
    exitButton.addActionListener(listener);

    buttonPanel = new JPanel();
    buttonPanel.setPreferredSize(new Dimension(200,50));
    buttonPanel.setBackground(Color.black);
    buttonPanel.add(enterButton);
    buttonPanel.add(exitButton);


    textField = new JTextField();
    textField.setSize(200, 100);

    textArea = new JTextArea();
    textArea.add(textField);


    add(buttonPanel);
    add(textField);

}

//Creating a ButtonListener class that implements the ActionListener interface
private class ButtonListener implements ActionListener{
        @Override
        //Overriding the ActionPerformed method of ActionListener
        public void actionPerformed(ActionEvent action) {
            if(action.getSource()== enterButton)
                enterButton();
            if(action.getSource()== exitButton)
                System.exit(0);
        }
}       

private void enterButton() {
            // TODO Auto-generated method stub

}


public static void main (String[] args){
    JFrame frame = new JFrame("Raj's Reverse a String Program");
    frame.setBackground(Color.white);
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setSize(new Dimension(600,600));
    //frame.pack();
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(new ReverseAStringMain());



}

}

If there are any problems or improvements I can make in my code, please let me know!

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
rajwaid
  • 21
  • 1
  • 2
  • 4
    Your problem could be that you're shooting yourself in the foot by setting sizes of things. Don't set sizes or preferred sizes. Let the layout managers do this for you. And don't comment out pack. You should call it for the same reasons. – Hovercraft Full Of Eels Jan 10 '14 at 18:33
  • 1
    @HovercraftFullOfEels nonsense. you can def. set preferred sizes, I use this all the time to make the UI look pretty. Also, `pack` is not needed. You can manually size everything if you choose. – SnakeDoc Jan 10 '14 at 18:35
  • 3
    @SnakeDoc: \yep, and you can shoot yourself in the foot if you want to, it is easily possible, but not recommended. By setting preferred sizes you risk creating GUI's that don't look quite right on all systems or worse. I'm talking best practices here. Ask Jeanette/kleopatra, one of the authors of the SwingX utilities, for more details on this. – Hovercraft Full Of Eels Jan 10 '14 at 18:36
  • @HovercraftFullOfEels you are free to color inside the lines and create boring and mundane GUI's if you choose. I, on the other hand, choose to stylize my GUI's either with applying different LaF's or manually formatting buttons, etc. If you know what you are doing, then there is no risk. And, if you are going to bother with making a SWING application, you should probably learn what you are doing. – SnakeDoc Jan 10 '14 at 18:38
  • 1
    @SnakeDoc: I'm sure that they are gorgeous, but I like creating component libraries that can be used and re-used with ease and without breaking the GUI that they are being placed in. This requires extra care to "draw in the lines", but is well worth it in the long run. – Hovercraft Full Of Eels Jan 10 '14 at 18:54
  • 1
    @AndrewThompson SO... the perfect place to do a full background check of someone's programming expertise, at least thats what Andrew Thompson believes. – Tdorno Jan 10 '14 at 19:41
  • @AndrewThompson Does this not directly relate to what I said: "@SnakeDoc I was checking evidence of your [experience with Swing](http://stackoverflow.com/search?q=user%3A2161954+%5Bswing%5D). ..Just like I thought." - YOU – Tdorno Jan 10 '14 at 19:55
  • 1
    As an aside, why on Earth are you attempting to add the text field into a text area? Provide ASCII art (or an image with a simple drawing) of the GUI as it should appear in smallest size and (if resizable) with extra width/height. – Andrew Thompson Jan 10 '14 at 20:03
  • I agree -- there's no need for an ad hominem attack, and SO reputation is no true measure of a coder's abilities. Better to simply argue the merits of our arguments and the weakness of his. – Hovercraft Full Of Eels Jan 10 '14 at 20:10

4 Answers4

4

You're adding the components to your JFrame after it's visible. You should either add them to the JFrame before it's visible, or revalidate the JFrame after you add the components.

Kevin Workman
  • 41,537
  • 9
  • 68
  • 107
3

When I load your code (after making it a lot shorter in height), this is what I see:

Preferred Size

I suspect this is more along the lines of what you expect to see.

Laid Out

Here is how I did it. Look carefully at:

  • The numbers provided to the BorderLayout constructor for white space between the panels.
  • The EmptyBorder for white space around the controls.
  • The use of pack() to shrink the GUI to the natural size.
  • The use of size hints in the construction of the text field and text area.
  • The use of a second layout - commonly known as a combined, or nested, layout.

import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class ReverseAStringMain extends JPanel {
private JButton enterButton, exitButton;
private JTextField textField;
private JPanel pageTopPanel;
private JTextArea textArea;

public ReverseAStringMain(){
    super(new BorderLayout(10,10));
    setBorder(new EmptyBorder(5,15,5,15));
    JButton enterButton = new JButton("Enter");
    JButton exitButton = new JButton("Exit");

    pageTopPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    pageTopPanel.setBackground(Color.black);
    pageTopPanel.add(enterButton);
    pageTopPanel.add(exitButton);
    textField = new JTextField(5);
    pageTopPanel.add(textField);

    textArea = new JTextArea(4,40);
    add(pageTopPanel, BorderLayout.PAGE_START);
    add(textArea);  // defaults to CENTER
}

public static void main (String[] args){
    Runnable r = new Runnable() {
        public void run() {
            JFrame frame = new JFrame("XXX's Laid out Program");
            frame.setBackground(Color.white);
            frame.setResizable(false);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new ReverseAStringMain());

            frame.pack();
            frame.setVisible(true);
        }
    };
    SwingUtilities.invokeLater(r);
}
}

General Tips

Java GUIs might have to work on a number of platforms, on different screen resolutions & using different PLAFs. As such they are not conducive to exact placement of components. To organize the components for a robust GUI, instead use layout managers, or combinations of them1, along with layout padding & borders for white space2.

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
2

Generally, you want to set the frame visible After adding components

JFrame frame = new JFrame("Raj's Reverse a String Program");
frame.setBackground(Color.white);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setSize(new Dimension(600,600));
//frame.pack();
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ReverseAStringMain());
frame.setVisible(true);                                   <<------

Also, it is better practice to use .pack() insteack of .setSize(), so you had it right in the commented out //.pack()

If you wanted to set a size to the panel, you would override the getPreferredSize() like this

public Dimension getPreferredSize() {
    return new Dimension(300, 300);   // or whatever size you want
}

When you .pack(), this preferred size will be respected by the frame.


Also, not, setting the size of the JTextField won't work. What you want to do is pass it an integer value for the number of character spaces, like this

textField = new JTextField(20);

See an edited version of your program, with all the above mentioned points. One thing I also did was get rid of all your .setPreferredSizes. You will see the difference

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

public class ReverseAStringMain extends JPanel {
    private JButton enterButton, exitButton;
    private JTextField textField;
    private JPanel buttonPanel;
    private JTextArea textArea;

    public ReverseAStringMain() {
        JButton enterButton = new JButton("Enter");
        JButton exitButton = new JButton("Exit");
        //enterButton.setPreferredSize(new Dimension(60, 60));
        //exitButton.setPreferredSize(new Dimension(60, 60));

        ButtonListener listener = new ButtonListener();
        enterButton.addActionListener(listener);
        exitButton.addActionListener(listener);

        buttonPanel = new JPanel();
        //buttonPanel.setPreferredSize(new Dimension(200, 50));
        buttonPanel.setBackground(Color.black);
        buttonPanel.add(enterButton);
        buttonPanel.add(exitButton);

        textField = new JTextField(20);
        //textField.setSize(200, 100);     /// <<-----------

        textArea = new JTextArea();
        textArea.add(textField);

        add(buttonPanel);
        add(textField);

    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 600);
    }

    // Creating a ButtonListener class that implements the ActionListener
    // interface
    private class ButtonListener implements ActionListener {
        @Override
        // Overriding the ActionPerformed method of ActionListener
        public void actionPerformed(ActionEvent action) {
            if (action.getSource() == enterButton)
                enterButton();
            if (action.getSource() == exitButton)
                System.exit(0);
        }
    }

    private void enterButton() {
        // TODO Auto-generated method stub

    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Raj's Reverse a String Program");
        frame.setBackground(Color.white);
        frame.getContentPane().add(new ReverseAStringMain());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

Have a look at the Swing tutorial trail for more information on creating GUIs with Swing.

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • @nachokk Why would I edit? You comment makes no sense. – Paul Samsotha Jan 10 '14 at 19:31
  • @nachokk How would you do it without `new Dimension`? This is how I see it in _all_ the tutorials. – Paul Samsotha Jan 10 '14 at 19:46
  • 1
    creating outside the method like a member `final Dimension dim = new Dimension(400,400);` – nachokk Jan 10 '14 at 19:47
  • 1
    @nachokk Actually (making a new instance of dimension each time getPreferredSize is called) isn't a bad idea. Remember, Dimension is mutable by the caller. Passing back a single reference allows the value to changed meaning you now have rouge value which when changed will change how the component works, not what you want to happen – MadProgrammer Jan 10 '14 at 20:31
  • @MadProgrammer then better would be `new Dimension(dimension)` but it's a minor implementation detail – nachokk Jan 10 '14 at 20:36
  • @nachokk Its amounts to the same thing. You could argue that the values supplied to Dimension should be static final int...;) – MadProgrammer Jan 10 '14 at 20:40
0

Try to add the buttonPanel to a Container, like this. And extend JFrame instead

 Container contentpane = getContentPane();

 contentPane.add(buttonPanel);
Björn Hallström
  • 3,775
  • 9
  • 39
  • 50