JFrame issue. This keeps printing double the amount of windows I need - java

I have two more classes that this main class is using, but I think that it can be answered without those classes because I think it is a logic problem.
I'm trying to create a JFrame that prints out a drawing. The way the API is set up, I want public Viewer to create the frame and set the title and then main to instantiate a viewer. But the way I have this set up keeps printing double the amount of frames that I need. Also, when I try to concatenate
v.setTitle(v.getTitle() + String.format(" pi = %.4f", pi));
it doesn't work. It just prints a new JFrame with just
String.format(" pi = %.4f", pi));
and the original JFrame prints its name (two separate frames). So I know it has to be a logic problem somewhere, but I can't figure it out.
import java.util.Scanner;
import javax.swing.JFrame;
public class Viewer extends JFrame{
private ControlPanel cp;
public Viewer(String name, int in){
JFrame frame = new JFrame();
frame.setSize(550, 550);
frame.setTitle("Name: " + name);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cp = new ControlPanel(in);
frame.add(cp);
frame.setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
int n = (int) 1e4;
System.out.println("Enter the number of runs to make <1 to 4>:");
#SuppressWarnings("resource")
Scanner in = new Scanner(System.in);
int runs = in.nextInt();
if (runs > 4){
runs = 4;
}
if (runs < 1){
runs = 4;
}
for (int i = 1; i <= runs; i ++){
n = n * runs;
Viewer v = new Viewer("Trey Wilson", n);
int hits = v.cp.getHits();
double pi = 4.0 * hits / n;
v.setTitle(v.getTitle() + String.format(" pi = %.4f", pi));
v.pack();
v.setVisible(true);
v.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}

Your code has multiple errors:
It extends JFrame and creates a JFrame object (just remove the extends JFrame from the class, it's recommended to do so)
Here lies your problem:
Viewer v = new Viewer("Trey Wilson", n);
this calls the Viewer's class constructor but the constructor itself sets it's own title, size, etc, and then you're modifying those attributes and making another call to setVisible(true) which makes this last frame visible again, so remove one or the other.
You're not placing your program on the EDT, see SwingUtilities.invokeLater() why is it needed?
See The use of multiple JFrames, Good / Bad Practice? (Bad) you should instead want to try using a single JFrame with multiple JPanels switching them with a Card Layout or using JDialogs to display / retrieve information to / from user
From your comment above:
I'm completely new to Jframe (along with java) and was given an API to follow along with. What does extends mean? I'll give it a google, but didn't know if you had an answer on how to fix it.
I recommend you to learn the OOP basics, Java concepts first before going into Java Swing which will make your learning harder because it will add more complexity to it and make it harder to you to maintain or make a quality software.

THIS SOLVES THE PROBLEM OF DOUBLE FRAME APPEARING:
So you can either take away frame.setVisible(true); in the constructor as in:
public Viewer(String name, int in){
JFrame frame = new JFrame();
frame.setSize(550, 550);
frame.setTitle("Name: " + name);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cp = new ControlPanel(in);
frame.add(cp);
}
OR Rather take away v.setVisible(true); from you main method.
I will advice you to take away frame.setVisible(true);. But depending on you requirement, choose the best for yourself.

Related

How to create multiple buttons that do the same on different positions without creating actual new buttons?

Im really new to java and Programming as a whole. In school, I decided to work on a project to raise my grade, and as simple java is currently our topic i decided on trying to recreate battleships in a jframe using swing. I've made some good progress so far but im stuck on a quality of Life Problem.
So basically, in the editor we use (Java Editor ( javaeditor.org )) i use swing to implement buttons etc. in the jframe. As im gonna need a lot of Buttons for the games gui, I want to do it, so i dont have to make several buttons which have to be filled in with the arguments. What im trying to do is have some arguments create several buttons for me so they dont actually all need their own “method“ as all buttons have to basically do the exact same thing.
I tried searching for similar things on google but I couldnt find anything, so i decided to create this account to ask if someone might be able to help me with this Problem. If something isnt understandable feel free to ask (English isnt my mother tongue so some parts might be hard to understand).
Looking forward to any replies! Thanks in advance for helping.
Initially I thought I could use a for-loop to create these multiple buttons but there would always be some kind of error with the ActionPerformed argument.
for (int i = 0;i > 25;i++ ) {
jButton[i].setBounds(48, 48 + i, 113, 73);
jButton[i].setText("jButton1");
jButton[i].setMargin(new Insets(2, 2, 2, 2));
jButton[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jButton[i]_ActionPerformed(evt);
}
});
cp.add(jButton[i]);
}
As already said I expect there to be more than 1 button, whilst keeping the lines of code in the constructor as short as possible.
If you're desiring a grid of buttons, then create them in a for loop, and place them in the JPanel using a GridLayout. Something like this might work:
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class ManyButtons extends JPanel {
private static final int SIDES = 10;
private JButton[][] buttonGrid = new JButton[SIDES][SIDES];
public ManyButtons() {
setLayout(new GridLayout(SIDES, SIDES));
for (int row = 0; row < buttonGrid.length; row++) {
for (int col = 0; col < buttonGrid[row].length; col++) {
String text = String.format("[%d, %d]", col + 1, row + 1);
buttonGrid[row][col] = new JButton(text);
buttonGrid[row][col].addActionListener(event -> {
String command = event.getActionCommand();
System.out.println("Button pressed: " + command);
});
add(buttonGrid[row][col]);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
ManyButtons mainPanel = new ManyButtons();
JFrame frame = new JFrame("Many Buttons");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
Also avoid setBounds and null layouts.
Regarding:
.... without creating new JButtons
This is not technically possible if you want a fully functioning button (as opposed to creating a rendered button in a JTable), however, buttons can share ActionListeners, so all buttons that do the same kind of thing (think -- all the number buttons on a calculator) can use the very same ActionListener. Alternatively, you can set a button's Action using your own class that extends from AbstractAction for even greater flexibility and power, and multiple buttons (and JMenuItems) can share the same action.

Java NullPointer Exception with Jpanel [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
Hello guys I started a personal project to where I would basically make a meal planner based of how many calories a person wants to consume per day for myself. I know it maybe a tough challenge for me since I'm a beginner, but I can do it! I will leave the backend later, but for now I wanted to work on the UI and I'm having trouble with this piece of code. I want to make a list of panels to be held in a panel, based on how many number of meals they want is how many panels will appear. any insight on this will be much appreciated.
package mealplanner;
import javax.swing.*;
/**
* Created by Usman on 6/8/2017.
*/
public class MealPlannerPanel extends JPanel {
JPanel[] panel;
int mealsPerDay, caloriesPerDay;
public MealPlannerPanel(){
mealsPerDay = Integer.parseInt(JOptionPane.showInputDialog("How many meals would you like per day?",null));
caloriesPerDay = Integer.parseInt(JOptionPane.showInputDialog("What is your daily calorie aim?",null));
panel = new JPanel[mealsPerDay];
for(int i = 0; i < panel.length; i++){
add(panel[i]);
}
}
public static void main(String[] args){
MealPlannerPanel planner = new MealPlannerPanel();
JFrame frame = new JFrame("Meal Planner");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(planner);
frame.pack();
frame.setVisible(true);
}
}
panel = new JPanel[mealsPerDay];
That statement just creates an array that is able to hold the given number of panels.
It does not actually create the panel (so when you index into the array you will get a null object).
So you need something like:
for(int i = 0; i < panel.length; i++){
JPanel onePanel = new JPanel();
panel[i] = onePanel;
add(panel[i]);
}
Also, be more descriptive with you variable names. "panel" implies a single component. Given it is meant to represent an array the least you can do is call it "panels" so we know there is more than one.

Error when I tried to run my Java class on another computer?

I am notdoing a school project, so please do not be alarmed. I am doing some private programming to brush up. My program, a program of type .java, creates a form that asks for the boundaries and quantities of a lottery-drawing activity and acts on the generating based on the input.
Here's my problem. On the WIndows 2000 computer where I coded the program, shows itself, perfectly. That's only half the story. When I tried to put it on another computer, the program shows a blank window; it compiles and runs, but it shows a blank window. Now, I do consider version numbers to be factors, so I will provide the versions and ask for confirmation if those are the root of the evil.
On my original computer, which is Windows 2000, the version is 1.6.0_31-b05. The other computer, which is Windows 7 dual-booted with Linux Mint 17.2, is running 1.8.0_60-b27 and 1.8.0_00 respectively.
My program is not finished yet, but I'll worry about that later. What I'm hoping to do now is to get the program, such as it is, to run on the platforms of all my computers. Since Java is known for its portability, I expect it to run on all my computers. Is that a misconception?
Anyways, here's the code:
//Import class libraries
import javax.swing.*;
import javax.swing.JOptionPane;
import java.awt.*;
import java.awt.event.*;
public class Lotterygui //Begin class
{
//VARIABLES FOR DATA COLLECTION
private JTextField lowerRange; //Lowest number
private JTextField higherRange; //Highest number
private JTextField quantity; //How many numbers to generate
private JTextArea displayArea; //What to display when the program is in use
//ADD WARNING CONSTANT FOR INVALID INPUT
private final String WARNING = "Please fill out valid data "
+ "and not leave anything out. "
+ "Also,do not enter any "
+ "zeroes.";
public Lotterygui()
{
//GUI CONFIGURATION
//Frame settings
JFrame jfrFrame = new JFrame("Lottery Program");
jfrFrame.setSize(300,400);
jfrFrame.setLocationRelativeTo (null);
jfrFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrFrame.setVisible(true);
jfrFrame.setResizable(false);
//Panel to hold the user input controls in place
JPanel jplInputs = new JPanel();
jplInputs.setLayout(new GridLayout(4, 2));
//CREATE INPUT CONTROLS
//Lowest range
JLabel jlblLowerRange = new JLabel("Lowest");
lowerRange = new JTextField();
//Highest range
JLabel jlblHigherRange = new JLabel("Highest");
higherRange = new JTextField();
//Quantity
JLabel jlblQuantity = new JLabel("Quantity");
quantity = new JTextField();
//Buttons and their respective action associations
//Generate numbers button
JButton jbtnGenerate = new JButton("Generate");
ActionListener alGenerate = new listenGenerate();
jbtnGenerate.addActionListener(alGenerate);
//Reset all values button
JButton jbtnReset = new JButton("Reset");
ActionListener alReset = new listenReset();
jbtnReset.addActionListener(alReset);
//ADD CONTROLS TO FORM
jplInputs.add(jlblLowerRange);
jplInputs.add(lowerRange);
jplInputs.add(jlblHigherRange);
jplInputs.add(higherRange);
jplInputs.add(jlblQuantity);
jplInputs.add(quantity);
jplInputs.add(jbtnGenerate);
jplInputs.add(jbtnReset);
//CREATE DISPLAY AREA AND ADD
//The display area used for showing generated numbers
displayArea = new JTextArea();
displayArea.setLineWrap(true);
displayArea.setText(WARNING);
//The control that sets autoscrolling for the display area
JScrollPane jspDisplayArea = new JScrollPane(displayArea);
jfrFrame.add(jspDisplayArea);
//Add the JPanels to the window
jfrFrame.add(jplInputs, BorderLayout.NORTH);
jfrFrame.add(jspDisplayArea);
}//END lotteryGUI constructor
//MAIN Method
public static void main (String[] args)
{
//CALL UP lotteryGUI CLASS
new Lotterygui();
}//END Main method
//GENERATE BUTTONS ACTION
private class listenGenerate implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//DECLARE VARIABLES
int low; //Lowest number
int high; //Highest number
int qty; //How many numbers
try //Monitor the input of above variables in the form
{
low = Integer.parseInt(lowerRange.getText());
high = Integer.parseInt(higherRange.getText());
qty = Integer.parseInt(quantity.getText());
}
catch (NumberFormatException nfe)
{
//RESET ALL FORM VALUES
reset();
//RESET VARIABLE VALUES
low = 0;
high = 0;
qty = 0;
}//END format errors try-catch
//CHECK IF PROGRAM CAN CONTINUE
if (low != 0 || high != 0 || qty != 0) //If valid
{
//Action pending
displayArea.setText("Generate here - incomplete");
}
else //If there are more one or more errors in the input
{
//ISSUE WARNING
JOptionPane.showMessageDialog(null, WARNING);
}//END IF continue CHECK
}//END actionPerformed method
}//END listenGenerate class
I've been looking up and down at the code. Can this that I did not reference any of the layouts outlined in import? I know it's not JPanel as I did try that can still the problem existed. Anything that will help me will be appreciated. Thank you.
You're calling
jfrFrame.setVisible(true);
first and then adding a bunch of components to the JFrame, and that's backwards and can result in a GUI that does not render components until it is resized or minimized and restored. In fact try this -- run your program, then minimize the blank GUI and restore it, and I'll bet you'll see your components.
I suggest that you swap this order around -- call jfrFrame.setVisible(true); last after adding everything to the GUI.

Closing only a single instance of JFrame?

So I have two classes, Main and MakeUserWindow, inside of my Main class I call MakeUserWindow several times with different parameters by using a loop. The only problem is, this creates several windows that overlap each-other (Which isn't that much of a deal, it's just that I can get 20 windows on top of each-other). What I thought of doing was simply using window.dispose(); right before recalling the instance, however, when I do that it closes all instances of the window. Not allowing me to recreate the instance using the same variable. Is there a way of closing only the single instance like window.close(); that I am unaware about, or am is there just a better way of doing this? I have searched for awhile before coming here, no results have helped.
For some reference, here is a simplified version of what I am doing
(MakeUserWindow is a class that extends JFrame)
MakeUserWindow newWindow;
for(stuff){
newWindow.dispose();
newWindow = new MakeUserWindow("parameters here");
}
EDIT---
The reason I initialize MakeUserWindow outside of the loop is because I need to use newWindow's properties.
Thanks for reading, -Zach.
I had tested it and this is what i got:
JFrame frame = new JFrame();
for (int i = 0; i < 5 ; i++) {
frame.dispose();
frame = new JFrame();
}
More or less like your code. Only the last frame survived cause you are closing the others when you do the ".dispose()". What you can do is a Map that keeps all the instances.
Map<String, JFrame> frames = new HashMap<String, JFrame>();
JFrame frame = new JFrame();
for (int i = 0; i < 5 ; i++) {
frame = new JFrame();
frames.put("Window" + i,frame);
}
And if you want to close a frame you do:
frames.get("WindowX").dispose();

Java: Animated Sprites on GridLayout Part 2

This is a continuation from my last post Java: Animated Sprites on GridLayout. Thanks to a reply, it gave me an idea in where I just had to insert a loop in the trigger condition and call pi[i].repaint() in it. So far it works. Though I tried to integrate it to my game which composed of multiple sprites, it had no improvement in it. Without the animation, the sprites show on the grid with no problems. I inserted the animation loop in the GridFile class and it didn't show. I also tried to insert the animation loop in the MainFile, it showed irregular animations, kinda like a glitch. Can someone tell me where did I went wrong? Ideas are welcome.
MainFile class
public class MainFile {
JFrame mainWindow = new JFrame();
public JPanel gridPanel;
public MainFile() {
gridPanel= new GridFile();
mainWindow.add(gridPanel,BorderLayout.CENTER);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(700,700);
mainWindow.setResizable(false);
mainWindow.setVisible(true);
}
public static void main(String[]args){
new MainFile();
}
}
GridFile class
public class GridFile extends JPanel{
ImageIcon gameBackground = new ImageIcon(getClass().getResource("Assets\\GridBackground.png"));
Image gameImage;
int[] pkmArray = new int[12];
int random = 0;
Pokemon[] pkm = new Pokemon[36];
JPanel[] pokeball = new JPanel[36];
int j = 0;
public GridFile(){
setLayout(new GridLayout(6,6,6,6));
setBorder(BorderFactory.createEmptyBorder(12,12,12,12));
gameImage = gameBackground.getImage();
for(int i = 0;i < 36;i++){
do{
random = (int)(Math.random() * 12 + 0);
if(pkmArray[random] <= 3){
pokeball[i] = new Pokemon(random);
pokeball[i].setOpaque(false);
pokeball[i].setLayout(new BorderLayout());
pkmArray[random]++;
}
}while(pkmArray[random] >= 4);
add(pokeball[i],BorderLayout.CENTER);
}
while(true){
for(int i = 0; i < 36; i++){
pokeball[i].repaint();
}
}
}
public void paintComponent(Graphics g){
if(gameImage != null){
g.drawImage(gameImage,0,0,getWidth(),getHeight(),this);
}
}
}
Use a swing Timer for the repainting, and give a bit time between the frames for swing to do the painting work. There's no point trying to draw faster than what could be displayed anyway. If you have the animation loop in main(), the repaint manager will try to drop some of the repaint requests that appear close to each other, which can be the cause of the irregular animation you see.
You should create and access swing components only in the event dispatch thread. You current approach is breaking the threading rules.
Addition: When the animation loop is where you have it now, the GridFile constructor never returns, which explains that you'll see nothing because the code never gets far enough to show the window.

Categories