【问题标题】:My method is called, but it does not draw the lines我的方法被调用,但它没有画线
【发布时间】:2015-03-31 09:53:15
【问题描述】:

以下是我绘制游泳池并同时计算其体积的代码。

有问题的方法是paintSwimmingPool(),当被stateChanged() 监听器方法调用时,它可以正常工作。但是,问题是我想在启动程序时绘制矩形。我添加了一些控制台消息来帮助调试,它告诉我该方法是从 createGUI() 方法正确调用的。但是为什么paintSwimmingPool() 没有在面板上绘制任何东西呢?抱歉,我花了很长时间解决这个问题,但没有找到。

提前感谢您的任何指点。

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);

    }

}

【问题讨论】:

标签: java swing


【解决方案1】:

你不能这样画,正确的技巧是

  • 覆盖JPanel 子类中的paintComponent() 方法并改用Graphics 参数。
  • 调用 repaint() 来触发重绘而不是您的 paintSwimmingPool() 方法
  • 将参数(即 deepEnd 和 shallowEnd)移动到字段中,并从您的 paintComponent() 方法中引用它们 - 我们能够“看到”这些字段的内部类。理想情况下,这些将位于绘图面板和控制代码共享的单独模型中,但内部类可以完成工作。
  • oracle tutorial on custom painting

完整的例子

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);

    }

}

【讨论】:

  • (咳嗽)super.paintComponent(咳嗽)
  • g.drawImage(image, 0, 0, null); 应该是g.drawImage(image, 0, 0, this);,因为JPanel 通过JComponent 实现ImageObserver 接口。在某些系统上未处理您创建的 Graphics 上下文 (image.getGraphics();) 也可能存在问题,但这是一个工作流问题。
  • 嗨@Adam,但我还有另一个问题。我建立了另一个班级并尝试在其中画游泳池。但是,如何将所需的参数(如 xPos、yPos)传递给 paintComponent(Graphics g)?我无法使用上面显示的技术进行锻炼。你可以说得更详细点吗?谢谢。
  • 我已经修改了我的答案,以准确地向您展示如何处理参数,即没有参数并改用共享状态。理想情况下,这些将在绘图面板和控制代码共享的正式模型中,但我使用的内部类可以完成工作。
【解决方案2】:

Swing 可能会在您绘制 JPanel 后重新绘制它。 Swing 可以在任何时候以任何感觉重新绘制组件。因此,您不应使用getGraphics

相反,您需要创建自己的组件类(扩展现有组件,例如JPanel),并覆盖paintComponent

更多详情请见this question

【讨论】:

    猜你喜欢
    • 2018-03-21
    • 2012-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多