JTextField appears in 2 locations when created inside paintComponent() - java

I am creating a minesweeper game, and what I want to do is to have a JTextField where the user inputs his name in order for his score to be saved in a file.
My problem is that when I create a JTextField and add it to my Jpanel it appears in 2 locations. Here is an image of what is happening
(https://i.imgur.com/Ao8dRo1.jpg)
This is my code over-simplified. I believe that I don't properly understand something about how the mechanism of the GUI works.
GUI.java
public class GUI extends JFrame {
//..
//some variables here
//...
public GUI() {
this.setTitle("Minesweeper Game");
this.setSize(WIDTH, HEIGHT);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
this.setLayout(null);
//This method does not involve any drawing, it only places data in some arrays that I later use in paintComponent() to draw stuff accordingly to what the data is
setMinefield();
Board board = new Board();
this.setContentPane(board);
Click click = new Click();
this.addMouseListener(click);
}
public class Board extends JPanel {
public void paintComponent (Graphics g) {
//...
//Drawing tiles, smiley, counters
//...
//And now I draw the area for the JTextField, and I also create it and add it in the Jpanel
JTextField textField = new JTextField();
textField.setFont(new Font("Tahoma", Font.PLAIN, 35));
textField.setBounds(290, 80, 135, 40); //<-- This correctly places the textField where I want. The second textField seems to appear in the exact center of the X axis of my window
add(textField); //<-- Adding the textField to the Jpanel
} //End of paintComponent()
}//End of Board class
}//End of GUI class
Main.java
public class Main implements Runnable {
GUI gui = new GUI();
public static void main(String[] args) {
new Thread (new Main()).start();
}
#Override
public void run() {
while (true) {
gui.repaint();
}
}
}

I think the problem is that you have overridden paintComponent in your Board class. This method gets called every time the component needs to be drawn so a new text field will be added each time.
It would be better to add the text field in the constructor for your board class.

I use the command textField.setBounds(290, 80, 135, 40); to place it where I want but it doesn't work. Why could this happen?
Swing was designed to used with layout managers. The default layout manager for a JPanel is the FlowLayout. The FlowLayout will ignore the setBounds(...) statement and set the size/location of the text field based on the rules of the FlowLayout.
So don't attempt to use a null layout and don't use setBounds(). Instead let the layout manager do its job.
Also, you should be adding the components to the frame BEFORE you make the frame visible.
I would suggest your code should be something like:
JTextField textField = new JTextField(10);
JPanel top = new JPanel();
top.add( textField );
Board board = new Board();
add(top, BorderLayout.PAGE_START);
add(board, BorderLayout.CENTER);
setResizable( false );
pack();
setVisible( true );
The Board class should override the getPreferredSize() method of the Board to return your desired size so that the pack() method works properly.
The default layout manager for a JFrame is the BorderLayout. So, now the top part of the frame will contain the text field centered and the main part of the frame will contain your Board class. Read the section from the Swing tutorial on How to Use BorderLayout to understand how the above code works.
Also, the MouseListener should be added to the Board, not the JFrame.

Related

Why can I not edit the location of my JButton?

Code:
public class launcher implements ActionListener {
private static JFrame window;
private static JPanel panel;
private JButton createPassword;
private JButton seePassword;
public launcher() {
window = new JFrame();
panel = new JPanel();
window.setTitle("Password Vault");
window.setSize(400, 260);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setResizable(false);
window.setVisible(true);
window.getContentPane().add(panel); // Adds panel to JFrame
createPassword = new JButton("Create Password");
createPassword.setBounds(20, 100, 150, 100);
createPassword.addActionListener(this);
seePassword = new JButton("View Password");
seePassword.setLocation(20, 50);
seePassword.addActionListener(this);
panel.add(createPassword);
panel.add(seePassword);
}
public static void main(String[] args) {
new launcher();
}
Why can I not change the location of my JButtons? I have tried the setBounds and setLocation function but my buttons still stay on the top middle part of the JFrame window. I have also tried declaring my buttons inside the launcher() method and declaring them as a static variable.
You should NOT attempt to set the size/location of your buttons.
Swing was designed to be used with layout managers. The layout manager will set the size/location of the button based on the rules of the layout manager.
The default layout manager for a JPanel is the FlowLayout, which is why you see the button centered.
If you want to position the buttons differently, then you need to change the layout manager.
Read the section from the Swing tutorial on Layout Managers for more information and examples.
It looks like you want the buttons displayed vertically, so maybe a BoxLayout or GridLayout can be used depending on your exact requirement.
Other issues with your code:
Class names should start with an upper case character
There is no need to use static variables. That is not how the static keyword should be used
Components should be added to the frame BEFORE the frame is made visible.
You should be invoking pack() on the frame, BEFORE invoking setVisible(...) so the components can be displayed at their preferred size.
While you really shouldn't change the place of your components without a layout manager, there is a way. If you put this line of code into your code, it should work with setBounds:
window.setLayout(null);

How do you organize objects in a flow layout?

I would like to have a jframe with the text on the left(JLabel) and button on the right. I added the text first and would like to try not to set the frame to right to left.
EndFrame code ... uses information from other class and other classes update the JLabel.
public class endFrame extends JFrame
{
public endFrame()
{
setSize(500,75);
setLayout(new FlowLayout());
add(board.winner);
JButton r = new JButton("Reset");
r.addActionListener(board.mouse);
add(r);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
}
MadProgrammer showed me that using Container#add(Comonent, int) allows you to move the objects in the correct order that you want.

How to refresh a JPanel that is nested inside another Jpanel?

I have nested a Jpanel within another JPanel. I want to refresh one of JPanels while not refreshing the other one. I have the following code, I can use the repaint() function however it will update all of the JPanels not just the one that I want (the Time JPanel).
How would I go about refreshing just the Time JPanel? Leaving the Weather JPanel untouched?
I would like to be able to do this from an external thread.
public class MainPanel extends JPanel{
public static JPanel TimePanel = new Time();
public static Weather WeatherPanel = new Weather();
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.BLACK);
this.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
TimePanel.setLocation(0, 0);
TimePanel.setSize(new Dimension(500, 300));
this.add(TimePanel);
WeatherPanel.setLocation(0,300);
WeatherPanel.setSize(new Dimension(100, 100));
this.add(WeatherPanel);
//repaint();//Just causes recursion
}
}
Your code is completely wrong. The paintComponent() method is used for painting with the Graphics object. You should NEVER add components to a panel or change the size, or change the location of a component in a painting method.
There is no need for you to override the paintComponent() method.
In the constructor of your class is where you create the child panels and add them to the main panel. Something like:
public class MainPanel extends JPanel
{
public JPanel timePanel = new Time();
public Weather teatherPanel = new Weather();
public MainPanel()
{
this.setBackground(Color.BLACK);
this.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
this.add(timePanel);
this.add(weatherPanel);
}
}
Notice how I also changed your variables:
you should not be using static
variable names start with a lower case character.
I suggest you start by reading the Swing Tutorial for Swing basics. You can check out the section on How To Use Panels for a working example.

JPanel won't display components when layout is null

I'm trying to create a GUI, and I want to place elements in certain places. I made the layout of my panel null, so I could do this. However, Nothing will appear when the panel is null. Here's the code:
public class OverView extends JFrame {
//height and width of screen
Toolkit tk = Toolkit.getDefaultToolkit();
int x = ((int) tk.getScreenSize().getWidth());//length of screen
int y = ((int) tk.getScreenSize().getHeight());//height
//components
private JLabel title;
private JLabel description;
private JPanel panel;
private ArrayList<JButton> farms;
//farm variables
public ArrayList<Farm> owned;
public OverView(ArrayList<Farm> owned) {
super("The Lolipop Farm - Overview");
setSize(700, 700);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
//initialize variables
this.owned = owned;
panel = new JPanel();
panel.setLayout(null);
title = new JLabel("<html>Your Farms - The Lolipop Farm"
+ "<br> <font size=1000> <i> An Eph Production </i> </font></html>");
//set background color, color, and font of JComponents
title.setFont(new Font("serif", Font.BOLD, 25));
title.setBackground(Color.GRAY);
title.setOpaque(true);
//set size and location of the components
title.setSize(350, 120);
title.setLocation(x / 2, 600);
//add to panel
panel.add(title);
//add panel to the screen
add(panel);
}
}
Why isn't the panel showing anything when the layout's null?
As Overview is a Frame, I think you must call the method
setVisible(true);
according to https://docs.oracle.com/javase/tutorial/uiswing/layout/using.html in order to make it visible .
Now, if that doesn't work, I wonder if you have created an instance of the Overview class somewhere else in your code, or in the Main method. If you haven't, then there is no object that can show the panel inside of your class so your program won't show anything.
Your problem is with the code
setLayout(null);
This will set the layout of the JFrame to null since you are extending (inheriting it). You must have a layout for a JFrame although you can do without layout for JPanel. Just remove that line and it will be fine.
EDIT:
And of course you need to call setVisible(true) like the other guy said.

why the last GUI element i declare is filling the whole panel?

public class add extends JPanel {
private JPanel add = new JPanel();
JFrame frame;
public add(){
frame = new JFrame("Add");
frame.setBounds(550, 300, 700,500);
frame.setVisible(true);
JLabel nameLabel = new JLabel("Name");
final JTextField nameField = new JTextField();
frame.add(nameLabel);
frame.add(nameField);
nameLabel.setBounds(200, 40, 150, 30);
nameField.setBounds(350, 40, 150, 30);
...
JButton registerButton = new JButton("Salveaza");
frame.add(registerButton);
registerButton.setBounds(200,300,300, 30);
registerButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
}
});
}
}
and if i delete the JButton, than a label, which would be the last element, will fill the whole JPanel when i run the programm.
what can i do so i can make it work properly?
You're adding components to a container, the JFrame's contentPane, that uses a BorderLayout as its default layout manager. When you do this and don't specify constants, the component gets added BorderLayout.CENTER, covering up any components added before.
Good Solution: learn and use layout managers, including using nested JPanels, each using its own layout manager and components.
Bad Solution: use null layout with absolute positioning. While to a newbie this seems the best way to create complex GUI's, the more you deal with Swing GUI creation, the more you will find that doing this will put your GUI in a straight-jacket, painting it in a very tight corner and making it very hard to extend or enhance. Just don't do this.

Categories

Resources