0

I want do design a simple login format and in order to do so I want two JTextFields for Username/Password and a Login Button. The Login button is display as expected but when I add the JTextField, nothing shows in my JFrame. Would be nice if someone could help a beginner out...

Here's my code (I know it's ugly but this is just a "code sketch"):

package bucketlistpackage;

import java.awt.Container;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GameFrame extends JFrame {

    public GameFrame(String title) {

        super(title);               //sets title of frame

        startFrame();               //sets details of main frame        

        final Container logincont = getContentPane();       //creates content pane

        JFrame loginframe = new JFrame();

        usernameField(loginframe);

        loginButton(loginframe);

        logincont.add(loginframe);

    }


    private void usernameField(JFrame loginframe) {

        JTextField usernameF = new JTextField("Username", 1);   

        usernameF.setBounds(50, 50, 50, 20);

        loginframe.add(usernameF);

        usernameF.setVisible(true);

    }


    private void startFrame() {         

        this.setSize(1000, 1000);

        this.setVisible(true);

    }


    private void loginButton(Container cont) {

        JButton loginB = new loginButton();

        loginB.setSize(300, 150);

        loginB.setText("Login");

        cont.add(loginB);

    }
}

1 Answers1

0

The problem lies on how you are adding component to one another in your case.

You are adding a JFrame to a Container, when in all case it should be the other way around.

The other problem is that you are not using Layouts to manage the components positions on the JFrame.

Another problem as well is that you are not refreshing the windows after adding all the stuff on it.

A bit of a resume on how Java works with native UIs: Java creates a new thread for the UI. So if you open the debugger you will see AWT threads as well as the main threads and others. This means that you have to manage this in a correct way, because after the application starts SWING and the functions you determine for reactions will lay the ground on how it will behave. Your main thread will die, but the visual threads will keep active.

If you are just starting to program I would encourage you to practice a bit more native java language before moving to SWING or AWT. This libraries can be really painful and tricky to use.

The other thing is SWING library follows a hierarchy for the components: JFrame > JPanels > Components

In your code you have already worked with all of them but in a disorganized way. JFrame is the main application window, where the graphics will be displayed (can also be a Canvas or whatever class you want to use for that matter). JPanels are organizers, you can use different layouts to organize whatever is inside it. And finally the Components are well... everything! A component can be a JTextField, but it can also be a JPanel, or JButton.

The idea with SWING is to create multiple Panels and organize the end components inside them, using the help of the different layouts to see whats the best approach to make them attractive in many different window sizes.

Finally, if you are using Eclipse, there is a plugin called WindowBuilder which might help you. I don't recommend you using it if you are very new to Java since it will make you depend a lot on it instead of learning how to actually code with SWING.

Hope this helps!!!

Btw, to fix the code above I would do something like this:

public GameFrame(String title) {
    super(title);               //sets title of frame
    startFrame();               //sets details of main frame
    final Container logincont = getContentPane();       //creates content pane
    logincont.setLayout(new BorderLayout());
    usernameField(logincont, BorderLayout.NORTH);
    loginButton(logincont, BorderLayout.CENTER);
    this.revalidate();
    this.repaint();
}

private void usernameField(Container loginframe, String direction) {
    JTextField usernameF = new JTextField("Username");
    // usernameF.setBounds(50, 50, 50, 20);
    loginframe.add(usernameF, direction);
    usernameF.setVisible(true);
}

private void startFrame() {
    this.setSize(1000, 1000);
    this.setVisible(true);
}

private void loginButton(Container cont, String direction) {
    JButton loginB = new JButton();
    loginB.setSize(300, 150);
    loginB.setText("Login");
    cont.add(loginB, direction);
}
  • I would `pack()` the frame rather than `setSize(...)` of it. Also you're making the frame visible before adding all the components to it. `usernameF` there's no need to make it visible. If you have `this.setVisible(true)` after you've added all items to the `JFrame`, there's no need to `revalidate()` and `repaint()`. I would also not recommend extending a `JFrame` but creating an instance of it. See [this question](https://stackoverflow.com/questions/22003802/extends-jframe-vs-creating-it-inside-the-program) – Frakcool Sep 16 '19 at 18:54