简体   繁体   中英

How to fill a polygon after drawing

I wanna draw a polygon and then fill it. My code looks like this:

@Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;

        if (polygons.isEmpty()) {
            return;
        }

        for (int j = 0; j < polygons.size(); j++) {

            ArrayList<Point> ActPoint = polygons.get(j);

            if (ActPoint.isEmpty()) {
                return;
        }

        Point a = new Point();
        a = ActPoint.get(0);
        for (int p = 0; p < ActPoint.size(); p++) {
            Point b = ActPoint.get(p);
            Line2D.Double line = new Line2D.Double(a, b);
            g2d.draw(line);
            a = b;
        }

    }


    for (int j = 0; j < polygons.size(); j++) {
        ArrayList<Integer> listX = new ArrayList<>();  
        ArrayList<Integer> listY = new ArrayList<>();

        for (int p = 0; p < polygons.get(j).size(); p++) {
         listX.add(polygons.get(j).get(p).x );
         listY.add(polygons.get(j).get(p).y );
        }
        g.fillPolygon(convertIntegers(listX),convertIntegers (listY), polygons.get(j).size());
    }
}

I don't know how too make the code so it fills the polygon only after i finished drawing it. Like if i wanna have a polygon with 5 sides, the polygon is filled only after i finished drawing all the sides. Also i'd like the polygon to be filled only when i action a button. I tried to make a function

public void fill (Graphics g){
for (int j = 0; j < polygons.size(); j++) {
            ArrayList<Integer> listX = new ArrayList<>();  
            ArrayList<Integer> listY = new ArrayList<>();

            for (int p = 0; p < polygons.get(j).size(); p++) {
             listX.add(polygons.get(j).get(p).x );
             listY.add(polygons.get(j).get(p).y );
            }
                g.fillPolygon(convertIntegers(listX),convertIntegers (listY), polygons.get(j).size());


} 

and i tried to call it here

if (e.getActionCommand().equals("Fill")) {

            }

but i don't really know how. Please help.

PS Is there other ways to fill a polygon without the fillPolygon function?


UPDATE : added Timer-based renderer to display the lines one at a time at the end of this answer.


Firstly, I recommend @Overriding paintComponent() , instead of paint() .

Secondly, to draw a Polygon then fill a Polygon , you literally just stack the commands as the Graphics context will paint in order.

for(int j = 0; j < polygons.size(); j++) {
    ArrayList<Integer> listX = new ArrayList<>();  
    ArrayList<Integer> listY = new ArrayList<>();

    for (int p = 0; p < polygons.get(j).size(); p++) {
        listX.add(polygons.get(j).get(p).x);
        listY.add(polygons.get(j).get(p).y);
    }

    // this may need slight conversion depending on parameters required
    g.drawPolygon(convertIntegers(listX), convertIntegers(listY), polygons.get(j).size());
    g.fillPolygon(convertIntegers(listX), convertIntegers(listY), polygons.get(j).size());
}

If you override paintComponent() for your chosen object (I usually use a JPanel for custom painting) all you then have to do is call repaint() to refresh the view (not that you should need in this instance).

To recap, override paintComponent() on a JPanel , stack your drawPolygon / fillPolygon calls and if you want to control when your polygon is displayed, handle that by adding / removing the JPanel as necessary from your application. Or set a boolean flag that indicates "toBeDrawn" or not and modify your paintComponent code so that it only draws the polygons when this is set to true.


UPDATE : example runnable class below demonstrated Timer-based drawLine() functionality.


import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test extends JPanel {

    private static final long serialVersionUID = 1L;

    private Timer lineTimer;

    private Polygon toBeFilled;
    private ArrayList<Point[]> inactiveLines;
    private ArrayList<Point[]> activeLines;
    private boolean toBeDrawn = false;

    public static void main(String[] args) {
        JFrame frame = new JFrame("Test");
        frame.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

        Test test = new Test();
        frame.add(test);
        frame.pack();
        frame.setVisible(true);

        test.getLineTimer().start();
    }

    public Test() {
        super();

        setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
        setPreferredSize(new Dimension(480, 340));
        setBackground(Color.BLACK);

        int midpointX = getPreferredSize().width / 2;
        int midpointY = getPreferredSize().height / 2;
        int lineWidth = 20;

        // let's make a square
        toBeFilled = new Polygon();
        // let's centre this square nicely
        toBeFilled.addPoint(midpointX - (lineWidth / 2), midpointY - (lineWidth / 2)); // top-left
        toBeFilled.addPoint(midpointX + (lineWidth / 2), midpointY - (lineWidth / 2)); // top-right
        toBeFilled.addPoint(midpointX + (lineWidth / 2), midpointY + (lineWidth / 2)); // bottom-right
        toBeFilled.addPoint(midpointX - (lineWidth / 2), midpointY + (lineWidth / 2)); // bottom-left

        inactiveLines = new ArrayList<Point[]>();
        activeLines = new ArrayList<Point[]>();
        for(int n = 0; n < 4; n++) {
            Point[] points = new Point[2];
            if(n < 3) {
                points[0] = new Point(toBeFilled.xpoints[n], toBeFilled.ypoints[n]);
                points[1] = new Point(toBeFilled.xpoints[n + 1], toBeFilled.ypoints[n + 1]);
            } else {
                // loop back to the first point in the array
                points[0] = new Point(toBeFilled.xpoints[n], toBeFilled.ypoints[n]);
                points[1] = new Point(toBeFilled.xpoints[0], toBeFilled.ypoints[0]);
            }

            inactiveLines.add(points);
        }

        ActionListener lineAction = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(inactiveLines.get(inactiveLines.size() - 1) != null) {
                    int count = 0;
                    for(Point[] pArray : inactiveLines) {
                        if(pArray != null) {
                            activeLines.add(new Point[] { pArray[0], pArray[1] });
                            inactiveLines.set(count, null);
                            repaint();
                            break;
                        }

                        count++;
                    }
                } else {
                    // we've exhausted the line array, so now it's time to fill it
                    toBeDrawn = true;
                    lineTimer.stop();
                    repaint();
                }
            }           
        };

        lineTimer = new Timer(1000, lineAction);
    }

    @Override
    public void paintComponent(Graphics g) {
        // useful for animation
        Toolkit.getDefaultToolkit().sync();
        super.paintComponent(g);
        if(toBeDrawn) {
            doFillPainting(g);
        } else {
            doLinePainting(g);
        }
    }

    private void doFillPainting(Graphics g) {
        // Graphics2D is more advanced than the older Graphics API, and more reliable
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.WHITE);
        if(toBeFilled != null) {
            g2d.fillPolygon(toBeFilled);
        }
    }

    private void doLinePainting(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.WHITE);
        for(Point[] activeLine : activeLines) {
            g2d.drawLine(activeLine[0].x, activeLine[0].y, activeLine[1].x, activeLine[1].y);
        }
    }

    public Timer getLineTimer() {
        return lineTimer;
    }

    public void setLineTimer(Timer lineTimer) {
        this.lineTimer = lineTimer;
    }

    public Polygon getToBeFilled() {
        return toBeFilled;
    }

    public void setToBeFilled(Polygon toBeFilled) {
        this.toBeFilled = toBeFilled;
    }

    public boolean isToBeDrawn() {
        return toBeDrawn;
    }

    public void setToBeDrawn(boolean toBeDrawn) {
        this.toBeDrawn = toBeDrawn;
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM