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
Related
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;
}
}
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.
I am using Java's Swing here to make a UI application. I have a created a JFrame, with some buttons. When I click on this button, I want a new JFrame with some different content at this place. However, I do not want a new JFrame to load here.
One approach, I know is of setting the visbility of the second JFrame to be True in the actionPerformed(ActionEvent obj) method of the button in the first JFrame. But it again loads a new JFrame and I don't want that.
public class FirstUI extends JFrame {
JButton but1;
public FirstUI(){
but1= new JButton("Click here");
add(but1);
XYZ obj= new XYZ():
but1.addActionListener(obj);
}
public class XYZ implements ActionListener{
public void actionPerformed(ActionEvent obj1){
// WHAT TO DO HERE
}
}
}
I only want a single JFrame whose content changes as we click on different buttons. How can I achieve that ?
Have a look at CardLayout, this would allow to switch the content of your frame:
A CardLayout object is a layout manager for a container. It treats each component in the container as a card. Only one card is visible at a time, and the container acts as a stack of cards. The first component added to a CardLayout object is the visible component when the container is first displayed.
See How to Use CardLayout for an example.
You can also dynamically manipulate the contents of your JFrame at runtime. You can use add(...), remove(...), removeAll(...) methods to add and remove the contents as you do before showing the frame. After you're done you need to call revalidate() and repaint() methods of the modified container to make everything settle down and displayed properly.
However I think the right solution depends on the actual concept you are trying to implement. If you want to add or remove a couple of GUI elements to emphasize a functionality, then the correct way is to manipulate the container as I outlined. But if you want slightly different GUI depending on system state (not more then 2-3) then CardLayout would be a better suited choice
You can set visibility of parent class false.
Then you get only one Frame at a time with your required content.
You have to create static object of the frame and setVisible(fase) at the click event of the Button.
Ex.
public class demo {
static JFrame jf;
public static void main(String a[])
{
JButton b=new JButton("OK");
JPanel jp=new JPanel();
jf=new JFrame();
jf.setVisible(true);
jf.setSize(200,200);
jf.add(jp);
jp.add(b);
b.addActionListener( new ActionListener(){
public void actionPerformed(ActionEvent e)
{
jf.setVisible(false);
JFrame f= new JFrame();
f.setSize(200,200);
f.setVisible(true);
}
});
}
}
It will help you.
you got my point?
One approach is to change the JFrame's Content Pane. which is basically a JPanel. You can do that byframe.setContentPane( <your new panel> );
The Second approach is to do what #Peter Lang did. and that is to use a Layout Manager which could change different content groups.
I have a MainWindow class that extends JFrame and is the only frame in my application. I have several JPanels to change its content though. I would like to pass the MainWindow around so I won't have to make a global copy of it.
Here is the problem. I have a fake JMenuBar in MainWindow that I use to go around and look for screens. In their JMenuItem listeners, I cannot pass MainWindow as this to the JPanels.
Is there a way I can do that, like maybe marking the class final or do I have to create a new MainWindow each time I have to pass in one. It doesn't carry around any data so its not crucial and the performance isn't a major concern for a small final project like this but I want to know if there is a better way?
Are you unable to pass this because it would reference the listener? If so, you should be able to use MainWindow.this.
Or create a reference to this outside the listener and pass that as the parameter.
Create the MainWindow class as the Outer class and extend this to JFrame which u already did, . Now in the MainWindow class, create as many inner classes as you want and let the handle the ActionListener method in different way..
eg:
MainWindow extends JFrame {
MainWindow(){
}
class panel1 extends JPanel implements ActionListener{
}
class panel2 extends JPanel implements ActionListener{
}
}
You can also implement Singleton Pattern, so that makes sure there is only one instance of MainWidow.
Try any of this approaches:
Make MainWindow singleton.
Mark as final a variable in the method when you create the listener.
Use MainWindow.this
For your case use the singleton approach, with that you can access freely from any place of your project.