0

I am trying to get this code to work, such that I have a cardlayout container and each panel be defined in its own class and actual file. This code is not 100% my own and is a modified version of my previous stuff by another Stack overflow user. It is more or less what I need, but I need it such that it isn't automated and I can write 15 different panels with decisions made inside each one. The Main and Arrow class was modified by said user, and Imagepanel is my attempt to write a class that will be accepted by the working part of the code. The issue is the Imagepanel I insert into the container will register as existing, but nothing shows up on the panel, it's blank. The commented out portion in ImagePanel is my code that I set on the back burner in favor of the established stuff previously used in the Arrow class.

Here is the Main class

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.*;
import javax.swing.*;

public class Main extends JPanel {
   private Arrow arrow = new Arrow();   //creates a new Arrow object

public Main() {
    JPanel btnPanel = new JPanel();
    btnPanel.add(new JButton(new NextAction("Next")));     

    setLayout(new BorderLayout());
    add(arrow, BorderLayout.NORTH);
    add(btnPanel, BorderLayout.PAGE_END);
}

private class NextAction extends AbstractAction {
    public NextAction(String name) {
        super(name);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        arrow.next();  // *** call arrow's public next method that you created

        // no need to make a new CardLayout instance
    }
}

private static void createAndShowGui() {
    Main mainPanel = new Main();

    JFrame frame = new JFrame("Iowa Budget Simulation");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.getContentPane().add(mainPanel);
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> createAndShowGui());
}

}

Here is the Arrow class where the container is created

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;

import javax.swing.*;

class Arrow extends JPanel {
    private static final long serialVersionUID = 1L;
    private CardLayout cardLayout = new CardLayout();       // make me a field
    private JPanel cardHolder = new JPanel(cardLayout);     //creates a master JPanel

public Arrow() {
    for (int i = 0; i < 5; i++) {
        cardHolder.add(createCard(i), "card " + i);
    }
    ImagePanel pear = new ImagePanel();
    cardHolder.add(pear, "Pear");
    setLayout(new BorderLayout());
    add(cardHolder, BorderLayout.NORTH);

}

// public method that other objects can call
public void next() {
    cardLayout.next(cardHolder);  // call next on the correct object
}

// simply creates a "pretty" new JPanel
private JComponent createCard(int i) {
    JLabel label = new JLabel("Card " + i);
    label.setFont(label.getFont().deriveFont(Font.BOLD, 50f));

    float h = (float)Math.random();
    Color c = Color.getHSBColor(h, 1f, 1f);
    label.setForeground(c.darker());

    JPanel panel = new JPanel(new GridBagLayout());
    panel.add(label);
    panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
    panel.setBackground(c.brighter().brighter());

    panel.setPreferredSize(new Dimension(400, 300));
    return panel;
}

Here is ImagePanel, my attempt at a 3rd, individual panel/class

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;

import javax.swing.*;

class ImagePanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private String imgString;
    private JLabel imgLabel;

public JComponent ImagePanel() {
    /*
    setName("Pear");
    JLabel john = new JLabel("Pear");   

    float h = (float)Math.random();
    Color c = Color.getHSBColor(h, 1f, 1f);
    john.setForeground(c.darker());

    JPanel panel = new JPanel(new GridBagLayout());
    panel.add(john);
    panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
    panel.setBackground(c.brighter().brighter());
    // Ensure size is correct even before any image is loaded.
    setPreferredSize(new Dimension(400, 300));
    return panel;
    */

    JLabel label = new JLabel("Pear");
    label.setFont(label.getFont().deriveFont(Font.BOLD, 50f));

    float h = (float)Math.random();
    Color c = Color.getHSBColor(h, 1f, 1f);
    label.setForeground(c.darker());

    JPanel panel = new JPanel(new GridBagLayout());
    panel.add(label);
    panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
    panel.setBackground(c.brighter().brighter());

    panel.setPreferredSize(new Dimension(400, 300));
    return panel;
}

There is no error to post, it simply displays a blank panel. Thank you for any assistance I might receive, and I apologize in advance as I am learning Java Swing GUI through YouTube and stack overflow.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Josh
  • 71
  • 1
  • 2
  • 11
  • `ImagePanel()` won't do anything (it will create an empty component), instead, change `public JComponent ImagePanel() {` to `public ImagePanel() {` so you now have a constructor. Remove `JPanel panel = new JPanel(new GridBagLayout());` and simply call `setLayout(new GridBagLayout());` and remove the other references to `panel` and it should start working – MadProgrammer Feb 21 '17 at 06:42

1 Answers1

2

public JComponent ImagePanel() { isn't a constructor, it's a method, to make it work in your code you would have to change ImagePanel pear = new ImagePanel(); to JComponent pear = new ImagePanel().ImagePanel();, but frankly that just doesn't make much sense.

Instead, change public JComponent ImagePanel() { to public ImagePanel() {, now it's the class's constructor

Next, change...

JPanel panel = new JPanel(new GridBagLayout());
panel.add(label);
panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
panel.setBackground(c.brighter().brighter());

panel.setPreferredSize(new Dimension(400, 300));
return panel;

to

setLayout(new GridBagLayout());
add(label);
setBorder(BorderFactory.createLineBorder(c.darker(), 20));
setBackground(c.brighter().brighter());

//panel.setPreferredSize(new Dimension(400, 300));
//return panel;

Don't get me started on why setPreferredSize is a bad idea

Now you can simply use

ImagePanel pear = new ImagePanel();
cardHolder.add(pear, "Pear");
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • To explain why using `setPreferredSize()` is a ba...unwise idea: http://stackoverflow.com/a/26828479/1368690. Basically when you use `setPreferredSize()` you dont allow the component to compute the exact size it needs, which might lead to chopped off parts or extra room. – hamena314 Feb 22 '17 at 13:59
  • 1
    @hamena314 Thanks, I know, it's not that's "bad" or "unwise", but it's overused without thought and overriding `getPreferredSize` is generally a better choice as the container generally has a better idea of how much room it needs – MadProgrammer Feb 22 '17 at 20:36