yerpy
yerpy

Reputation: 1446

Can not add JComponent to JPanel

Have problem with adding class extended from JComponent to MyPanel class. After choose from JComboBox list and press Start/Restart, the right panel doesnt update. Mean after adding to the Panel MyComponent class where is all drawing stuff. If someone can take a look and tell me when i am doing the mistakes or if its the different way to do that, please help me :)!

Run app class :

import javax.swing.JFrame;

public class RunApp {

    public static void main(String[] args) {

        JFrame mainFrame = new MyPanel();
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        mainFrame.setVisible(true);


    }

}

MyPanel class :

    import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;



public class MyPanel extends JFrame {

    private JPanel leftPanel = null;
    private JPanel rightPanel = null;
    private JPanel mainPanel = null;
    private JButton start = null;
    private JButton restart = null;
    private JComboBox<String> menuBox = new JComboBox<>();
    private Toolkit kit = Toolkit.getDefaultToolkit();
    private Dimension screenSize = kit.getScreenSize();
    private int screenHeight = screenSize.height;
    private int screenWidth = screenSize.width;

    public MyPanel() {

        mainPanel = new JPanel();

        mainPanel.setBackground(Color.orange);
        mainPanel.setPreferredSize(getPreferredSize());

        leftPanel = new JPanel();
        leftPanel.setBackground(Color.blue);
        leftPanel.setPreferredSize(new Dimension(screenWidth/6, screenHeight));

        menuBox.addItem("Gaussian Wave - non Dispersive");
        menuBox.addItem("Gaussian Wave - Dispersive");

        start = new JButton("Start");
        restart = new JButton("Restart");

        leftPanel.add(menuBox);
        leftPanel.add(start);
        leftPanel.add(restart);


        rightPanel = new JPanel();
        rightPanel.setBackground(Color.red);
        rightPanel.setPreferredSize(new Dimension(screenWidth -( screenWidth/5 ), screenHeight));

        start.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                if(menuBox.getItemAt(menuBox.getSelectedIndex()).equals("Gaussian Wave - non Dispersive")) {

                    rightPanel.add(new MyComponent());
                    rightPanel.revalidate();
                    rightPanel.repaint();


                } else if(menuBox.getItemAt(menuBox.getSelectedIndex()).equals("Gaussian Wave - Dispersive")) {

                    rightPanel.add(new MyComponent());
                    rightPanel.revalidate();

                    rightPanel.repaint();
                }
            }
        });


        restart.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                rightPanel.removeAll();
                rightPanel.revalidate();
                rightPanel.repaint();
                rightPanel.setBackground(Color.RED);
            }
        });

        mainPanel.add(leftPanel);
        mainPanel.add(rightPanel);
        add(mainPanel);



    }

    @Override
    public Dimension getPreferredSize() {

        return new Dimension(screenWidth, screenHeight);
    }

}

Like i say the MyComponent class is not working when i add it in this way. Normally when i add this class directly like :

public MyPanel() {

    add(new MyComponent);

}

Working perfect, but i want to add it after choose from the list to the divided screen. Thx !

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.util.function.Function;

import javax.swing.JComponent;

public class MyComponent extends JComponent {

private int wx, wy;

    private double xMin, xMax, yMin, yMax, xInc, time;



    private Function<Double, Double>gaussFunction;
    private Function<Double, Double>dispersiveGaussFunction;

    public MyComponent() {
        init();
    }


    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        makeGraphics(g2);

    }

    private void makeGraphics(Graphics2D g2) {

        GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
        if(time < 5) {
            countGaussianWave(this.time);

            double x = xMin;
            double y = gaussFunction.apply(x);


                path.moveTo(
                        mapX(x), mapY(y)
                        );
                x+=xInc;

                while(x < xMax) {
                    y = gaussFunction.apply(x);
                    path.lineTo(
                            mapX(x), mapY(y)
                            );
                        x+=xInc;
                }
                g2.draw(path);
                repaint();
                this.time+=0.001;

                if(this.time > 3.5) {
                    this.time = -3.5;

                    System.out.println(time);
                }
            }


    }


    private void init() {
        wx = 700;
        wy = 700;
        xMin = -1;
        xMax = 1;
        yMin = -1;
        yMax = 1;
        xInc = 0.01;
        setTime(time);
    }

    private double mapX(double x) {
        double fx = wx / 2;
        double sx = wx / (xMax - xMin);

        return x * fx + sx;
    }

    private double mapY(double y) {
        double fy = wy / 2;
        double sy = wy / (yMax - yMin); 

        return -y * sy + fy;
    }

    public void countGaussianWave(double time) {

        double lambda = 1;

        this.gaussFunction = x -> {
                return x = Math.exp(-(Math.pow((x-time ), 2)))
                        * (Math.cos((2*Math.PI*(x-time))/lambda)
                                + Math.sin((2*Math.PI*(x-time))/lambda)); // need complex
        };
    }

//  public void countDispersiveGaussianWave(double time) {
//      
//      double lambda = 1;
//      double k = (2 * Math.PI) / lambda;
//      
//      this.dispersiveGaussFunction = x -> {
//          return x = (1/(Math.sqrt(1 + 2 * time)) * 
//                  Math.exp(-(Math.pow((1 / Math.pow(1 + 4 * time, 2)) * (x - k * time), 2)))
//                  * Math.exp(Math.pow(, b));
//                  );
//      };
//  }

    public double getTime() {
        return time;
    }

    public void setTime(double time) {
        this.time = time;
    }


}

app ss

Upvotes: 0

Views: 1256

Answers (2)

camickr
camickr

Reputation: 324128

Don't use "==" when comparing objects.

Instead you should be using the equals(...) method.

When you add (or remove) a component to a visible GUI the basic code is:

panel.add(...);
panel.revalidate();
panel.repaint();

Basically you need to make sure the layout manager is invoked otherwise the component has a size of (0, 0) so there is nothing to paint.

Also, you need to override the getPreferredSize() method to return the size of the component. Otherwise the size is (0, 0) so there is nothing to paint.

Edit

I'm guessing your components isn't showing because of your poor GUI design and hardcoding of values. A FlowLayout is a terrible layout to use for ALL the components added to the frame. You need to make an effort to logically organize the components on panels with appropriate layout managers. When lots of components are added the components will wrap to a second row. However, the preferred size does not automatically change so you may not see all the components. So

rightPanel.setPreferredSize(new Dimension(...) );

Don't hardcode a preferred size. Each component is responsible for determining its own size which is why you override the getPreferredSize() method. Then the layout manages can do their job properly. So get rid of all the setPreferrededSize() statements.

The default layout for a Jframe is a BorderLayout. I would stick with that layout. There is no need for your mainPanel as the content pane for the frame is already a JPanel.

So I would rename your "leftPanel" and maybe call it "topPanel". Then you can just add the fixed components to that panel and add that panel to the frame:

JPanel topPanel = new JPanel();
topPanel.add( comboBox );
topPanel.add( startButton );
topPanel.add( restartButton );
frame.add(topPanel, BorderLayout.PAGE_START);

So these components will appear at the top of the frame.

Now there is also no need for the "rightPanel". Instead you can just add your component directly to the frame.

frame.add( new MyComponent(), BorderLayout.CENTER);
frame.revalidate();
frame.repaint();

This component will now appear in the center of the frame and take up all the extra space available in the frame.

Upvotes: 3

Jonah
Jonah

Reputation: 1003

To start, you can simplify the start buttons ActionListener logic like so

if(combobox.getSelectedItem().equals("Text")
{
    doSomething();
}

Also, after adding or removing new components, you need to call Revalidate & Repaint

If you're trying to paint in one of the components, make sure to @Override it and call it's super method super.paintComponent(g);

You also have 2 action listeners assigned to the same button. I suggest removing one of those

Along with @Camickr's answer of Overriding the getPreferredSize() method, you should change the restart button's ActionListener to this

rightPanel.removeAll();
rightPanel.revalidate();
rightPanel.repaint();
rightPanel.setBackground(Color.RED);

You can Override the getPreferredSize(); method like so:

@Override
public Dimension getPreferredSize()
{
    int width = Toolkit.getDefaultToolkit().getScreenSize().width / 2;
    int height = Toolkit.getDefaultToolkit().getScreenSize().height;
    return new Dimension(width, height);
}

Upvotes: 1

Related Questions