简体   繁体   中英

My method is called, but it does not draw the lines

Below is my code to draw a swimming pool and at the same time calculate its volume.

The method in question is paintSwimmingPool(), which works fine when called by stateChanged() listener method. However, the problem is that I want to draw the rectangle upon launching the program. I have added in some console message to help debug which tells me that the method is called correctly from createGUI() method. But why paintSwimmingPool() does not draw anything on the panel? Sorry I have spent quite some time on solving this but got no where.

Thank you in advance for any pointers.

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SwimingPoolCalculator implements ChangeListener {

    private JFrame frame;
    private JPanel primaryJPanel, drawingJPanel;
    private JLabel deepJLabel, shallowJLabel;
    private JSlider deepJSlider, shallJSlider;
    private JTextField resultTextField;

    final private int xPos = 20;
    final private int yPos = 20;
    final private int swimmingPoolLength = 200;
    final private int swimmingPoolWidth = 50;

    public static void main(String[] args) {

        SwimingPoolCalculator swimingPoolCalculator = new SwimingPoolCalculator();

        swimingPoolCalculator.createGUI();

    }

    private void createGUI(){

        frame = new JFrame("Swiming Pool Calculator");

        primaryJPanel = new JPanel();
        primaryJPanel.setPreferredSize(new Dimension(250, 500));

        drawingJPanel = new JPanel();
        drawingJPanel.setPreferredSize(new Dimension(250, 300));
        drawingJPanel.setBackground(Color.yellow);

        shallowJLabel = new JLabel("S End");
        deepJLabel = new JLabel("D End");

        shallJSlider = new JSlider(JSlider.HORIZONTAL, 10, 100, 10);
        deepJSlider = new JSlider(JSlider.HORIZONTAL, 50, 200, 100);

        shallJSlider.addChangeListener(this);
        deepJSlider.addChangeListener(this);

        resultTextField = new JTextField(15);

        primaryJPanel.add(drawingJPanel);
        primaryJPanel.add(shallowJLabel);
        primaryJPanel.add(shallJSlider);
        primaryJPanel.add(deepJLabel);
        primaryJPanel.add(deepJSlider);
        primaryJPanel.add(resultTextField);

        frame.getContentPane().add(primaryJPanel);
        frame.pack();
        frame.setVisible(true);

        // why the first call does not draw any line?
        paintSwimmingPool(deepJSlider.getValue(), shallJSlider.getValue());

    }

    private void paintSwimmingPool(int deepEnd, int shallowEnd){

        Graphics drawingBoard = drawingJPanel.getGraphics();

        drawingBoard.setColor(Color.yellow);
        drawingBoard.fillRect(0, 0, 250, 250);
        drawingBoard.setColor(Color.black);

        drawingBoard.drawLine(xPos, yPos, xPos + swimmingPoolLength, yPos);  // the top line
        drawingBoard.drawLine(xPos, yPos, xPos, yPos + deepEnd); // the left line
        drawingBoard.drawLine(xPos + swimmingPoolLength, yPos, xPos + swimmingPoolLength, yPos + shallowEnd); // the right line
        drawingBoard.drawLine(xPos, yPos + deepEnd, xPos + swimmingPoolLength, yPos + shallowEnd); // the bottom line

    }

    private void calculateVolume(double averageDepth){

        int swimmingPoolVolume = (int)(averageDepth * swimmingPoolLength * swimmingPoolWidth);

        resultTextField.setText("Volume: " + swimmingPoolVolume);

    }

    @Override
    public void stateChanged(ChangeEvent e) {

        int shallowEnd = shallJSlider.getValue();
        int deepEnd = deepJSlider.getValue();

        double averageDepth = (shallowEnd + deepEnd) / 2;

        paintSwimmingPool(deepEnd, shallowEnd);

        calculateVolume(averageDepth);

    }

}

You cannot draw like this, the correct technique is

  • override the paintComponent() method in a JPanel subclass and use the Graphics parameter instead.
  • call repaint() to trigger a repaint instead of your paintSwimmingPool() method
  • move parameters ie deepEnd and shallowEnd into fields and reference these from your paintComponent() method - the inner class we be able to 'see' these fields. Ideally these would be in a separate model shared by the drawing panel and the control code, but the inner class gets the job done.
  • Look at the oracle tutorial on custom painting

Fully worked example

public class SwimingPoolCalculator implements ChangeListener {

    private JFrame frame;
    private JPanel primaryJPanel, drawingJPanel;
    private JLabel deepJLabel, shallowJLabel;
    private JSlider deepJSlider, shallJSlider;
    private JTextField resultTextField;

    final private int xPos = 20;
    final private int yPos = 20;
    final private int swimmingPoolLength = 200;
    final private int swimmingPoolWidth = 50;
    private int deepEnd;   // <== moved to fields
    private int shallowEnd;  // <== moved to fields

    private class InnerDrawingPanel extends JPanel {
        @Override
        protected void paintComponent(Graphics drawingBoard) {
            drawingBoard.setColor(Color.yellow);   // <== drawing code now here
            drawingBoard.fillRect(0, 0, 250, 250);
            drawingBoard.setColor(Color.black);

            drawingBoard.drawLine(xPos, yPos, xPos + swimmingPoolLength, yPos);  // the top line
            drawingBoard.drawLine(xPos, yPos, xPos, yPos + deepEnd); // the left line
            drawingBoard.drawLine(xPos + swimmingPoolLength, yPos, xPos + swimmingPoolLength, yPos + shallowEnd); // the right line
            drawingBoard.drawLine(xPos, yPos + deepEnd, xPos + swimmingPoolLength, yPos + shallowEnd); // the bottom line
        }
    }

    public static void main(String[] args) {

        SwimingPoolCalculator swimingPoolCalculator = new SwimingPoolCalculator();

        swimingPoolCalculator.createGUI();

    }

    private void createGUI(){

        frame = new JFrame("Swiming Pool Calculator");

        primaryJPanel = new JPanel();
        primaryJPanel.setPreferredSize(new Dimension(250, 500));

        drawingJPanel = new InnerDrawingPanel();  // <== use inner class
        drawingJPanel.setPreferredSize(new Dimension(250, 300));
        drawingJPanel.setBackground(Color.yellow);

        shallowJLabel = new JLabel("S End");
        deepJLabel = new JLabel("D End");

        shallJSlider = new JSlider(JSlider.HORIZONTAL, 10, 100, 10);
        deepJSlider = new JSlider(JSlider.HORIZONTAL, 50, 200, 100);

        shallJSlider.addChangeListener(this);
        deepJSlider.addChangeListener(this);

        resultTextField = new JTextField(15);

        primaryJPanel.add(drawingJPanel);
        primaryJPanel.add(shallowJLabel);
        primaryJPanel.add(shallJSlider);
        primaryJPanel.add(deepJLabel);
        primaryJPanel.add(deepJSlider);
        primaryJPanel.add(resultTextField);

        frame.getContentPane().add(primaryJPanel);
        frame.pack();
        frame.setVisible(true);

        // why the first call does not draw any line?
        shallowEnd = deepJSlider.getValue(); // <== now update fields
        deepEnd = shallJSlider.getValue();
        drawingJPanel.repaint();        // <== trigger repaint

    }


    private void calculateVolume(double averageDepth){

        int swimmingPoolVolume = (int)(averageDepth * swimmingPoolLength * swimmingPoolWidth);

        resultTextField.setText("Volume: " + swimmingPoolVolume);

    }

    @Override
    public void stateChanged(ChangeEvent e) {

        shallowEnd = shallJSlider.getValue();  // <== update fields
        deepEnd = deepJSlider.getValue();

        double averageDepth = (shallowEnd + deepEnd) / 2;


        drawingJPanel.repaint();   // <== trigger repaint
        calculateVolume(averageDepth);

    }

}

Swing is probably repainting the JPanel after you painted on it. Swing can repaint components at any time, for any reason it feels like. For this reason, you should not use getGraphics .

Instead, you need to create your own component class (extending an existing component, such as JPanel ), and override paintComponent .

See this question for more details.

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