I started not so long ago learning Java through tutorials and videos, and after understanding a few things (how buttons, layouts, audio, and a few other things work) one of my goal now is to create a little interactive game.
I wrote a pretty big part of the game in the Main Class and it was working good, but it got messy after a while.
So I decided to try another time from the beginning using different classes for every part of the game to make the code look more clear and understandable.
But I have a problem from the very beginning and after a few hours of searching tutorials, answers on forums and not finding a precise answer, I think it's the best if you will see exactly my problem (which is very simple!)
-So I just constructed the JFrame in a class (I use the main Class only to launch the frame, and it works fine) :
import javax.swing.*;
import java.awt.*;
public class principalFrame {
public principalFrame(){
JFrame mainFrame = new JFrame();
mainFrame.setVisible(true);
mainFrame.setSize(1200,750);
mainFrame.getContentPane().setBackground(Color.BLACK);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setResizable(false);
}
}
and I created a JPanel in another class :
import javax.swing.*;
import java.awt.*;
public class mainMenu{
public mainMenu(){
JPanel menuPanel = new JPanel();
menuPanel.setSize(300,300);
menuPanel.setBackground(Color.BLUE);
}
}
And my goal is to add the JPanel inside the JFrame. And... I don't understand how to do it.
I tried to add the menuPanel class as an object in the mainFrame class so I could add the JPanel but it did'nt work. Then tried a bunch of other solutions from what I read on older questions but nothing really helped me.
PS : I know that I didn't add any layout manager or any other things in the code here because I want to keep the code very simple for the question.
So if you want to make a separate class for mainMenu, you should make it extend JPanel. This way, your mainFrame class can instantiate it.
Here is what I would tell you about the lessons I learned in building things in swing:
You (almost) never need a separate class to create a JFrame. If you create a class that extends JPanel, it is easy enough to create a JFrame in a static method (like main) to put your JPanel in. That being said, if you also want to use the JLayeredPane or want to add menus on a JMenuBar, there might be a case of subclassing JFrame. The advantage of not subclassing JFrame is that it makes it easier to stick your JPanel into a JFrame, a JDialog (via JOptionPane) or a JWindow.
Unless you have a Component that you think could be useful in other applications, you should build your entire GUI in one class, and also use that class as the Controller. What is an example of a Component that could be used in other applications? Back in the day, I made a "ColorButton" swing class, for color picking. This component has a self-contained model, has its own controller and an API to get the picked color. (https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/ui/ex/) which makes it reuseable. But normally, the elements of the GUI you are building aren't really reuseable outside of what you are doing in that class.
With that said, to the code you posted above:
Your mainMenu JPanel isn't accessible outside the class, so that is probably a problem. As I said in the paragraph above, if you're not sure that the Component you are creating could be used in another place, it is better to put the entire view and model building in the same class as the controller
You were close. You have to be able to get the JPanel from the MainMenu class.
The JFrame methods must be called in a specific order. This is the order I use for my Swing applications.
Class names start with an upper case character.
Here's one way you could code your MainMenu class.
public class PrincipalFrame {
public PrincipalFrame() {
JFrame mainFrame = new JFrame();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(new MainMenu().getMenuPanel(), BorderLayout.CENTER);
mainFrame.setSize(1200, 750);
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
}
public class MainMenu {
private final JPanel menuPanel;
public MainMenu() {
this.menuPanel = new JPanel();
this.menuPanel.setPreferredSize(300, 300);
this.menuPanel.setBackground(Color.BLUE);
}
public JPanel getMenuPanel() {
return menuPanel;
}
}
Related
I'm writing a Java text adventure and using Java Swing as a way to display a simple user GUI as the game play screen. I want to have three different windows, one as a start screen, one for a character creation screen where the user inputs a name and some attributes, and one where the game actually takes place.
I want to write each screen in a separate class to increase the organization and readability of my code. However whenever I click on the JButton to go to the next screen a completely new JFrame opens with the content. How can I write my GUI so that all of the screen changes take place in just one frame? Is Java supposed to function like this?
I've looked through at least a couple dozen Java Swing forum questions but still cant find out what I'm doing wrong with my Java swing implementation.
package guiPackage;
import javax.swing.*;
import thingsPackage.Player;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class StartGame extends JFrame {
JFrame Game;
JPanel buttonMenu, screen;
JButton newGame, settings, exit, loadGame;
public StartGame() {
Game = new JFrame();
Game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Game.setVisible(true);
Game.setSize(750, 750);
Game.setLocationRelativeTo(null);
screen = new JPanel();
screen.setVisible(true);
TitleScreenHandler ts = new TitleScreenHandler();
buttonMenu = new JPanel();
newGame = new JButton("New Game");
newGame.addActionListener(ts);
loadGame = new JButton("LoadGame");
loadGame.addActionListener(ts);
settings = new JButton("Settings");
settings.addActionListener(ts);
exit = new JButton("Exit");
exit.addActionListener(ts);
Game.add(screen);
screen.add(buttonMenu, BorderLayout.SOUTH);
buttonMenu.add(newGame);
buttonMenu.add(loadGame);
buttonMenu.add(settings);
buttonMenu.add(exit);
}
public class TitleScreenHandler implements ActionListener{
public void actionPerformed(ActionEvent titleScreenEvent) {
if (titleScreenEvent.getSource() == newGame) {
buttonMenu.setVisible(false);
CharacterCreator newCharacter = new CharacterCreator();
}
else if (titleScreenEvent.getSource() == loadGame) {
buttonMenu.setVisible(false);
}
else if (titleScreenEvent.getSource() == settings) {
buttonMenu.setVisible(false);
}
else if (titleScreenEvent.getSource() == exit){
System.out.println("goodbye");
System.exit(0);
}
}
}
}
package guiPackage;
import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
public class CharacterCreator extends StartGame {
JTextField newName;
JPanel creatorScreen;
Scanner scan = new Scanner(System.in);
public CharacterCreator() {
creatorScreen = new JPanel();
//creatorScreen.setVisible(true);
newName = new JTextField("Create a charactor");
//newName.setLocation(null);
screen.add(creatorScreen);
creatorScreen.add(newName);
}
public String setCharacterName(){
String characterName = "";
return characterName;
}
}
Is Java supposed to function like this?
Your code is only doing what you're telling it to, and you've several problems in your code including one problem here:
public class CharacterCreator extends StartGame {
You're misusing inheritance by havng the CharacterCreator class extend from StartGame. You seem to be doing this to allow communication between classes, but that is not what inheritance is for, and in doing this you're child class is calling the parent class's constructor, creating more windows than you want or need. The solution is to not use inheritance here but rather to pass references to where they are needed.
Also please check out The Use of Multiple JFrames, Good/Bad Practice? since your application should have only one main application window or JFrame. Any child windows should be JDialogs, not JFrames.
Another issue: StartGame extends JFrame and also holds a JFrame variable -- too many JFrames, and best to get rid of one or the other. Usually you don't want to create classes that extend a top-level window since you'll find yourself painting yourself in a corner by having your class extend JFrame, forcing you to create and display JFrames, when often more flexibility is called for. In fact, I would venture that most of the Swing GUI code that I've created and that I've seen does not extend JFrame, and in fact it is rare that you'll ever want to do this. More commonly your GUI classes will be geared towards creating JPanels, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. This will greatly increase the flexibility of your GUI coding.
Other separate and unrelated issues:
You appear to be combining an event driven GUI with a console GUI since you're using a Scanner object initiated with System.in. This is not a good idea since these two programming paradigms do not easily play nice with each other, and instead it is best to stick with one or the other, either a linear console program or an event-driven GUI.
In short, you should try using jLayeredPane and multiple jPanels, not multiple frames. If you're using Netbeans, check out my guide to making GUIs at: http://philofjava.webstarts.com/
I have 2 frames. I want from the first frame to open the second. I tried this, but it leads to an exception.
class aboutaction implements ActionListener {
public void actionPerformed(ActionEvent e) {
frame.dispose();
aboutInfo about = new aboutInfo();
about.frame.setVisible(true);
}
}
about.addActionListener(new aboutaction());
This is the full program: https://github.com/Zhelyazkov97/Fuel-calculator.git.
You're basic problem is a NullPointerException create from a misunderstanding of how Swing works and a bad design.
Basically, you define your class as...
public class aboutInfo extends JFrame {
private JPanel contentPane;
javax.swing.JFrame frame;
Now, here the confusion starts, you basically have two frames, but you only ever add components to the instance of aboutInfo.
The basic answer here is, get rid of frame, it's just confusing the issue. In fact, you shouldn't be extending from JFrame in the first place, you should really use something like JPanel and simply add instances of the class to instances of JFrame or JDialog or what ever container you want
How can I reach jPanel on an other jFrame ?
I want to impel users question.According to answer(yes),I want to get jPanel.setVisible(true)
on an other jFrame
I want to impel users question. According to answer(yes), I want..
See the overloaded methods of JOptionPane.showConfirmDialog(..).
Use some kind of model, which can be altered by your first frame, but which your second frame is listening to.
You should very rarely try and access UI elements that are outside the scope of your current class, as this leads to no end of issues with trying to figure out who is control.
This is at the core of the Model-View-Controller paradigm and observer pattern
You should also have a look at The Use of Multiple JFrames: Good or Bad Practice?
First of all, please change your question because it is very hard to understand what you want from us.
Now to your problem:
I think you want to access a jPanel that is located at the other JFrame.
My Solution:
Just make a reference to it!
So if you have a class MyFrame, just make it look like this one:
public class MyFrame{
private JPanel panelThatIsLocatedAtTheSecondFrame
//Setter and Getter and the other bullshit :D
}
public static void main(String[] args){
MyFrame frame1 = new MyFrame();
MyFrame frame2 = new MyFrame();
JPanel panelIWantToObserve = new JPanel();
frame2.add(panelIWantToObserve);
frame1.setPanelThatIsLocatedAtTheSecondFrame(panelIWantToObserve);
}
I have a class "GUI" that extends JPanel. I have another class "Buttons" that extends JFrame. I'm trying to have the JFrame class call a method "clearScreen()" in the JPanel class when the when a JButton "clearB" is pushed on the JFrame.
The only way I could make this work was by building the object for the JPanel class "GUI" right in the actionlistener for the JButton:
clearB.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
GUI g = new GUI();
g.clearScreen();
}
}
);
But then when I called the method clearScreen(), which looks like this:
public void clearScreen(){
xs.clear();
ys.clear();
count = 0;
repaint();
}
NOTHING HAPPENED. I'm guessing it's because the repaint() method wasn't working for some reason unknown to me.
Someone PLEASE show me an easier, working way of doing what I'm trying to accomplish here.
Thanks! :D
The reason that your ActionListener isn't working is because the GUI object that you create in there is a new GUI object, one that is completely unrelated to the GUI object that is displayed, and so calling the clearScreen() method on the non-displayed GUI instance will have no effect on the displayed GUI instance.
The solution is for your Buttons class to hold a valid reference to the visualized GUI object and call methods on this reference. The reference can be passed via a setter method or constructor parameter.
i.e.,
public class Buttons {
private GUI gui;
public Buttons (GUI gui) {
this.gui = gui;
}
// in some ActionListener code...
gui.someMethod();
}
A couple of comments:
It is unusual that you should have to have a class that extends JFrame. Myself, I try to avoid doing this unless necessary, but rather usually create my JFrames from the JFrame class itself, and only when needed.
I'm a little surprised that your main window class doesn't already have a GUI variable, since it likely displays the GUI instance.
First of all... I'd like to say that I am not interested in using the card layout for this... Unless it's necessary (which means that not using the card layout would be result in unnecessary workarounds and complex code). This is for learning purposes after all and I will look into the card layout very soon enough anyway...
Okay so my question is pretty basic GUI layout I guess. My code is not working and this whole layouting confuses me quite a lot...
I'm having trouble how to make the transition between JPanels like this:
I have one window. I press a button, the old window is replaced by another window. I press a button and that window will be replaced by another window.
I'd like to add that I am skipping a lot of irrelevant code in my example below...
I start off with a JFrame:
public class StartWindow extends JFrame{
public StartWindow(){
//Add JButton & ActionListener
//When the button is pressed:
add(new NextWindow());
}
public static void main(String [] args){
new StartWindow();
}
}
then I have several JPanels...
public class NextWindow extends JPanel{
public NextWindow(){
//Add a JButton & ActionListener
//When the button is pressed:
add(new NextWindow2());
remove(this);
//This does not work. Nothing happens.
}
}
public class NextWindow2 extends JPanel{ // Stuff and so on}
So, I'd like to know a proper way to handle this situation!
You are adding a panel to itself. You need to remove the panel from the JFrame, add the new one to it, and call revalidate() on the JFrame.