I'm trying to make a simple menu for my game. I have 4 buttons in the center and I want to make them a little bit bigger and center them.
The last part worked but I can't seem to call any of my JButtons and do a .setSize / .setPreferedSize(new Dimension()) on it.
public class mainMenu extends JFrame {
private JButton start, highscore, help, stoppen;
public mainMenu() {
super("Master Mind");
maakComponenten();
maakLayout();
toonFrame();
}
private void maakComponenten() {
start = new JButton("Start");
start.setBackground(Color.gray);
highscore = new JButton("Higscores");
help = new JButton("Help");
stoppen = new JButton("Stoppen");
}
private void maakLayout() {
JPanel hoofdmenu = new JPanel();
hoofdmenu.setLayout(new BoxLayout(hoofdmenu, BoxLayout.Y_AXIS ));
hoofdmenu.add(start);
start.setAlignmentX(CENTER_ALIGNMENT);
hoofdmenu.add(highscore);
highscore.setAlignmentX(CENTER_ALIGNMENT);
hoofdmenu.add(help);
help.setAlignmentX(CENTER_ALIGNMENT);
hoofdmenu.add(stoppen);
stoppen.setAlignmentX(CENTER_ALIGNMENT);
super.add(hoofdmenu);
}
private void toonFrame() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
setSize(500,500);
}
public static void main(String[] args) {
new mainMenu();
}
}
As an example, to change the size of the "Start" button,
change :
start1 = new JButton("Start");
to
start1 = new JButton("Start") {
{
setSize(150, 75);
setMaximumSize(getSize());
}
};
The problem is that JFrames use BorderLayout by default, which means that your JPanel will naturally fill the space.
Before adding your JPanel, call the following code to change the JFrame's layout to null and use the JPanel's settings instead.
this.setLayout(null);
JPanel hoofdmenu = new JPanel();
hoofdmenu.setBounds(0,0, 400, 100);
Alternatively, you could set the maximum size of the JButtons
Dimension maxSize = new Dimension(100, 100);
start.setMaximumSize(maxSize);
highscore.setMaximumSize(maxSize);
help.setMaximumSize(maxSize);
stoppen.setMaximumSize(maxSize);
Here's another example following behind the previous two - I'm making a soundboard program, and this is actually a sample from it - The JPanel actually is needed, agreeing to the second post.
JFrame frame = new JFrame();
JPanel menuPanel = new JPanel();
JButton Button1 = new JButton("<BUTTON NAME 1>");
Button1.setSize(80, 30);
Button1.setLocation(4, 4);
JButton Button2 = new JButton("<BUTTON NAME 2>");
Button2.setSize(80, 30);
Button2.setLocation(90, 4);
Ah, and another thing - You created the buttons in a different block from the second piece of code. Doing that causes the other blocks to not see it. You need to declare them outside the block so all the blocks can see them.
Related
I'm just getting into creating GUIs in Java, and with this basic setup, I can't get anything to appear in my JFrame:
public class Main extends JFrame {
public static void main(String[] args) {
JFrame jframe = new JFrame();
jframe.setSize(400,400); // setting size
jframe.setVisible(true); // Allow it to appear
jframe.setTitle("Lab 7");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Main init = new Main();
}
public Main() {
Container pane = getContentPane();
pane.setBackground(Color.BLUE);
pane.setLayout(new FlowLayout());
JButton add = new JButton("Add");
JButton close = new JButton("Close");
JTextArea area = new JTextArea();
JScrollPane scroll = new JScrollPane(area);
add.setBounds(70, 125, 80, 20);
close.setBounds(70, 115, 80, 20);
pane.add(add);
pane.add(close);
pane.add(scroll);
AddClick added = new AddClick();
add.addActionListener(added);
}
}
I also tried moving all the JFrame stuff into public Main() but it caused an infinite amount of windows opening and I had to end the program each time.
You're creating two separate JFrames: one is your Main class, and the other is an unrelated JFrame. Most of the customization, including adding components, happens to the Main in its constructor. But you only ever set the other JFrame to be visible.
Use your Main instance as the JFrame instead of creating another one, and the problem will be fixed.
public static void main(String[] args) {
JFrame jframe = new Main(); //Use an instance of Main as your JFrame
jframe.setSize(400,400); // setting size
jframe.setVisible(true); // Allow it to appear
jframe.setTitle("Lab 7");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
I'm trying to make a little game that will first show the player a simple login screen where they can enter their name (I will need it later to store their game state info), let them pick a difficulty level etc, and will only show the main game screen once the player has clicked the play button. I'd also like to allow the player to navigate to a (hopefully for them rather large) trophy collection, likewise in what will appear to them to be a new screen.
So far I have a main game window with a grid layout and a game in it that works (Yay for me!). Now I want to add the above functionality.
How do I go about doing this? I don't think I want to go the multiple JFrame route as I only want one icon visible in the taskbar at a time (or would setting their visibility to false effect the icon too?) Do I instead make and destroy layouts or panels or something like that?
What are my options? How can I control what content is being displayed? Especially given my newbie skills?
A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.
Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.
Oh, and welcome to stackoverflow.com!
Here is an example of a Login Dialog as #HovercraftFullOfEels suggested.
Username: stackoverflow Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Arrays.equals("stackoverflow".toCharArray(), jpfPassword.getPassword())
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
I suggest you insert the following code:
JFrame f = new JFrame();
JTextField text = new JTextField(15); //the 15 sets the size of the text field
JPanel p = new JPanel();
JButton b = new JButton("Login");
f.add(p); //so you can add more stuff to the JFrame
f.setSize(250,150);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insert that when you want to add the stuff in. Next we will add all the stuff to the JPanel:
p.add(text);
p.add(b);
Now we add the ActionListeners to make the JButtons to work:
b.addActionListener(this);
public void actionPerforemed(ActionEvent e)
{
//Get the text of the JTextField
String TEXT = text.getText();
}
Don't forget to import the following if you haven't already:
import java.awt.event*;
import java.awt.*; //Just in case we need it
import java.x.swing.*;
I hope everything i said makes sense, because sometimes i don't (especially when I'm talking coding/Java) All the importing (if you didn't know) goes at the top of your code.
Instead of adding the game directly to JFrame, you can add your content to JPanel (let's call it GamePanel) and add this panel to the frame. Do the same thing for login screen: add all content to JPanel (LoginPanel) and add it to frame. When your game will start, you should do the following:
Add LoginPanel to frame
Get user input and load it's details
Add GamePanel and destroy LoginPanel (since it will be quite fast to re-create new one, so you don't need to keep it memory).
I'm creating a program that features a grid of 12 JPanels. When the "add image" button is pressed, an image appears in the first JPanel in the grid and a counter is incremented by one. From then onwards, every time the "add image" is clicked again, an image would be added to the next JPanel. For some reason, the button only adds an image to the first JPanel and then stops working. Here's the code I've got so far.
public class ImageGrid extends JFrame {
static JPanel[] imageSpaces = new JPanel[12];
int imageCounter = 0;
ImageGrid() {
this.setTitle("Image Grid");
setSize(750, 750);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel p3 = new JPanel();
p3.setLayout(new GridLayout(3, 4, 10, 5));
p3.setBackground(Color.WHITE);
p3.setOpaque(true);
p3.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
for (int j = 0; j < imageSpaces.length; j++) {
imageSpaces[j] = setImageSpace();
p3.add(imageSpaces[j]);
}
MyButtonPanel p1 = new MyButtonPanel();
add(p1, BorderLayout.SOUTH);
add(p3, BorderLayout.CENTER);
}
public JPanel setImageSpace() {
JPanel test;
test = new JPanel();
test.setOpaque(true);
test.setPreferredSize(new Dimension(100, 100));
return test;
}
class MyButtonPanel extends JPanel implements ActionListener {
final JButton addImage = new JButton("Add Image");
ImageIcon lorryPicture = new ImageIcon(ImageGrid.class.getResource("/resources/lorry.png"));
JLabel lorryImage = new JLabel(lorryPicture);
MyButtonPanel() {
add(addImage);
addImage.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == addImage) {
imageSpaces[imageCounter].add(lorryImage);
revalidate();
repaint();
imageCounter++;
}
}
}
public static void main(String[] args) {
ImageGrid test = new ImageGrid();
test.setVisible(true);
}
}
You should be revalidating and repainting the panel, (which is the containter being affected by the addition), not the frame
imageSpaces[imageCounter].add(lorryImage);
imageSpaces[imageCounter].revalidate();
imageSpaces[imageCounter].repaint();
Diclaimer: This may work as a simple fix, but also note that a component (in this case your JLabel lorryImage) can only have one parent container. The reason the above fix still works is because you don't revalidate and repaint the previous panel, the label was added to. So you may want to think about doing it correctly, and adding a new JLabel to each panel.
if (e.getSource() == addImage) {
JLabel lorryImage = new JLabel(lorryPicture);
imageSpaces[imageCounter].add(lorryImage);
imageSpaces[imageCounter].revalidate();
imageSpaces[imageCounter].repaint();
imageCounter++;
}
Disclaimer 2: You should add a check, to only add a label if the count is less than the array length, as to avoid the ArrayIndexOutOfBoundsException
Side Notes
Swing apps should be run from the Event Dispatch Thread (EDT). You can do this by wrapping the code in the main in a SwingUtilities.invokeLater(...). See more at Initial Threads
You could also just use a JLabel and call setIcon, instead of using a JPanel
For the sake of less code, I am taking out code that is unrelevant to the problem, such as addActionListener(); etc.
My main class is public class TF2_Account_Chief
I have my main Jframe f; and its contents:
private static JFrame f = new JFrame("TF2 Account C.H.I.E.F.");
private JLabel runnableTogetherLabel = new JLabel("How many idlers would you like to run at a time?");
private static JTextField runnableTogetherInput = new JTextField();
private JButton runButton = new JButton("Run!");
private JButton stopButton = new JButton("Stop!");
private JButton resetButton = new JButton("Reset!");
private JButton exitButton = new JButton("Exit!");
and I set the properties of all the contents:
public void launchFrame() {
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
f.add(runnableTogetherInput);
f.add(runnableTogetherLabel);
f.add(runButton);
f.add(stopButton);
f.add(resetButton);
f.add(exitButton);
f.setSize(625, 500);
runnableTogetherInput.setSize(35, 20);
runnableTogetherLabel.setSize(275, 25);
runButton.setSize(60, 25);
stopButton.setSize(65, 25);
resetButton.setSize(70, 25);
exitButton.setSize(60, 25);
f.setLocation(0, 0);
runnableTogetherInput.setLocation(285, 3);
runnableTogetherLabel.setLocation(5, 0);
runButton.setLocation(330, 0);
stopButton.setLocation(395, 0);
resetButton.setLocation(465, 0);
exitButton.setLocation(540, 0);
}
then I have my main() method:
public static void main(String[] args) throws IOException {
TF2_Account_Chief gui = new TF2_Account_Chief();
gui.launchFrame();
Container contentPane = f.getContentPane();
contentPane.add(new TF2_Account_Chief());
}
And then I have my second JFrame iF which is not displaying the contents correctly:
private void invalidInput() {
JFrame iF = new JFrame("Invalid Input!");
JLabel iL = new JLabel("The input you have entered is invalid!");
JButton iB = new JButton("Exit!");
Container contentPane2 = iF.getContentPane();
contentPane2.add(new TF2_Account_Chief());
iF.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
iF.pack();
iF.setVisible(true);
iF.add(iL);
iF.add(iB);
iF.setSize(500, 300);
iL.setSize(125, 25);
iB.setSize(60, 25);
iF.setLocation(0, 0);
iL.setLocation(0, 15);
iB.setLocation(0, 45);
}
Now, JFrame iF is launched when the invalidInput() method is called, but you can't see that because that part of the code is unrelevant to the problem. What does matter is that the JFrame iF is launched.
The new frame looks like this:
Any ideas on why the contents are not displaying properly?
(By improperly, I mean the JButton iB takes up the whole frame and the frame is a light blue instead of the normal grey.)
You are using absolute positions without using a null layout, that's why you see a large button.
To see every component, you have to use
iF.setLayout(null);
but it's not a good practice, I'd suggest you to learn how to use Layouts and leave all the work to the layout manager
The default layout of JFrame is BorderLayout, in which there are "5" locations you can put your components to
CENTER
PAGE_START
PAGE_END
LINE_START
LINE_END
So, iF.add(component) will add the component to the CENTER, you can specify the location like this:
iF.add(component, BorderLayout.PAGE_END);
//You can also put PAGE_START, LINE_START, LINE_END, CENTER
Take my advice and read more about BorderLayout, because if you refuse to learn Layout Managers, you probably go to Absolute Positioning( null layout) which is not a good way and must not be used.
This is a weird problem. I have a solution for it, but I don't know WHY the problem occurs in the first place. Observe the code below:
// VERSION 1
public class test {
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Test");
JPanel inputPanel = new JPanel();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
mainFrame.setBounds(100, 50, 200, 100);
mainFrame.setVisible(true);
JButton inputFileButton = new JButton("BROWSE");
inputPanel.add(inputFileButton);
}
}
It works as expected. The button does nothing, but it renders correctly. Now, I add a JFileChooser (which I plan to do something with later, but for now all I'm doing is instantiating it).
// VERSION 2
public class test {
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Test");
JPanel inputPanel = new JPanel();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
mainFrame.setBounds(100, 50, 200, 100);
mainFrame.setVisible(true);
JFileChooser inputFileChooser = new JFileChooser(); // NEW LINE
JButton inputFileButton = new JButton("BROWSE");
inputPanel.add(inputFileButton);
}
}
All of a sudden my button no longer renders. Why? I know two ways to make it work again, but neither makes 100% sense to me. One way to fix it:
// VERSION 3
public class test {
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Test");
JPanel inputPanel = new JPanel();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
mainFrame.setBounds(100, 50, 200, 100);
mainFrame.setVisible(true);
JButton inputFileButton = new JButton("BROWSE");
inputPanel.add(inputFileButton);
JFileChooser inputFileChooser = new JFileChooser(); // MOVE LINE TO END
}
}
So moving that line to the end allows the button to render again, but that still makes no sense to me what an instantiated JFileChooser has to do with the unconnected button. Another way I can fix this issue:
// VERSION 4
public class test {
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Test");
JPanel inputPanel = new JPanel();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getContentPane().add(BorderLayout.CENTER, inputPanel);
mainFrame.setBounds(100, 50, 200, 100);
JFileChooser inputFileChooser = new JFileChooser();
JButton inputFileButton = new JButton("BROWSE");
inputPanel.add(inputFileButton);
mainFrame.setVisible(true); // MOVE *THIS* LINE TO THE END
}
}
It kind of makes sense why the version above fixes the problem... obviously something about the JFileChoose instantiation was making my button invisible, but this setVisible() method afterwards bring it back into the light. But that still doesn't tell me WHY it went invisible in the first place.
Can somebody please help me figure out what I'm missing? Thanks!
You are making your mainFrame visible and adding the button afterwards. Take a look at this SO question on what steps you need to take to make sure your button is visible.
The reason why it works in your first example is probably pure luck. Your call to add the button will be performed before the EDT shows your component.
Note: please perform the Swing operations on the EDT