简体   繁体   English

调用我的方法,但它不绘制线条

[英]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. 有问题的方法是paintSwimmingPool(),它在被stateChanged()监听器方法调用时工作正常。 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. 我在一些控制台消息中添加了帮助调试,它告诉我从createGUI()方法正确调用该方法。 But why paintSwimmingPool() does not draw anything on the panel? 但为什么paintSwimmingPool()不会在面板上绘制任何东西? 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. 覆盖JPanel子类中的paintComponent()方法,改为使用Graphics参数。
  • call repaint() to trigger a repaint instead of your paintSwimmingPool() method 调用repaint()来触发重绘而不是paintSwimmingPool()方法
  • 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. 将参数(例如deepEnd和shallowEnd)移动到字段中并从paintComponent()方法引用这些参数 - 我们能够“看到”这些字段的内部类。 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 看看自定义绘画oracle教程

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可能会重新粉刷JPanel。 Swing can repaint components at any time, for any reason it feels like. Swing可以随时重新绘制组件,无论出于何种原因。 For this reason, you should not use getGraphics . 因此,您不应该使用getGraphics

Instead, you need to create your own component class (extending an existing component, such as JPanel ), and override paintComponent . 相反,您需要创建自己的组件类(扩展现有组件,如JPanel ),并覆盖paintComponent

See this question for more details. 有关详细信息,请参阅此问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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