I write a program to draw 50 rectangles after clicking OK button. But I don't uderstand why it disappears after resizing window, using scrollbar or clicking on OK again.
Here's my code (I have two classes: drawingPanel and Main)
drawingPanel.java:
import javax.swing.*;
import java.awt.*;
public class drawingPanel extends JPanel
{
public boolean drawIt = false;
public int x = 140,y = 0;
public void paintIt()
{
drawIt = true;
repaint();
}
public void paintComponent(Graphics g)
{
if (drawIt == true)
{
super.paintComponent(g);
for (int i = 1; i <= 50; i++)
{
g.fillRect(x, y, 50, 50);
y += 70;
}
}
}
}
Main.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JFrame
{
private drawingPanel draw = new drawingPanel();
private JPanel controlPanel = new JPanel();
private JButton ok = new JButton("OK");
private JScrollPane scroll = new JScrollPane(draw);
public Main()
{
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Demo");
setLayout(new BorderLayout());
controlPanel.setLayout(new FlowLayout());
controlPanel.add(ok);
ok.addActionListener(new okListener());
draw.setPreferredSize(new Dimension(100,1000));
add(controlPanel, BorderLayout.NORTH);
add(scroll,BorderLayout.CENTER);
setVisible(true);
}
private class okListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
draw.paintIt();
}
}
public static void main(String[] args)
{
new Main();
}
}
Please help me, thanks in advance.
Re-initialize x and y fields within your paint component method like so that they won't keep increasing out of view each time the JPanel is drawn:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // move this here
if (drawIt) {
x = 140; // add these guys
y = 0;
for (int i = 1; i <= 50; i++) {
// .... etc....
and things should draw OK.
Other minor issues not related to your question:
The super's painting method should always be called, so pull that out of the if block.
Rename your drawingPanel class to be DrawingPanel so that it conforms to Java conventions.
Better to change if (drawIt == true) { to the more simple if (drawIt) {
Minor quibble: paintComponent should be protected, not public.
Related
I am making kind of my paint that creates shapes, it worked fine until I added layers(panel and frame), now the shapes aren't visible on button press I assume it is under the layers?i tried using paintComponent and revalidate etc and still couldn't get it to appear
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main2 extends JPanel implements ActionListener {
private static Square mySquare;
private static Circle myCircle;
private static Color myColor;
public boolean SquareCheck;
public boolean CircleCheck;
JButton buttonSquare;
JButton buttonCircle;
JFrame frame;
JPanel panel;
public void paint(Graphics g) {
if (SquareCheck) {
g.setColor(myColor);
g.fillRect(mySquare.x, mySquare.y, mySquare.width, mySquare.length);
} else if (CircleCheck) {
g.setColor(myColor);
g.fillOval(myCircle.x, myCircle.y, myCircle.width, myCircle.length);
}
}
public void start() {
frame = new JFrame();
panel = new JPanel();
//setLayout(new BorderLayout());
buttonSquare = new JButton("■");
buttonCircle = new JButton("●");
buttonSquare.setPreferredSize(new Dimension(200, 20));
buttonCircle.setPreferredSize(new Dimension(200, 20));
buttonCircle.addActionListener(this);
buttonSquare.addActionListener(this);
//add(buttonCircle, BorderLayout.NORTH);
//add(buttonSquare, BorderLayout.SOUTH);
JToggleButton red = new JToggleButton();
panel.add(buttonCircle);
panel.add(buttonSquare);
frame.add(panel);
frame.setSize(500, 500);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == buttonSquare) {
SquareCheck = true;
} else if (e.getSource() == buttonCircle) {
CircleCheck = true;
}
repaint();
}
public static void main(String[] args) {
mySquare = new Square(30, 50, 50, 50);
myCircle = new Circle(60, 100, 50, 50);
myColor = Color.red;
Main2 x = new Main2();
x.start();
}
}
Basiclly the buttons changes the boolean then the repaint is called and based on the boolean it draws either a cirlce or a square,the code worked before adding frame and panel
Your paint method is a method of the Main2 class, but you never add a Main2 instance to the JFrame or to any component that goes into the JFrame, and so the Main2 instance will never be displayed, and the Swing painting manager will never call its paint method.
For starters, get rid of this variable, panel = new JPanel(); and every place you use panel, substitute this. This way you'll be working with a correct Main2 instance and adding it to the GUI.
Other issues:
You need to call the super's equivalent painting method in your override on its first line
Override paintComponent, not paint, and yes call super.paintComponenet(g); in this override
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
For safety's sake, add the #Override annotation above any method that you think may be overriding a parent method (such as paint), to make sure that you are doing it correctly.
For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
#SuppressWarnings("serial")
public class Main2 extends JPanel implements ActionListener {
private static Square mySquare;
private static Circle myCircle;
private static Color myColor;
private JToggleButton buttonSquare;
private JToggleButton buttonCircle;
JFrame frame;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (buttonSquare.isSelected()) {
g.setColor(myColor);
g.fillRect(mySquare.x, mySquare.y, mySquare.width, mySquare.length);
}
if (buttonCircle.isSelected()) {
g.setColor(myColor);
g.fillOval(myCircle.x, myCircle.y, myCircle.width, myCircle.length);
}
}
public Main2() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonSquare = new JToggleButton("■");
buttonCircle = new JToggleButton("●");
buttonCircle.addActionListener(this);
buttonSquare.addActionListener(this);
this.add(buttonCircle);
this.add(buttonSquare);
frame.add(this);
frame.setSize(500, 500);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public static void main(String[] args) {
mySquare = new Square(30, 50, 50, 50);
myCircle = new Circle(60, 100, 50, 50);
myColor = Color.red;
new Main2();
}
}
class MyShape {
public int x, y, width, length;
public MyShape(int x, int y, int width, int length) {
this.x = x;
this.y = y;
this.width = width;
this.length = length;
}
}
I try to add JPanel in an ArrayList and in another JPanel. Then repaint () the JFrame which JPanel is located in. After several hours of attempts, I start to get tired and find it difficult to think. I changed the program so many times that there may have been some simple mistakes that I no longer see.(Errors may also be found in my English I write here).
I apologize in advance if this is not understandable.
JFrame
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class JFrameClassen extends JFrame{
ArrayList <Bild> somePictures= new <Bild> ArrayList();
JPanel p;
public JFrameClassen(){
super("Window with pictures");
p = new JPanel();
p.setBackground(Color.GREEN);
add(p);
setBounds(1300, 500, 400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void addPhoto(String s){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
getContentPane().repaint();
}
public void addPhoto(String [] arr){
for(String s : arr){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
}
getContentPane().repaint();
}
public static void main(String[] args) {
JFrameClassen j = new JFrameClassen();
String oneArray[] = {"blab.gif", "peli.gif"};
j.addPhoto(oneArray);
j.addPhoto("stef.gif");
j.addPhoto("pear.gif");
}
}
JPanel
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Bild extends JPanel{
ImageIcon myImage;
int posX = 50;
int posY = 50;
Muslyssnare m = new Muslyssnare(this);
public Bild(String name){
myImage= new ImageIcon(name);
addMouseListener(m);
addMouseMotionListener(m);
}
public void move(int x, int y){
posX = x;
posY = y;
super.repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(myImage.getImage(), posX, posY, this);
}
}
MouseAdapter
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class Muslyssnare extends MouseAdapter implements MouseMotionListene{
Bild oneImage;
public Muslyssnare(Bild b){
oneImage = b;
}
public void mouseClicked (MouseEvent e) {
System.out.println("(" + e.getX() + "," + e.getY() + ")");
}
public void mouseDragged (MouseEvent e) {
int x = e.getX();
int y = e.getY();
oneImage.move(x, y);
}
}
You need to set a Layout on your main JPanel.
public JFrameClassen(){
super("Window with pictures");
p = new JPanel();
p.setBackground(Color.GREEN);
// This will stack your newly created panels.
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
// This will generate a scroll bar. You may need it
JScrollPane pane = new JScrollPane(p);
add(pane);
setBounds(1300, 500, 400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
Also follow MadProgrammer's advice and invoke revalidate / repaint
public void addPhoto(String s){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
getContentPane().revalidate();
getContentPane().repaint();
}
// Simplify your code. Reuse
public void addPhoto(String [] arr){
for(String s : arr){
addPhoto(s);
}
}
NOTE: BorderLayout will resize your inner panels to occupy all width available. You can user other layouts.
More info: https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://www.oracle.com/technetwork/java/tablelayout-141489.html
NOTE II: Next problem you'll face is image loading.
ImageIcon Loading in Java
How to add an image to a JPanel?
I am trying to make the effect of gravity but it just looks like there are growing streaks of circles instead of individual circles moving down. I do not know how to remove the circles I have already drawn. There are no errors in the code btw.
import javax.swing.Timer;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
public class Tester {
static JFrame frame;
static JPanel panel;
static JButton button;
static ArrayList<Ellipse2D.Double> circles = new ArrayList<Ellipse2D.Double>();
static void init(){
frame = new JFrame();
panel = new JPanel(new BorderLayout());
button = new JButton("South");
panel.add(button, BorderLayout.SOUTH);
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setBackground(Color.LIGHT_GRAY);
}
public static void main(String[] args) {
init();
class MeteorMover extends JPanel{
Ellipse2D.Double m;
int x = 40,y=40;
boolean isSettingGravity=true;
public MeteorMover(){
m = new Ellipse2D.Double(x,y,30,30);
}
void createNewMeteor(int n){
repaint();
}
void setGravity(){
isSettingGravity = true;
for (int i=0;i<circles.size();i++){
Ellipse2D.Double m = circles.get(i);
m= new Ellipse2D.Double(m.getX(),m.getY()+1,30,30);
circles.set(i, m);
}
repaint();
}
protected void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
if (isSettingGravity){
for (Ellipse2D.Double c:circles){
g2.draw(c);
}
isSettingGravity = false;
}
else{
m = new Ellipse2D.Double(x,y,30,30);
circles.add(m);
g2.fill(m);
g2.draw(m);
Random r = new Random();
x = r.nextInt(500);
y=r.nextInt(100);
}
}
}
final MeteorMover m = new MeteorMover();
panel.add(m);
panel.repaint();
class TimerListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
m.createNewMeteor(1);
}
}
TimerListener cListener = new TimerListener();
Timer timer = new Timer(1000,cListener);
timer.start();
class TimerListener2 implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
m.setGravity();
}
}
TimerListener2 gListener = new TimerListener2();
Timer gTimer = new Timer(100,gListener);
gTimer.start();
}
}
call super.paintComponent(g);
protected void paintComponent(Graphics g) {
super.paintComponent(g);
read more about super.paintComponent .
There's no direct way to erase with graphics, you have two options:
If you always know which ellipse you need to erase, AND the ellipses never intersect, then you could keep in memory which is the next ellipse to erase and call g.setColor(bgColor); g.fill(erasedEllipse);
This is option is more reliable, You could keep an ArrayList of ellipses to draw. and you could clear all the pane and repaint all
the ellipses in the ArrayList, and if you want to erase one, you
just call ArrayList.remove(erasedElipseIndex)
Thanks for the help. The objects are all showing now.
But I ran into a new problem. Im trying to use a For loop to draw 10 copys of the same box with a little space in between so they don't just stack in the same position.
But for some reason they keep getting painted on top of eachother and in the center instead of starting at x = 20...
import java.awt.*;
import javax.swing.*;
public class CarWashPanel extends JPanel {
public int i;
public int x = 20;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
for (i=0; i < 10; i++){
g.fillRoundRect(x, 10, 50, 100, 55, 25);
x = x + 10;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 150);
}
}
//
I'm trying to add graphics in my CarWashPanel class to I want to add to my GUI. I've read some tutorials and other questions but I can't figure out what i'm doing wrong.
The buttons and label that i've added to the GUI show up just fine but when I add something to my CarWashPanel it doesn't show up in the GUI.
I feel like I need to tell my GUI to add all elements from the CarWashPanel but I'm not sure how.
public class Main {
public static void main(String[] args) {
GUI g = new GUI();
}
}
import javax.swing.*;
import java.awt.*;
public class GUI extends JFrame {
private JTextField t1 = new JTextField(2);
private JLabel l1 = new JLabel("enter position");
private JButton b1 = new JButton("new customer");
private JButton b2 = new JButton("wash car");
public GUI() {
setDefaultCloseOperation (
JFrame.EXIT_ON_CLOSE );
add(l1);
add(t1);
add(b1);
add(b2);
setTitle("Carwash");
setSize(500, 200);
setVisible(true);
setLayout(new FlowLayout());
add(new CarWashPanel());
}
}
public class Carwash {
private boolean[] positions = new boolean[10];
private int washing = 10;
public void addCar(int p) {
positions[p] = true;
}
public void removeCar(int p) {
positions[p] = false;
}
public boolean[] getPositions() {
return positions;
}
public int getWashing() {
return washing;
}
}
import java.awt.*;
import javax.swing.*;
public class CarWashPanel extends JPanel {
public CarWashPanel(){
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRoundRect(150, 50, 100, 100, 50, 25);
}
}
It's very often issue. You are calling setVisible before you are adding your components. Add your components on CarWashPanel, add CarWashPanel on JFrame and then call setVisible. Also, remove this line: setLayout(new FlowLayout()); - FlowLayout is default layout for JPanel (CarWashPanel in your case) and this makes it sufficient.
Your code should look something like this:
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(GUI::new);
}
public static class GUI extends JFrame {
private JTextField t1 = new JTextField(2);
private JLabel l1 = new JLabel("enter position");
private JButton b1 = new JButton("new customer");
private JButton b2 = new JButton("wash car");
CarWashPanel carWashPanel = new CarWashPanel();
public GUI() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
carWashPanel.add(l1);
carWashPanel.add(t1);
carWashPanel.add(b1);
carWashPanel.add(b2);
add(carWashPanel,BorderLayout.CENTER);
setTitle("Carwash");
pack();
setVisible(true);
}
}
public class Carwash {
private boolean[] positions = new boolean[10];
private int washing = 10;
public void addCar(int p) {
positions[p] = true;
}
public void removeCar(int p) {
positions[p] = false;
}
public boolean[] getPositions() {
return positions;
}
public int getWashing() {
return washing;
}
}
public static class CarWashPanel extends JPanel {
public CarWashPanel() {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillRoundRect(150, 50, 100, 100, 50, 25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
}
}
Other sidenotes:
Don't call setSize for JFrame, call pack. Rather override getPreferredSize for JPanel and return some dimensions.
Avoid extending your class with JFrame unless you want to define new methods or override existing ones.
If you don't need to add things dynamically the best thing to do is call setVisible(true) after you've added all your components.
However, if you want to add things after the frame is visible you can do so and then call the frame's revalidate() method to cause it to redraw.
Secondly I'd recommend you set the layout before you add any components.
I'm trying to create an applet that will produce as many ovals as the number specified within a textbox. The textbox appears, but upon hitting enter, my paintComponent does not draw. Thank you in advance.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.miginfocom.layout.*;
import net.miginfocom.swing.MigLayout;
import java.awt.geom.*;
public class OvalDrawer extends JApplet
{
private JLabel numberL;
private JTextField numberTF;
private NumHandler numHandler;
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
//Create Layout
public void init()
{
setLayout(new MigLayout("wrap 2"));
numberL = new JLabel("Enter number of ovals to draw:");
numberTF = new JTextField(7);
add(numberL);
add(numberTF);
numHandler = new NumHandler();
numberTF.addActionListener(numHandler);
setSize(500, 500);
}
//Event Handler
public class NumHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
//Draw Ovals
public void paintComponent (Graphics g)
{
super.paintComponents(g);
int number;
int x = 10;
int y = 30;
int width = 20;
int height = 10;
number = Integer.parseInt(numberTF.getText());
for (int i = 0; i < number; i++)
{
g.drawOval(x, y, width, height);
x += 5;
y += 5;
width += 5;
height += 5;
}
}
}
A JApplet class does not have a paintComponent method to override. Note that your compiler won't let you call the actual super method (you think you may be doing this, but you're actually calling super.paintComponents(...), a completely different method).
A bad solution is to override the JApplet's paint method, but I strongly advise you not to do this. Instead you should draw in the paintComponent method of a JPanel and then have the JApplet display that JPanel. Also, you'll want to get into the habit of using the #Override annotation to be sure that you're actually overriding methods you think are.
/* * <Applet code=PressButton2 width=600 height=600> * </Applet>
*/
import javax.swing.*; import java.awt.*; import java.awt.event.*;
class MyPanel extends JPanel {
static String s="n";
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(s.equals("g"))
setBackground(Color.green);
if(s.equals("b"))
setBackground(Color.blue);
if(s.equals("c"))
setBackground(Color.white);
}
}
public class PressButton2 extends JApplet {
MyPanel panel;
MyPanel screen;
String s="n";
JButton green, clear, blue;
public void init() {
Container container = getContentPane();
panel = new MyPanel();
screen = new MyPanel();
panel.setLayout(new GridLayout(1, 3));
green = new JButton("Green");
blue = new JButton("Blue");
clear = new JButton("Clear");
green.addActionListener(new ActionEventHandler1());
blue.addActionListener(new ActionEventHandler1());
clear.addActionListener(new ActionEventHandler1());
panel.add(green);
panel.add(blue);
panel.add(clear);
container.add(panel, BorderLayout.SOUTH);
container.add(screen);
}
class ActionEventHandler1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
String temp = e.getActionCommand();
if (temp.equals("Green")) {
MyPanel.s = "g";
screen.repaint();
}
if (temp.equals("Blue")) {
MyPanel.s = "b";
screen.repaint();
}
if (temp.equals("Clear")) {
MyPanel.s = "c";
screen.repaint();
}
}
}