Reputation: 583
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);
}
}
Upvotes: 1
Views: 71
Reputation: 36723
You cannot draw like this, the correct technique is
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);
}
}
Upvotes: 3
Reputation: 58909
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.
Upvotes: 0