문제

I am trying to make a program that has a window which displays a polygon and two buttons. The polygon starts at 3 points (a triangle) and allows the user to press a "+" and "-" button to add or subtract sides of the polygon. Here is my code:

In TestPolygonBox:

package testpolygonbox
import javax.swing.*;
import java.awt.*;
public class TestPolygonBox extends JFrame {


public TestPolygonBox(){
    setLayout(new BorderLayout(5,5));
    add(new PolygonBox ());
}
public static void main(String[] args) {
    TestPolygonBox frame = new TestPolygonBox();
    frame.setTitle("Polygon Box");
    frame.setSize(400,420);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

}
}

next there is the control class:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class PolygonBox extends JPanel {
private JButton jbtEnlarge = new JButton("+");
private JButton jbtShrink = new JButton("-");
private PolygonPanel polygonPanel = new PolygonPanel();

public PolygonBox(){
    JPanel panel = new JPanel();
    panel.add(jbtEnlarge);
    panel.add(jbtShrink);
     setLayout(new BorderLayout());
    this.add(polygonPanel,BorderLayout.CENTER);
    this.add(panel, BorderLayout.SOUTH);

    jbtEnlarge.addActionListener(new EnlargeListener());
    jbtShrink.addActionListener(new ShrinkListener());
}


class EnlargeListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
    polygonPanel.enlarge();
   }
}
class ShrinkListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
    polygonPanel.shrink();
}
}
}

class PolygonPanel extends JPanel{
private int polygonSides = 3;

/** Add side to the polygon*/
public void enlarge(){
    polygonSides++;
    repaint();
}
public void shrink(){
    polygonSides--;
    repaint();
}
  @Override /** Draw requested Shape*/
protected void paintComponent(Graphics g){

    int frameWidth = getWidth() / 2;
    int frameHeight = getHeight() / 2;
    int radius = (int)(Math.min(getWidth(),getHeight())* 0.4);
    int xCenter = getWidth() / 2;
    int yCenter = getHeight() / 2;


    g.setColor(Color.BLUE);
    Polygon polygon = new Polygon();

    polygon.addPoint(xCenter + radius, yCenter);
                polygon.addPoint((int)(xCenter + radius * Math.cos(2 * Math.PI/polygonSides)),
                        (int)(yCenter - radius * Math.sin(2 * Math.PI / polygonSides)));
                for (int polygonPoint = 2; polygonPoint <= polygonSides; polygonPoint++){
                    polygon.addPoint((int)(xCenter + radius * Math.cos(polygonPoint * 2 * Math.PI/polygonSides)),
                        (int)(yCenter - radius * Math.sin(polygonPoint * 2 * Math.PI / polygonSides)));
                }

    g.fillPolygon(polygon);
}


}

When i try to run this program i get the error: Exception in thread "main" java.lang.IllegalArgumentException: adding a window to a container at java.awt.Container.checkNotAWindow(Container.java:483) at java.awt.Container.addImpl(Container.java:1084) at java.awt.Container.add(Container.java:998) at javax.swing.JFrame.addImpl(JFrame.java:562) at java.awt.Container.add(Container.java:410) at testpolygonbox.TestPolygonBox.(TestPolygonBox.java:21) at testpolygonbox.TestPolygonBox.main(TestPolygonBox.java:24) Java Result: 1

if anyone could tell me where i am adding a window to a container please? Im not sure what im doing wrong.

도움이 되었습니까?

해결책

PolygonBox is a JFrame window but you're adding it to another JFrame. Change the class so it extends JPanel instead.

public class PolygonBox extends JPanel {

다른 팁

There are 4 severe problems with your code.

  • You are not executing the Swing code in the Event dispatch thread (EDT). Your main has to look like this:

    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                initializeGUI();
            }
        }
    }
    

    This is very important even the Swing Hello World - the simplest Swing program - does it. If you want to know why this has to be like this read this concurrency tutorial. In short, If you don't do this properly once your program gets bigger and more complex you'll see a lot of inconsistent, non-reproducible exceptions and bugs that occur in the Swing classes and you can't track down.

  • Second, as stated by Reimeus, you can't put a frame inside another frame, PolygonBox has to be a JPanel.

  • Third you are not populating the panels correctly. Look at this code:

    JPanel panel = new JPanel();
    panel.add(jbtEnlarge);
    panel.add(jbtShrink);
    

    This code looks weird, and it is. The question that pops up when you see it is: "Where are those buttons added?" Well in the panel of course, but where in the panel? That depends of the layout that the panel is using. And what is the layout of that panel? Well since you didn't explicitly specify one it is using the default layout for JPanels: the BorderLayout. With the border layout panel.add(component); is equivalent to panel.add(component, BorderLayout.CENTER);. However you can't put two components in the CENTER, you can put a panel with a lot of components or whatever, but you can't directly put two components, that is why that code doesn't work. Then how do you populate the panel? Pick a layout learn to use it and then add the components in a proper way. For example I'll do this with the GridLayout.

    JPanel panel = new JPanel(new GridLayout(1, 2));
    panel.add(_enlargeButton);
    panel.add(_shrinkButton);
    

    With the Grid layout because I said that I want a grid 1x2, those adds are correct because the panel knows now that he has to put the components in each cell of the grid.

  • Lastly you will see that there are painting problems: the polygons are not erased, they are painted one over the other, adn you might see the image of the buttons in the panel... This is because you have to call super.paintComponent(g) in your paintComponent method. Thing is that code paints a polygon, yes, but you also have to do all the other work the component was doing for painting itself, so the first thing you have to do is call the original code you are overriding and then paint your component. For an extensive tutorial of why this works like this see Painting in AWT and Swing.

With all that, changing some variables names to follow the Java conventions and reformatting the code for a better organization. This is your fixed program:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class TestPolygonBox extends JFrame
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() { //Error 1: executing Swing code outside the EDT fixed
            public void run()
            {
                TestPolygonBox frame = new TestPolygonBox();
                frame.setVisible(true);
            }
        });
    }

    public TestPolygonBox()
    {
        super("Polygon Box"); //this is JFrame("title") since we are extending a frame
        setLayout(new BorderLayout());//this line doesn't actually do nothing since the frame already usesk BorderLayout by default

        add(buildPolygonBoxPanel());

        setSize(400, 420);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }


    private JPanel buildPolygonBoxPanel() //Error 2: PolygonBox has to be a panel, also I made it into a mthod returning the panel instead of a whole class since it was unnecessary.
    {
        JPanel polygonBox = new JPanel(new BorderLayout());

        _polygonPanel = new PolygonPanel();

        JPanel buttonsPanel = new JPanel(new GridLayout(1, 2)); //Error 4 adding the buttons properly to a panel.
        _enlargeButton = new JButton("+1");
        _enlargeButton.addActionListener(new EnlargeListener());
        _shrinkButton = new JButton("-1");
        _shrinkButton.addActionListener(new ShrinkListener());
        buttonsPanel.add(_enlargeButton);
        buttonsPanel.add(_shrinkButton);

        polygonBox.add(_polygonPanel, BorderLayout.CENTER);
        polygonBox.add(buttonsPanel, BorderLayout.SOUTH);

        return polygonBox;
    }

    class EnlargeListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            _polygonPanel.enlarge();
        }
    }

    class ShrinkListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            _polygonPanel.shrink();
        }
    }

    private JButton _enlargeButton;
    private JButton _shrinkButton;
    private PolygonPanel _polygonPanel;
}

class PolygonPanel extends JPanel
{
    private int _polygonSides = 3;

    /** Add side to the polygon */
    public void enlarge()
    {
        _polygonSides++;
        repaint();
    }

    public void shrink()
    {
        if (_polygonSides > 3) _polygonSides--;
        repaint();
    }

    @Override
    /** Draw requested Shape*/
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g); //Error 4 fixed, call super.paintComponent

        int radius = (int) (Math.min(getWidth(), getHeight()) * 0.4);
        int xCenter = getWidth() / 2;
        int yCenter = getHeight() / 2;

        g.setColor(Color.BLUE);
        Polygon polygon = new Polygon();

        polygon.addPoint(xCenter + radius, yCenter);
        polygon.addPoint((int) (xCenter + radius * Math.cos(2 * Math.PI / _polygonSides)), (int) (yCenter - radius * Math.sin(2 * Math.PI / _polygonSides)));
        for (int polygonPoint = 2; polygonPoint <= _polygonSides; polygonPoint++)
        {
            polygon.addPoint((int) (xCenter + radius * Math.cos(polygonPoint * 2 * Math.PI / _polygonSides)), (int) (yCenter - radius * Math.sin(polygonPoint * 2 * Math.PI / _polygonSides)));
        }

        g.fillPolygon(polygon);
    }
}

Just copy and execute it and it looks like this:

TestPolygonBox

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top