I have 2 buttons, a reset button and a calculate button.
The only purpose of the reset button is to repaint a JPanel called p1.
The purpose of the calculate button is to make a calculation and update a JLabel.
The issue is that when the reset button is pressed, followed by the calculate button, the JPanel is repainted and it should not be (see code below where the repaint method is not present in the ActionListener() for calculateButton).
I am wondering why this is happening, and what I can do to stop the JPanel from being repainted when this button is pressed (the reset button's functions exactly as expected, by repainting the panel).
public class DrawCircles extends JFrame {
//the following are x and y locations of the centers of the circles
int center1X;
int center1Y;
int center2X;
int center2Y;
int center3X;
int center3Y;
public DrawCircles(){
final CircleDraw c = new CircleDraw(); //create a circledraw object to get the area of the triangle between them
final JPanel p1 = new JPanel(); //first panel to hold all other panels making the layout
JPanel buttonPanel = new JPanel();
p1.setLayout(new BorderLayout()); //set the layout of the panel to a border layout
JButton areaTriangle = new JButton("Calculate area of triangle");
JButton perimeterTriangle = new JButton("Calculate perimeter of triangle");
JButton reset = new JButton("Reset");
buttonPanel.setLayout(new BoxLayout(buttonPanel,0));
buttonPanel.add(areaTriangle);
buttonPanel.add(Box.createRigidArea(new Dimension(15,0)));
buttonPanel.add(perimeterTriangle);
buttonPanel.add(Box.createRigidArea(new Dimension(15,0)));
buttonPanel.add(reset); //add a button that says reset
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
p1.repaint(); //redraw the circles and triangle
areaLabel.setText(""); //clear the label
}
});
calculateButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
areaLabel.setText("Area is "+ String.valueOf(2.0*c.getArea()));
}
});
resetButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
areaLabel.setText("");
}
});
add(p1);
}
public class CircleDraw extends JPanel {
int radius;
double s;
double area;
public CircleDraw(){
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Random rand = new Random(System.currentTimeMillis());
center1X=rand.nextInt(507);
center1Y=rand.nextInt(320);
center2X=rand.nextInt(507);
center2Y=rand.nextInt(320);
center3X=rand.nextInt(507);
center3Y=rand.nextInt(320);
//draw the 3 circles
g.drawOval(center1X, center1Y, 100,100);
g.drawOval(center2X, center2Y,100,100);
g.drawOval(center3X, center3Y, 100, 100);
//connect the centers of the circles with lines
g.drawLine(center1X+50, center1Y+50, center2X+50, center2Y+50);
g.drawLine(center2X+50, center2Y+50, center3X+50, center3Y+50);
g.drawLine(center3X+50, center3Y+50, center1X+50, center1Y+50);
}
}
public static void main(String[] args) {
DrawCircles frame = new DrawCircles();
frame.setSize(700,500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
You state:
The issue is that when the reset button is pressed, followed by the calculate button the panel is repainted and it should not be. (See code below where the repaint method is not present in the ActionListener() for calculateButton). I am wondering why this is happening, and what I can do to stop the panel from being repainted when this button is pressed. (The reset button functions exactly as expected, by repainting the panel).
It is impossible to guess what could be wrong based on the code you've posted so far. I urge you to consider creating and posting a minimal example program that allows us to see your problem for ourselves.
But having said that, I will add that you never have full control over when a component is painted or not, since many paintings are driven by the JVM responding to the operating system. This is one reason that program logic should never reside within a paint(Graphics g) or paintComponent(Graphics g) method override.
So your problem is really an XY Problem in disguise. You ask how to control the repainting of a component when you should instead be asking how to get your program logic out of one of the painting methods, and in fact this is my guess at the solution to your problem -- make sure that your painting method is used solely for painting and nothing else.
Edit
Yep, you have program logic within the paintComponent method, specifically this code:
Random rand = new Random(System.currentTimeMillis());
center1X=rand.nextInt(507);
center1Y=rand.nextInt(320);
center2X=rand.nextInt(507);
center2Y=rand.nextInt(320);
center3X=rand.nextInt(507);
center3Y=rand.nextInt(320);
Get it out of paintComponent and in its own method that will allow you to control when it is called.
Edit 2
For example, you could do this:
public class CircleDraw extends JPanel {
private int radius;
private double s;
private double area;
private Random rand = new Random(); // make this a field
// call this when you want to change the random images
public void randomizeDrawing() {
center1X = rand.nextInt(507);
center1Y = rand.nextInt(320);
center2X = rand.nextInt(507);
center2Y = rand.nextInt(320);
center3X = rand.nextInt(507);
center3Y = rand.nextInt(320);
repaint();
}
// and only do painting in paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw the 3 circles
g.drawOval(center1X, center1Y, 100, 100);
g.drawOval(center2X, center2Y, 100, 100);
g.drawOval(center3X, center3Y, 100, 100);
// connect the centers of the circles with lines
g.drawLine(center1X + 50, center1Y + 50, center2X + 50, center2Y + 50);
g.drawLine(center2X + 50, center2Y + 50, center3X + 50, center3Y + 50);
g.drawLine(center3X + 50, center3Y + 50, center1X + 50, center1Y + 50);
}
Related
I'm trying to let a user draw a rectangle with their mouse.
I'm having two problems which I think may be related. Firstly, the third class I posted here, Colors.java, needs to use the same rectangle object from the mouse listener, which is the second class I provided (Mouse.java).
I tried to use getters and setters with this, when I went through the program in debug mode it had the correct rectangle object in the color() method, but once it went to paintComponent() I now have a null rectangle object. I don't know why this is.
Another problem I've been having is that the repaint() method does not always call the paintComponent() method. I think this could be because of the rectangle object being null but I'm not sure.
I tried to shorten up the code and replaced some code with comments. I also didn't think including the rectangle class was necessary since most of the class is filled with other functions totally unrelated to the this problem.
Any help to lead me in the right direction would be appreciated, I'm pretty stuck right now. Thanks!
public class JavaSwing extends JFrame implements ItemListener {
//Checkbox objects here
Colors colors = new Colors();
public void createGui() {
intersection = new JCheckBox("Draw Intersections");
intersection.setMnemonic(KeyEvent.VK_C);
intersection.setSelected(false);
//checkbox objects assigned like above
//checkbox listeners
JFrame frame = new JFrame("Rectangles");
frame.setSize(600, 600);
frame.setVisible(true);
Mouse mouse = new Mouse();
colors.setLayout(new BoxLayout(colors, BoxLayout.PAGE_AXIS));
colors.addMouseListener(mouse);
colors.addMouseMotionListener(mouse);
colors.add(Box.createRigidArea(new Dimension(0, 5)));
colors.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
JButton button = new JButton("Clear Image");
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
panel.add(Box.createHorizontalGlue());
panel.add(intersection);
panel.add(Box.createRigidArea(new Dimension(10, 0)));
panel.add(union);
panel.add(Box.createRigidArea(new Dimension(10, 0)));
panel.add(commonArea);
panel.add(Box.createRigidArea(new Dimension(10, 0)));
panel.add(button);
frame.add(colors, BorderLayout.CENTER);
frame.add(panel, BorderLayout.PAGE_END);
}
#Override
public void itemStateChanged(ItemEvent e) {
//for checkboxes
}
public static void main(String args[]) {
JavaSwing javaSwing = new JavaSwing();
javaSwing.createGui();
}
}
Second Class:
public class Mouse extends MouseInputAdapter implements MouseListener{
Rectangle rectangleOne = new Rectangle(0, 0, 0, 0);
Colors colors = new Colors();
public void mousePressed(MouseEvent e) {
rectangleOne.setX(e.getX());
rectangleOne.setY(e.getY());
rectangleToDraw = new Rectangle(rectangleOne.getX(), rectangleOne.getY(),
rectangleOne.getWidth(), rectangleOne.getHeight());
colors.setRectangle(rectangleToDraw);
colors.color();
}
public void mouseReleased(MouseEvent e) {
int x2 = e.getX();
int y2 = e.getY();
rectangleOne.setWidth(x2 - rectangleOne.getX());
rectangleOne.setHeight(y2 - rectangleOne.getY());
rectangleToDraw = new Rectangle(rectangleOne.getX(), rectangleOne.getY(),
rectangleOne.getWidth(), rectangleOne.getHeight());
colors.setRectangle(rectangleToDraw);
colors.color();
}
Third Class:
public class Colors extends JPanel {
Rectangle rectangle;
public void setRectangle(Rectangle rectangle)
{
this.rectangle = rectangle;
}
public Rectangle getRectangle() {
return rectangle;
}
public void color() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
if (getRectangle() != null) {
g.fillRect(getRectangle().getX(), getRectangle().getY(), getRectangle().getWidth(), getRectangle().getHeight());
}
}
}
The reason rectangle is null when you reach paintComponent is because the colors in Mouse is not the same as the colors in JavaSwing. In both classes you do Colors colors = new Colors(). That means you have two separate, unrelated, instances of the class. That's also the reason you aren't seeing a repaint happen when you call repaint() - you're calling it on a component that's not part of the actual component hierarchy being displayed.
If you change things so that you use the same Colors instance in both cases, it will work correctly. So change your Mouse code to this:
public class Mouse extends MouseInputAdapter implements MouseListener{
Rectangle rectangleOne = new Rectangle(0, 0, 0, 0);
Colors colors;
public Mouse(Colors colors){
this.colors = colors;
}
/* The rest of your methods here */
}
And then create your Mouse instance like this:
Mouse mouse = new Mouse(colors);
Also, although I don't think this is what you're talking about, I think I should mention that repaint() does not always result in paintComponent being called, even when you do it on the correct object. What it does is make a request that the component be repainted when the Event Dispatch Thread is next able to. Usually it will cause paintComponent to be called, but not always (for example if the component isn't visible, or if you call it multiple times before it can be repainted, which will result in it only being painted once).
I want to draw an inscribed circle. A circle that is empty with no fill but making it have a full stroke. My code :
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package simon;
import java.awt.*;
import java.awt.event.*; //This allows us to detect user input
import java.awt.image.BufferedImage;
import javax.swing.*; //This allows us to use graphical elements, colors, etc.
/**
*
* #author User
*/
public class SimonA {
//First, we create all the elements of our program
//Here are the variables...
public static int score = 0;
public static int color = 0; //0 = yellow, 1 = red, 2 = blue, 3 = green
public static Boolean flash = false; //This is used to make the panel blink
public static Boolean running = false;
//Here are the widgets (objects)....
public static JFrame frame = new JFrame();
public static JPanel buttons = new JPanel();
public static JPanel buttons1 = new JPanel();//These buttons will all be square (the default). Different packages can be used to change the shape
public static JPanel controls = new JPanel();
public static JButton red = new JButton();
public static JButton yellow = new JButton();
public static JButton green = new JButton();
public static JButton blue = new JButton();
public static JButton toggle = new JButton("Start"); //Click this button to see a sample flash
public static JLabel scoreTxt = new JLabel("Score: " + score, SwingConstants.CENTER); //This object (a label element) displays the score variable's value
public static Timer blink = new Timer(600,new Ticker()); //This is used to time the duration of the flash
public static BufferedImage img = new BufferedImage(400, 400, BufferedImage.TYPE_INT_ARGB);
public static Graphics2D g = img.createGraphics();
public static JLabel space = new JLabel();
JPanel panelBgImg = new JPanel() {
public void paintComponent(Graphics g){
g.setStroke(new BasicStroke(8));
g.fillOval(0, 0, 400, 400);
}
};
/*Timers are important for any program in which something "moves" at set durations. In this case, every tenth of
a second, the timer will generate an event. In this case, we are using it to determine that the active tile
will flash for 600ms, or 6/10 of a second. Obvously, then, 1000 makes the timer generate an event once-per-second. */
public static void main (String[] args)
{
frame.setBackground(Color.gray);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //This means that when we close the window with [x] the program ends
frame.setSize(new Dimension(400,400));
frame.setForeground(Color.black);
frame.setTitle("Simon");
frame.setLayout(new BorderLayout()); //Remember this from the LayoutManager test?
buttons.setLayout(new GridLayout(1,2));
buttons1.setLayout(new GridLayout(1,2));//The buttons are placed in this panel, which is set as a 2x2 grid
yellow.setBackground(Color.yellow);
yellow.addActionListener(new YellowPressed()); //This triggers the "procedure" that runs when the yellow button is pressed
yellow.setPreferredSize(new Dimension(200,200));
//Note, the other buttons will take their cue for size from the above statement, since they are all in the same grid
//We do not need to specify dimensions again
red.setBackground(Color.red);
red.addActionListener(new RedPressed());
red.setPreferredSize(new Dimension(200,200));
blue.setBackground(Color.blue);
blue.addActionListener(new BluePressed());
green.setBackground(Color.green);
green.addActionListener(new GreenPressed());
green.setPreferredSize(new Dimension(200,200));
//Adding the four buttons to the panel called "buttons"
buttons1.add(yellow);
buttons.add(red);
buttons.add(green);
buttons1.add(blue);
//The control panel on the bottom is a gride of one row and two columns
controls.setLayout(new GridLayout(2,1));
controls.add(scoreTxt);
controls.add(toggle);
toggle.addActionListener(new ToggleOn());
//We now add the panels to the frame according to the border layout
frame.add(buttons,BorderLayout.NORTH);
frame.add(controls,BorderLayout.CENTER);
frame.add(buttons1,BorderLayout.SOUTH);
//This .pack() method removes any excess whitespace around your elements
//Sometimes it results in a better look, and sometimes not.
frame.pack();
frame.setVisible(true);
}
public static class ToggleOn implements ActionListener {
public void actionPerformed(ActionEvent event)
{
//This toggles the main button between Start and Stop
//If it's running, stop it from running
//If it's not running, start it running
running = !running;
if (running)
{
toggle.setText("Stop");
//To demonstrate how the code might work, a sample flash
color = 3; //Change the color to "active"
blink.start(); //Starts the 6/10 second timer
score += 10;
scoreTxt.setText("Score: " + score);
}
else
{
toggle.setText("Start");
}
}
}
public static class YellowPressed implements ActionListener {
public void actionPerformed(ActionEvent event)
{
//Right now, the buttons just print to the screen
//The "real" program would implement other instructions here
System.out.println("Yellow");
}
}
public static class RedPressed implements ActionListener {
public void actionPerformed(ActionEvent event)
{
System.out.println("Red");
}
}
public static class BluePressed implements ActionListener {
public void actionPerformed(ActionEvent event)
{
System.out.println("Blue");
}
}
public static class GreenPressed implements ActionListener {
public void actionPerformed(ActionEvent event)
{
System.out.println("Green");
}
}
public static class Ticker implements ActionListener {
public void actionPerformed(ActionEvent event)
{
//When the timer triggers, if a button is active,
//set it back to its original color 6/10 of a second later
flash = !flash;
if (flash) //If the button is to be lit, turn it white
{
if (color == 0)
yellow.setBackground(Color.white);
else if (color == 1)
red.setBackground(Color.white);
else if (color == 2)
blue.setBackground(Color.white);
else if (color == 3)
green.setBackground(Color.white);
}
else //Otherwise, change it back to its original color
{
if (color == 0)
yellow.setBackground(Color.yellow);
else if (color == 1)
red.setBackground(Color.red);
else if (color == 2)
blue.setBackground(Color.blue);
else if (color == 3)
green.setBackground(Color.green);
blink.stop();
}
}
}
}
Here is what I am using to create the circle, for some reason it does not create the circle:
JPanel panelBgImg = new JPanel() {
public void paintComponent(Graphics g){
g.setStroke(new BasicStroke(8));
g.fillOval(0, 0, 400, 400);
}
};
First of all, you're never (in the code provided) adding the panelBgImg to any component, so nothing is going to show it (you have to add it to a frame or another panel somewhere).
You should also change your paintComponent method though...
JPanel panelBgImg = new JPanel() {
public void paintComponent(Graphics g){
//Call super method to draw background
super.paintComponent(g);
//Cast to Graphics2D to use setStroke
Graphics2D g2d = (Graphics2D) g;
//Set the color of the circle you want to draw
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(8));
//g2d.fillOval(0, 0, 400, 400);
//Use drawOval instead of fillOval (otherwise it will be filled with the color)
g2d.drawOval(0, 0, 400, 400);
}
};
I am a newb and am trying to get a line to draw with my xslider and yslider so it would create cross hairs on the canvas panel. I cannot figure this out. The idea is that when I push the "Show" button a circle is to appear centered on the crosshairs set by the sliders. I used internalframes to create the button location and canvas for the circle and sliders. I need lines connected to the sliders. I cannot change the coding as to how the sliders work in tandem, part of expectations. Please assist.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class CircleViewer2 extends JPanel
{
//Variables
Ellipse2D.Double circle;
static Color FillColor = Color.blue;
static String ShowHideName = null;
static JSlider xSlider;
static JSlider xSlider2;
static JSlider ySlider;
static JSlider ySlider2;
//Creation of the circle utilizing Ellipse2D
public CircleViewer2(int radius)
{
circle = new Ellipse2D.Double(0, 0, radius, radius);
setOpaque(false);
}
//Setting PreferredSize
public Dimension getPreferredSize()
{
Rectangle bounds = circle.getBounds();
return new Dimension(bounds.width, bounds.height);
}
//Establishing parameters for Drawing the Circle Via Paint
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(FillColor);
g2.fill(circle);
}
public static void main(String[] args)
{
final JPanel center = new JPanel();
center.setLayout(null);
center.setPreferredSize(new Dimension(400,400));
ShowHideName = "Show";
final JButton ShowHideButton = new JButton(ShowHideName);
ShowHideButton.setPreferredSize(new Dimension(75, 25));
ShowHideButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if (ShowHideName.equals("Show"))
{
int xCoord = xSlider.getValue();
System.out.println(xCoord);
int yCoord = ySlider.getValue();
System.out.println(yCoord);
CircleViewer2 component = new CircleViewer2(50);
component.setLocation(xCoord,yCoord);
component.setSize(component.getPreferredSize());
center.add(component);
ShowHideName = "Hide";
center.repaint();
}
else
{
ShowHideName = "Show";
center.removeAll();
center.updateUI();
}
ShowHideButton.setText(ShowHideName);
}
});
final JButton ColorButton = new JButton("Color");
ColorButton.setPreferredSize(new Dimension(75, 25));
ColorButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
FillColor = JColorChooser.showDialog(null, "Pick a Color", Color.blue);
}
});
JFrame frame = new JFrame();
JInternalFrame canvas = new JInternalFrame();
JInternalFrame buttonFrame = new JInternalFrame();
JPanel buttonPanel = new JPanel();
buttonPanel.add(ShowHideButton);
buttonPanel.add(ColorButton);
javax.swing.plaf.InternalFrameUI ifu= buttonFrame.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI)ifu).setNorthPane(null);
buttonFrame.setBounds(0, 500, 500, 200);
buttonFrame.add(buttonPanel, BorderLayout.CENTER);
buttonFrame.setVisible(true);
xSlider = new JSlider(SwingConstants.HORIZONTAL,0,380,10);
BoundedRangeModel xmodel = xSlider.getModel();
xSlider2 = new JSlider(SwingConstants.HORIZONTAL);
xSlider2.setModel(xmodel);
ySlider = new JSlider(SwingConstants.VERTICAL,0,350,10);
BoundedRangeModel ymodel = ySlider.getModel();
ySlider.setInverted(true);
ySlider2 = new JSlider(SwingConstants.VERTICAL);
ySlider2.setModel(ymodel);
ySlider2.setInverted(true);
canvas.add(center, BorderLayout.CENTER);
canvas.add(xSlider, BorderLayout.SOUTH);
canvas.add(xSlider2, BorderLayout.NORTH);
canvas.add(ySlider, BorderLayout.EAST);
canvas.add(ySlider2, BorderLayout.WEST);
canvas.setBounds(0, 0, 500, 550);
canvas.setVisible(true);
javax.swing.plaf.InternalFrameUI ifu2 = canvas.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI)ifu2).setNorthPane(null);
frame.add(canvas, BorderLayout.NORTH);
frame.add(buttonFrame, BorderLayout.SOUTH);
frame.setBounds(0, 0, 500, 530);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
This is not a good implementation of the problem. You can inherit the JFrame and make the code clearer, it's the common method to play with Swing components. Any way, Add a change Listener to your sliders and change the location of the Center Panel according to the Sliders Value.
Something like that:
xSlider.addChangeListener( e -> {
center.setLocation(new Point(xSlider.getValue(), (int) center.getLocation().getY());
});
and so on.
This is a good place to start with Java/Swing GUI best practices
Your code looks way more complex than it needs to be, and I would try to simplify it greatly. Some suggestions:
Get rid of all the JInternalFrames and use JPanels instead.
Create a JPanel, say called drawingPanel, that has its paintComponent(Graphics g) overridden and perhaps its getPreferredSize() overridden, place this JPanel BorderLayout.CENTER in your main GUI.
In the paintComponent method, have the logic to draw the circles and the crosshairs based on fields of your class.
When a JSlider moves, have its ChangeListener change the state of the corresponding field, and then have it call repaint() on the drawing panel so that it will draw the changes.
When the show button is pressed, have it change the state of a boolean variable and then call repaint().
Have the drawingPanel use the boolean in its paintComponent method to decide whether or not to draw the filled circle.
Have the drawingPanel draw the lines in its paintComponent method based on the value returned by the JSliders. Again you're calling repaint in the JSlider's listeners, so the lines will move.
Do not add and remove components on button clicks since this adds unnecessary complexity which makes things much harder to code.
Don't move the center component or any component. Just use the fixed drawingPanel JPanel and move the location of the circle and the lines that it draws.
Since this is homework, I'm going to avoid posting code as the coding should be up to you. Much luck!
I am trying to add/draw a single Graphics object to an existing JPanel. I am generating 10 initial Graphics objects randomly sized and place in the panel, but would like to add additional drawn objects one a time, randomly sized and placed like the initial 10.
Currently, the AddNewDrawItem class is not rendering the new Graphics object.
Thank you for input.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class Painter{
private DrawingPanel dp = new DrawingPanel();
//constructor
public Painter(){
buildGUI();
}
private void buildGUI(){
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setTitle("Paint drawing demonstration");
JPanel headerPanel = new JPanel();
headerPanel.add(new JLabel("The drawing panel is below"));
JButton addNew = new JButton("Add New Graphic");
addNew.addActionListener(new addNewClickHandler());
headerPanel.add(addNew);
frame.add(BorderLayout.NORTH,headerPanel);
frame.add(BorderLayout.SOUTH,this.dp);
frame.pack();
frame.setVisible(true);
}
class DrawingPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
int x, posx, posy, width, height;
for(x=0;x<=10;x++){
//even number differentiation
if(x % 2 == 0){
g.setColor(Color.red);
}else{
g.setColor(Color.blue);
}
Random rand = new Random();
posx = rand.nextInt(300);
posy = rand.nextInt(300);
width = rand.nextInt(40);
height = rand.nextInt(40);
//System.out.println("the ran x pos is: " + posx);
g.fillRect(posx, posy, width, height);
}//end for
}//end paintComponent
public Dimension getPreferredSize() {
return new Dimension(400,400);
}
}// end DrawingPanel
private class addNewClickHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.print("in addNew_click_handler click handler");//trace debug
AddNewDrawItem newItem = new AddNewDrawItem();
newItem.repaint();
System.out.print("after repaint() in addNew_click_handler click handler");//trace debug
}
}
class AddNewDrawItem extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
int posx, posy, width, height;
Random rand = new Random();
posx = rand.nextInt(300);
posy = rand.nextInt(300);
width = rand.nextInt(40);
height = rand.nextInt(40);
g.setColor(Color.cyan);
g.fillRect(posx, posy, width, height);
}//end paintComponent
}//end AddNewDrawItem
public static void main(String args[]){
new Painter();
}
}//end class Painter
You've got some problems with your code, one of which is that you've got program logic in your paintComponent method: the code randomly changes values that are displayed within this method, meaning your display will change when it repaints, whether you want it to or not. To see that this is so, try to resize your GUI and you'll see some psychedelic changes in the drawn red and blue rectangles.
Now as to your current problem, the solution to it is similar to the solution to the problem I describe above. I suggest...
that you create an ArrayList<Rectangle2D>,
that you create your random rectangles in your class's constructor so that they're created only once, and then place them in the ArrayList above.
that you iterate through this ArrayList in your JPanel's paintComponent method, drawing them as you go. This way paintComponent does nothing but paint which is as it should be,
that you create a MouseAdapter-derived object and add it as a MouseListener and MouseMotionListener to your DrawingPanel
that you use the listener above to create a new Rectangle2D object and when done add it to the ArrayList and call repaint on the DrawingPanel
that you activate the mouse adapter via your button's action listener.
I'll stop there, but I think you get the idea, and if you don't, please ask any questions you may have.
Good day.
I develop program which must show few shapes when user clicks the button. At least it doesn't show it. What is wrong?
Code is:
public class ShowFrame extends JFrame
{
public ShowFrame()
{
this.setTitle("Show data"); //Title
this.setSize( DEF_WIDTH, DEF_HEIGHT ); //Size of frame
this.setResizable(false);
//...
JButton testButton = new JButton("Test");
buttonPanel.add(testButton);
this.add(buttonPanel, BorderLayout.SOUTH);
testButton.addActionListener( new ActionListener() { //Add listener
public void actionPerformed(ActionEvent e) {
DrawStuff stuff = new DrawStuff(); //Create class which draws shapes
add(stuff, BorderLayout.CENTER);
System.out.println("Test Button");
}
} );
}
public static final int DEF_WIDTH = 600;
public static final int DEF_HEIGHT = 400;
private JPanel buttonPanel = new JPanel();
}
Class which draws shapes:
public class DrawStuff extends JComponent
{
public void paintComponent( Graphics g )
{
Graphics2D g2 = (Graphics2D) g;
//...
Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
Line2D line = new Line2D.Double(leftX, topY, 0, 0);
//...
g2.draw(rect);
g2.draw(line);
//...
}
}
When you add/remove components on a visible GUI the code should be:
panel.add(...);
panel.revalidate();
panel.repaint();
Your design of adding a new panel every time you click a button is not a very good one.
Instead you should create a custom painting panel and override the paintComponent() method. Then when you click a button you invoke a method in your custom component to set the shape you want to draw. The paintComponent() method should be smart enought to paint the shape. Then you invoke repaint() on the panel.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.