0

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

yerpy
  • 1,366
  • 3
  • 17
  • 44
  • 1
    Where is the `MyComponent` class? – Jonah Mar 21 '16 at 19:12
  • There is nothing wrong, already test it a lot of times. it might be even empty drawing class extended from JComponent. It can draw even : public void paintComponent(Graphics g) { g.drawString("Hello world", MESSAGE_X, MESSAGE_Y); } and it will show it on my panel if i add it like i did without dividing for left and right panel. – yerpy Mar 21 '16 at 19:16
  • Would need to see the MyComponent class. – ManoDestra Mar 21 '16 at 19:41
  • @DerpyUnKnown `After choose from JComboBox list and press Start/Restart, the right panel doesnt update.` What do you mean by "doesn't update" ? Is the panel added by not updating the drawing or it is not added at all? – user3437460 Mar 21 '16 at 19:58
  • @DerpyUnKnown By the way, do you know you can accept answers which solves your problem? It will be good if you can accept some answers for your previous posts (which solves your problems). A record of zero accepted answer may turn away some potential solution providers. – user3437460 Mar 21 '16 at 20:00
  • Well i think its added, but doesnt updating the right panel, after add(new MyComponent() i added revalidate and repaint, but still no effect ;/ – yerpy Mar 21 '16 at 20:03
  • Yes i know, but i can not till i dont get enough reputation ;( – yerpy Mar 21 '16 at 20:05
  • @DerpyUnKnown, `Well i think its added,` did you verify this??? Did you add a System.out.println(...) to the if statement to see if the code is being executed??? `i added revalidate and repaint,` - that is only half the solution. Also, see my updated suggestion. – camickr Mar 21 '16 at 20:34
  • Yes the code is executed. Half ? What can I do yet ? – yerpy Mar 21 '16 at 20:40
  • You can check mine and @camickr's updated answers for a fix to the problem – Jonah Mar 21 '16 at 20:55
  • Please use a http://sscce.org/ – Charlie Mar 21 '16 at 21:26

2 Answers2

3

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • how can i return the size of the component ? return new Dimension(screenWidth, screenHeight); i Overrided this method and its not working ;/ – yerpy Mar 21 '16 at 20:53
  • I will follow on your advices, Thanks!! – yerpy Mar 22 '16 at 08:48
1

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);
}
Community
  • 1
  • 1
Jonah
  • 1,013
  • 15
  • 25
  • Did you solve the issue or not? Because you have marked an answer as accepted, which means that it solved the problem, but you never gave any indication to whether it is solved or not. – Jonah Mar 21 '16 at 20:10
  • Nope, sorry. I am new there. I used revalidation and repaint after adding the component to the panel, but its not working. – yerpy Mar 21 '16 at 20:14
  • Thank you, did it! – yerpy Mar 21 '16 at 20:18
  • What about the Start Button ? rightPanel.add(new MyComponent()); rightPanel.revalidate(); rightPanel.repaint(); – yerpy Mar 21 '16 at 20:59
  • Yes, I did mention that in the first link of the answer. Just didn't put a code example. :) – Jonah Mar 21 '16 at 21:00
  • Yes, but i have 3 panels right now, how can i use the same size for each Panel ? I did edition on MyPanel code. – yerpy Mar 21 '16 at 21:09
  • Set each one to the `screenWidth / 3` by overriding the `getPreferredSize()` – Jonah Mar 21 '16 at 21:15
  • Yeah, did it, and still doesnt show me MyComponent stuffs ;/ – yerpy Mar 21 '16 at 21:18
  • The preferred size would NOT be the size of the frame. The preferred size should be the size of the custom painting that is done on the component. – camickr Mar 21 '16 at 21:23
  • @DerpyUnKnown, [Here](http://pastebin.com/9ChpFas8) is a link to my classes. This currently gives me the results I believe you are looking for – Jonah Mar 21 '16 at 21:25
  • @DerpyUnKnown, That code is still sloppy and should not be used as a basis for learning. The getPreferredSize() method is wrong as I have already mentioned. Using "BorderLayout.CENTER" on a panel using a FlowLayout is wrong. You should NOT be using the setPreferredSize() method to hardcode sizes. It is the job of the layout manager to determine the size. It might work in this situation but it still shows a lack of understanding on how layout managers work and will cause you problems in the future. – camickr Mar 21 '16 at 21:40
  • I didn't even see those `setPreferredSize()` methods for the right and left panels. Will edit that code – Jonah Mar 21 '16 at 21:42