在Java上扩展JFrame的类上绘画

时间:2018-01-27 14:07:39

标签: java swing graphics jframe jpanel

我是Java图形的新手,我试图创建一个简单的十字路口GUI界面,上面有4个红绿灯,当我使用我创建的以下类时 - 我得到一个窗口它上面有一个大的灰色矩形(我假设因为我没有在中心分配一个红绿灯,它已经填充了默认的灰色背景),我如何控制JFrame中心的大小?

这就是我想要实现的目标: enter image description here

这就是我得到的: enter image description here

这是JFrame类。

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

public class CrossroadInterface extends JFrame /*implements IAppInterface*/ {
private static final int WIDTH_OF_WINDOW = 400;
private static final int HEIGHT_OF_WINDOW = 400;

//Panels
TrafficLight tLightW, tLightC, tLightE, tLightS, tLightN;

//Other
public CrossroadInterface() {
    super("My Crossroad");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(WIDTH_OF_WINDOW, HEIGHT_OF_WINDOW);
    this.setVisible(true);
    createInterface();
}

public void createInterface () {    
    tLightW = new TrafficLight();
    tLightE = new TrafficLight();
    tLightS = new TrafficLight();
    tLightN = new TrafficLight();
    this.add(tLightW, BorderLayout.WEST);
    this.add(tLightN, BorderLayout.NORTH);
    this.add(tLightE, BorderLayout.EAST);
    this.add(tLightS, BorderLayout.SOUTH);
 }
}

这是Jpanel类。

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;

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

public class TrafficLight extends JPanel {
    private final Color offRed = new Color(128, 0, 0);
    private final Color offGreen = new Color(0, 96, 0);
    private static final int CAR_DIAMETER = 50;
    private static final int PERSON_HEIGHT = 100;
    private static final int PERSON_WIDTH = 50;
    private int status;
    public TrafficLight() {
        super();
        this.setSize(CAR_DIAMETER, 120);
        this.setBackground(Color.BLACK);
        status = 0;
        this.setVisible(true);
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(offRed);
        g.fillOval(this.getX(), this.getY(), CAR_DIAMETER, CAR_DIAMETER);
        g.setColor(offGreen);
        g.fillOval(this.getX(), this.getY()+CAR_DIAMETER, CAR_DIAMETER, CAR_DIAMETER);
        g.setColor(offRed);
        g.fillRect(this.getX(), this.getY()+CAR_DIAMETER+PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
        g.setColor(offGreen);
        g.fillRect(this.getX(), this.getY()+CAR_DIAMETER+2*PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
        //drawIlluminatedLights(g);
        System.out.println(this.getX()+" "+this.getY());
    }
}

编辑: 继Hovercraft充满鳗鱼'建议,这是我的新课程:

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

public class CrossroadInterface extends JFrame /*implements IAppInterface*/ {
private static final int WIDTH_OF_WINDOW = 900;
private static final int HEIGHT_OF_WINDOW = 900;

//Panels
TrafficLight tLightW, tLightC, tLightE, tLightS, tLightN;

//Other
public CrossroadInterface() {
    super("My Crossroad");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(WIDTH_OF_WINDOW, HEIGHT_OF_WINDOW);
    setLayout(new GridLayout(3,3));
    createInterface();
}

public void createInterface () {    
    tLightW = new TrafficLight();
    tLightE = new TrafficLight();
    tLightS = new TrafficLight();
    tLightN = new TrafficLight();
    this.add(new JPanel());
    this.add(tLightW);
    this.add(new JPanel());
    this.add(tLightN);
    this.add(new JPanel());
    this.add(tLightE);
    this.add(new JPanel());
    this.add(tLightS);
    this.setVisible(true);
 }
}

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;

public class TrafficLight extends JPanel {
    private final Color offRed = new Color(128, 0, 0);
    private final Color offGreen = new Color(0, 96, 0);
    private static final int CAR_DIAMETER = 50;
    private static final int PERSON_HEIGHT = 50;
    private static final int PERSON_WIDTH = 50;
    private int status;
    public TrafficLight() {
        super();
        status = 0;
        this.setPreferredSize(new Dimension(CAR_DIAMETER,2*CAR_DIAMETER+2*PERSON_HEIGHT));
        this.setVisible(true);
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(offRed);
        g.fillOval(100, 50, CAR_DIAMETER, CAR_DIAMETER);
        g.setColor(offGreen);
        g.fillOval(100, 50+CAR_DIAMETER, CAR_DIAMETER, CAR_DIAMETER);
        g.setColor(offRed);
        g.fillRect(100, 50+CAR_DIAMETER+PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
        g.setColor(offGreen);
        g.fillRect(100, 50+CAR_DIAMETER+2*PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
        //drawIlluminatedLights(g);
    }
}

enter image description here

1 个答案:

答案 0 :(得分:3)

你的问题不是JFrame的中心太大,而是因为你周围的JPanel的大小太小了。了解大多数Swing布局管理器都尊重组件首选大小,并使用它来设置组件的大小。您的其他问题包括

  • 使用getX()getY()放置图纸。这些值给出了JPanel在其容器中的位置,但这不会帮助您放置绘图,因为当您在JPanel中绘制时,绘图的位置相对于JPanel内的像素位置而不是其容器放置,因此使用这些方法会搞砸你。
  • 在添加所有组件之前调用JFrame的setVisible(true) 。这可能无法显示所有组件。
  • 使您的TrafficLight类扩展JPanel。使用单个JPanel完成所有绘图并使TrafficLight类不从任何Swing组件扩展而是扩展为逻辑类,你会好得多。给它一个public void draw(Graphics2D g2)方法,你可以在绘图JPanel的paintComponent方法中调用它。

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.swing.*;

@SuppressWarnings("serial")
public class CrossRoads2 extends JPanel {
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private static final int TIMER_DELAY = 100;
    List<TrafficLight2> lights = new ArrayList<>();

    public CrossRoads2() {
        // create a timer to randomly change traffic light state
        // and start it
        new Timer(TIMER_DELAY, new TimerListener()).start();

        // create 4 TrafficLight2 objects and place them at 4
        // compass locations, and add to lights ArrayList
        int x = (PREF_W - TrafficLight2.getWidth()) / 2;
        int y = 0;
        lights.add(new TrafficLight2(x, y));
        x = 0;
        y = (PREF_H - TrafficLight2.getHeight()) / 2;
        lights.add(new TrafficLight2(x, y));
        x = (PREF_W - TrafficLight2.getWidth());
        lights.add(new TrafficLight2(x, y));
        x = (PREF_W - TrafficLight2.getWidth()) / 2;
        y = (PREF_H - TrafficLight2.getHeight());
        lights.add(new TrafficLight2(x, y));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // cast g into a Graphics2 object
        Graphics2D g2 = (Graphics2D) g;

        // for smooth rendering
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // iterate through the ArrayList, calling the draw method on each light 
        for (TrafficLight2 light : lights) {
            light.draw(g2);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        // give our JPanel a decent size
        return new Dimension(PREF_W, PREF_H);
    }

    // ActionListener that randomly changes the LightState of each traffic light
    private class TimerListener implements ActionListener {
        private Random random = new Random();

        @Override
        public void actionPerformed(ActionEvent e) {
            for (TrafficLight2 light : lights) {
                // random number 0 to 2
                int randomIndex = random.nextInt(LightState.values().length);

                // get one of the LightStates using the index above
                LightState lightState = LightState.values()[randomIndex];
                // set our light to this state
                light.setLightState(lightState);
            }
            repaint();
        }
    }

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

        JFrame frame = new JFrame("Cross Roads");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

class TrafficLight2 {
    private static final int ELLIPSE_W = 40;
    private static final int GAP = 4;
    private int x;
    private int y;
    private LightState lightState = LightState.RED; // what color is bright

    // map to hold our 3 ellipses, each one corresponding to a LightState
    private Map<LightState, Shape> lightMap = new EnumMap<>(LightState.class);

    public TrafficLight2(int x, int y) {
        // create 3 ellipses, one each for RED, YELLOW, GREEN
        // place each one below the previous
        // associate each one with one of our RED, YELLOW, or GREEN LightStates
        // putting the Ellipse into the map with the light state as key
        this.x = x;
        this.y = y;
        int tempX = x + GAP;
        int tempY = y + GAP;
        lightMap.put(LightState.RED, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
        tempY += ELLIPSE_W + GAP;
        lightMap.put(LightState.YELLOW, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
        tempY += ELLIPSE_W + GAP;
        lightMap.put(LightState.GREEN, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
    }

    // called by JPanel's paintComponent
    public void draw(Graphics2D g2) {
        // iterate through the 3 LightStates
        for (LightState ltSt : LightState.values()) {
            // if the ltSt in the for loop is this traffic light's LightState
            // then the display color should be bright
            Color c = ltSt == lightState ? ltSt.getColor() : 
                // other wise the display color should be very dark
                ltSt.getColor().darker().darker().darker();
            g2.setColor(c);
            g2.fill(lightMap.get(ltSt)); // fill the oval with color
            g2.setColor(Color.BLACK);
            g2.draw(lightMap.get(ltSt));  // draw a black border
        }
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public LightState getLightState() {
        return lightState;
    }

    public void setLightState(LightState lightState) {
        this.lightState = lightState;
    }

    // static method for the width of our traffic lights
    public static int getWidth() {
        return 2 * GAP + ELLIPSE_W;
    }

    // static method for the height of our traffic lights
    public static int getHeight() {
        return 4 * GAP + 3 * ELLIPSE_W;
    }
}

// enum that encapsulates the 3 possible states of the traffic light
enum LightState {
    RED("Red", Color.RED), YELLOW("Yellow", Color.YELLOW), GREEN("Green", Color.GREEN);

    private LightState(String text, Color color) {
        this.text = text;
        this.color = color;
    }

    private String text;
    private Color color;

    public String getText() {
        return text;
    }
    public Color getColor() {
        return color;
    }    
}