Swing app not drawing JComponent inside JPanel - java

I am currently writing a Java painting program using the Swing libraries and Graphics2D to paint. My main GUI class extends JComponent, and I am trying to put it inside a JPanel, and the JPanel inside a JFrame, in order to show it on the screen. When starting up the program though, the JComponent appears to be just a black line (the border, which is set to be a black line around the component). I cannot see why this is happening, and I've been debugging it for hours. If somebody could find the error in this program, I'd be very happy. Thanks in advance.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintGUI extends JComponent {
private static final long serialVersionUID = 1L;
JButton red, green, blue, clear;
Image img;
Graphics2D gfx;
JFrame drawFrame;
JPanel btnPan, drawPan;
MyListener ml;
Action act;
int x, y, prevX, prevY;
public PaintGUI(){
//Initialisering av panel, frame og content
drawFrame = new JFrame("IFIPaint");
drawFrame.setLayout(new BorderLayout());
btnPan = new JPanel();
drawPan = new JPanel();
btnPan.setLayout(new FlowLayout());
drawPan.setLayout(new BorderLayout());
this.setEnabled(true);
//Setter størrelser
btnPan.setPreferredSize(new Dimension(30, 60));
btnPan.setMinimumSize(new Dimension(30, 60));
btnPan.setMaximumSize(new Dimension(30, 60));
//Ordner knappene
red = new JButton("Rød");
green = new JButton("Grønn");
blue = new JButton("Blå");
clear = new JButton("Slett alt");
//Putter knappene på panelet
btnPan.add(red);
btnPan.add(green);
btnPan.add(blue);
btnPan.add(clear);
//Legger på action listeners
act = new Action();
red.addActionListener(act);
green.addActionListener(act);
blue.addActionListener(act);
clear.addActionListener(act);
//Fullfører vindu og setter synlighet
drawFrame.setSize(500, 500);
drawPan.setBounds(0, 0, 400, 400);
this.setBounds(0, 0, 400, 400);
drawPan.add(this);
this.setBackground(Color.RED);
drawFrame.add(drawPan, BorderLayout.NORTH);
drawFrame.add(btnPan, BorderLayout.SOUTH);
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
this.setVisible(true);
drawPan.setVisible(true);
btnPan.setVisible(true);
drawFrame.setVisible(true);
this.paintComponent(gfx);
drawFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
draw();
}
public void draw() {
ml = new MyListener();
this.addMouseListener(ml);
this.addMouseMotionListener(ml);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(img == null){
img = createImage(this.getWidth(),this.getHeight());
gfx = (Graphics2D) img.getGraphics();
gfx.setPaint(Color.RED);
gfx.fillRect(0, 0, this.getSize().width, this.getSize().height);
gfx.setPaint(Color.RED);
gfx.dispose();
}
gfx.drawImage(img, 0, 0, this);
}
class Action implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == red){
gfx.setPaint(Color.RED);
repaint();
} else if (e.getSource() == green){
gfx.setPaint(Color.GREEN);
repaint();
} else if (e.getSource() == blue) {
gfx.setPaint(Color.BLUE);
repaint();
} else if (e.getSource() == clear) {
gfx.clearRect(0, 0, drawFrame.getWidth(), drawFrame.getHeight());
repaint();
}
}
}
class MyListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
prevX = e.getX();
prevY = e.getY();
System.out.println("o ye");
}
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
gfx.drawLine(prevX, prevY, x, y);
repaint();
prevX = x;
prevY = y;
}
}
}

You added the PaintGUI to frame but LayoutManager don't know the size and can't set desired size.
Either set the preferred size (or override getPreferredSize to return desired size)
or add to the PaintGUI instance some component(s) with preferred size (e.g. buttons)

Related

Simple paint program using JPanel shows random images of JButtons

I'm trying to make a simple paint program in Java. It has 3 colors and a JField to enter the thickness. It works, except every time I enter a button, an image of that button shows up in the JPanel that contains the drawing portion.
I know that I can set the paintPane JPanel to opaque, but it relies on drawing over it self for the painting to work - otherwise it just drags a point around the screen. Thanks!!!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class SimplePainting
{
//The main method simply creates a frame, and terminates the program
//once that frame is closed.
public static void main (String [] args)
{
PaintFrame frame = new PaintFrame();
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);
}
}
class PaintFrame extends JFrame implements ActionListener
{
JPanel pane;
PaintPane drawPane;
Color paintColor = Color.black;
private int radius = 5;
//holds the thickness of the line
JTextField thick;
public PaintFrame ()
{
//We use the JFrame consturctor to add a title to the frame
super("Windows Paint");
//set the main content pane
pane = (JPanel)getContentPane();
pane.setLayout(new BorderLayout());
//make a pane to hold the drawing
drawPane = new PaintPane();
drawPane.addMouseMotionListener(drawPane);
//Make a JPanle to hold all of the buttons
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new GridLayout(1,6));
//add the buttons
JButton black = new JButton("Black");
buttonPane.add(black);
JButton red = new JButton("Red");
buttonPane.add(red);
JButton green = new JButton("Green");
buttonPane.add(green);
//Make a field to re-enter the thickness
thick = new JTextField(3);
thick.setText("5");
JButton thickness = new JButton("Reset Thickness");
thickness.addActionListener(this);
buttonPane.add(thickness);
buttonPane.add(thick);
JButton reset = new JButton("New Drawing");
reset.addActionListener(this);
buttonPane.add(reset);
black.addActionListener(this);
red.addActionListener(this);
green.addActionListener(this);
pane.add(drawPane, BorderLayout.CENTER);
pane.add(buttonPane, BorderLayout.SOUTH);
setSize(500,200);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("Black"))
paintColor = Color.black;
else if (e.getActionCommand().equals("Red"))
paintColor = Color.red;
else if (e.getActionCommand().equals("Green"))
paintColor = Color.green;
else if (e.getActionCommand().equals("Reset Thickness"))
{
if (thick.getText() != "")
{
int lineThickness = Integer.parseInt(thick.getText());
radius = lineThickness;
}
}
else if (e.getActionCommand().equals("New Drawing"))
{
drawPane.startPaint = false;
drawPane.repaint();
}
}
class PaintPane extends JPanel implements MouseMotionListener
{
private int x;
private int y;
// don't paint a point until mouse is dragged
boolean startPaint = false;
public PaintPane()
{
setBackground(Color.white);
}
//paints a circle centered at x,y
public void paint(Graphics g)
{
//recall that the frist (x,y) coordiantes represent the top left
//corner of a box holding the circle
g.setColor(paintColor);
if (startPaint)
g.fillOval(x-radius,y-radius, 2*radius, 2*radius);
else
super.paintComponent(g);
}
public void mouseDragged(MouseEvent e)
{
startPaint = true;
x = e.getX();
y = e.getY();
repaint();
}
public void mouseMoved(MouseEvent e)
{
}
}
}

How do i get my action listener to remove the contents from the current JPanel?

I am trying to add a button which will when pressed, clear the contents off the JPanel and return the panel back to its original set-up. How would i go about doing this? I have tried to revalidate, removeall etc but none have worked for me so far. Any suggestions on how i can do this? I will attach the code below, Help would be greatly appreciated.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class WindowBlind extends JFrame
implements ChangeListener, ActionListener {
private JSlider slider;
private int sliderValue = 0;
private JPanel panel;
private JButton open;
private JButton close;
private JButton exit;
private boolean clear;
public static void main(String[] args) {
WindowBlind applic = new WindowBlind();
applic.setLocation(100,100);
applic.setVisible(true);
} // main
public WindowBlind() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("WindowBlind");
setSize(300,300);
Container window = getContentPane();
window.setLayout(new FlowLayout());
panel = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
paintScreen(g);
} // paintComponent
};
panel.setPreferredSize(new Dimension(200, 200));
panel.setBackground(Color.white);
window.add(panel);
slider = new JSlider(JSlider.VERTICAL,0,100,0);
slider.setInverted(true); // 0 will be at top, not bottom, of vertical slider
window.add(slider);
slider.addChangeListener(this); // Register for slider events
JButton open = new JButton("Open Slider");
window.add(open);
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
JButton close = new JButton("Close Slider");
window.add(close);
close.addActionListener(this);
JButton exit = new JButton("Exit Slider");
window.add(exit);
exit.addActionListener(this);
} // WindowBlind constructor
public void paintScreen(Graphics g) {
g.setColor(Color.cyan);
g.fillRect(70, 40, 60, 100); // The blue sky
g.setColor(Color.lightGray);
g.fillRect(70, 40, 60, sliderValue); // The blind, partially closed
g.setColor(Color.black);
g.drawRect(70, 40, 60, 100); // The window frame
} // paintScreen
// When the slider is adjusted, this method is called automatically
public void stateChanged(ChangeEvent e) {
sliderValue = slider.getValue(); // Fetch the slider's current setting
repaint(); // Force a screen refresh (paintComponent is called indirectly)
} // stateChanged
#Override
public void actionPerformed(ActionEvent e) {
}
}
I'm taking a HUGE guess and assuming you want to reset the slider to it's "default" state, which would suggest that you need to change the sliderValue, something like...
close.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sliderValue = 0;
slider.repaint();
}
});
A better solution would be to generate a self contained class which encapsulated all this functionality, for example...
public class SliderPane extends JPanel {
private double sliderValue;
public double getSliderValue() {
return sliderValue;
}
public void setSliderValue(double sliderValue) {
this.sliderValue = Math.max(Math.min(1.0, sliderValue), 0);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
g.setColor(Color.cyan);
g.fillRect(0, 0, width, height); // The blue sky
g.setColor(Color.lightGray);
g.fillRect(0, 0, width, (int)(sliderValue * height)); // The blind, partially closed
g.setColor(Color.black);
g.drawRect(0, 0, width, height); // The window frame
}
}
Then you could control the slider value through the setSliderValue method.
This also allows you to specify the slider value as percentage, meaning that the size of the component doesn't matter as the area filled is a percentage of the height
This is because you always call paintScreen from the panel's paintComponent method. I would suggest this midification:
panel = new JPanel() {
boolean drawMe = true;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(drawMe)
paintScreen(g);
} // paintComponent
};
Whenever you want to clear the panel, do this:
panel.drawMe=false;
panel.invalidate();

Transparent JFrame doesn't clear on repaint

When I try to repaint a transparent window, and draw a rectangle on it, the previous rectangle will stay. The goal is to select an area on your screen by clicking and moving your mouse. It'll look like this if you move your mouse for a while
By removing the transparency it works just fine.
I tried everything I could find on Stack Overflow about this topic, But I wasn't able to get it working on both Windows and Linux.
Main class
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class Main {
private JFrame frame;
private boolean pressing = false;
private boolean selected = false;
private ScreenSelectPanel p;
public Main() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame = new JFrame("ScreenSelection");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(dim);
frame.setUndecorated(true);
frame.setContentPane(p = new ScreenSelectPanel());
registerListeners();
frame.getContentPane().setBackground(new Color(255, 255, 255, 0));
frame.setBackground(new Color(255, 255, 255, 0));
frame.setLayout(new BorderLayout());
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
private void registerListeners() {
p.setFocusable(true);
p.requestFocusInWindow();
p.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (selected)
return;
setLoc(e);
p.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (selected)
return;
setLoc(e);
if (!pressing)
setStartLoc(e);
p.repaint();
}
});
p.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
setLoc(e);
setStartLoc(e);
p.repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
setLoc(e);
setStartLoc(e);
p.repaint();
}
});
}
public void setStartLoc(MouseEvent e) {
p.mouseStartX = e.getX();
p.mouseStartY = e.getY();
}
public void setLoc(MouseEvent e) {
p.mouseX = e.getX();
p.mouseY = e.getY();
}
public static void main(String[] args) {
new Main();
}
}
ScreenSelectPanel class
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
public class ScreenSelectPanel extends JPanel {
public int mouseX = 0;
public int mouseY = 0;
public int mouseStartX = 0;
public int mouseStartY = 0;
private Color borderColor;
public ScreenSelectPanel() {
setOpaque(false);
borderColor = Color.BLACK;
}
public void setBorderColor(Color c) {
this.borderColor = c;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(borderColor);
Rectangle rect = new Rectangle();
rect.setFrameFromDiagonal(new Point2D.Float(mouseStartX, mouseStartY), new Point2D.Float(mouseX, mouseY));
Stroke dashed = new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{9}, 0);
g2d.setStroke(dashed);
g2d.drawRect(rect.x, rect.y, rect.width, rect.height);
g2d.dispose();
}
}
Thanks :)
You can't use transparency with Swing components. A transparent background causes these types of painting problems. A Swing component is either opaque or non-opaque.
Check out Backgrounds With Transparency for more information on this problem. However in this cause it is not the problem because you are trying to use full transparency on the Swing panel.
When I try to repaint a transparent window, and draw a rectangle on it, the previous rectangle will stay.
The code you posted does anything (at least on Windows). When you set a frame to be completely transparent then the MouseEvents are no longer handled by Swing and instead are handled by the application below the frame.
I made the following changes to your code and it seems to work for me:
//frame.getContentPane().setBackground(new Color(255, 255, 255, 0));
//frame.setBackground(new Color(255, 255, 255, 0));
frame.setBackground(new Color(255, 255, 255, 10));

Java color changing Graphics with Timer

I want to draw a disc that changes colors twice a second. The disk is drawn on a DrawPanel which extends a JPanel and in the main method the DrawPanel is added to a frame.
For the colorchanging I use a timer which works when I'm trying to change the background of the DrawPanel in the main method (what i commented out).
Can someone tell me why it doesn't work for the Graphics g object or any other suggestions?
I just copied the code from the main method and added it into the paintComponent() method, but here it doesn't work.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class DrawPanel extends JPanel{
public GridBagLayout gbl;
//position and dimension
int x = 0, y = 0, width = 200, height = 200;
public DrawPanel(){
repaint();
}
public DrawPanel(GridBagLayout gridBagLayout) {
this.gbl = gridBagLayout;
}
public void paintComponent(Graphics g){
//Overwriting of old picture
super.paintComponent(g);
ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Random gen = new Random();
Color color = new Color(gen.nextInt(256), gen.nextInt(256), gen.nextInt(256));
//Draw color disk
g.setColor(color);
g.fillArc(x, y, width, height, 0, 360);
}
};
Timer t = new Timer(500, action);
t.setRepeats(true);
t.setInitialDelay(0);
t.start();
//Draw boundary of circle
g.setColor(Color.BLACK);
g.drawArc(x, y, width, height, 0, 360);
}
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setSize(300, 300);
final DrawPanel panel = new DrawPanel();
panel.setOpaque(true);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
// ActionListener action = new ActionListener() {
// #Override
// public void actionPerformed(ActionEvent e) {
// Random gen = new Random();
// Color color = new Color(gen.nextInt(256), gen.nextInt(256), gen.nextInt(256));
// panel.setBackground(color);
// }
// };
//
// Timer t = new Timer(500, action);
// t.setRepeats(true);
// t.setInitialDelay(0);
// t.start();
}
}
The Graphics object is transient, so you should not cache it even if the compiler allows that. Instead establish the timer in the constructor of the class, set the BG of the panel, then call for a repaint. E.G.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class DrawPanel extends JPanel {
Random gen = new Random();
//position and dimension
int x = 0, y = 0, width = 200, height = 200;
Color drawColor = Color.BLACK;
public DrawPanel() {
repaint();
ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Color color = new Color(gen.nextInt(256), gen.nextInt(256), gen.nextInt(256));
//Draw color disk
drawColor = color;
DrawPanel.this.repaint();
}
};
Timer t = new Timer(500, action);
t.setRepeats(true);
t.setInitialDelay(0);
t.start();
}
#Override
public void paintComponent(Graphics g) {
//Overwriting of old picture
super.paintComponent(g);
//Draw boundary of circle
g.setColor(drawColor);
g.drawArc(x, y, width, height, 0, 360);
}
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setSize(300, 300);
final DrawPanel panel = new DrawPanel();
panel.setOpaque(true);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Graphics objects are only valid for that one draw
It would be better to instead to tell the JPanel to change it's current color (with a variable) and then tell it to repaint
Add variable discColor to your JPanel
Change your drawing code to not use timers and instead make it simple, just draw the disc based off of discColor
With a timer, update the discColor variable and then call the panel's repaint() method

Do I actually call the paintComponent method I make when creating a rectangle in Java?

This is my current RectangleComponent class and I add it to a panel in my main JFrame but it never appears. I thought it wasn't drawing so I decided to call the paintComponent method in the Rectangle's constructor, and after sorting through 4-5 nullPointerExceptions, nothing has changed. I've read multiple guides on how to draw rectangles and I have seen multiple code examples, but I can never get the panels to work with more than one JComponent. If you could, please take a brief look at my code and see if you can devise a solution.
Thank you for your time. Also listed is the Frame I call the rectangle constructor in.
public class GameFrame extends JFrame
{
private SpellBarComponent bar;
private JPanel mainPanel = new JPanel();
private JPanel buttonPanel = new JPanel();
private JPanel healthPanel = new JPanel();
Color green = new Color(29, 180, 29);
Color red = new Color(255, 0, 0);
private RectangleComponent life;
private RectangleComponent death;
private JFrame frame = new JFrame();
public GameFrame(char x)
{
frame.setSize(1024, 768);
frame.setTitle("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
FlowLayout layout = new FlowLayout();
createPanels(x);
healthPanel.setLayout(layout);
buttonPanel.setLayout(layout);
mainPanel.setLayout(layout);
frame.getContentPane().add(mainPanel);
frame.pack();
repaint();
}
public RectangleComponent getLife()
{
return life;
}
private void createHealth()
{
life = new RectangleComponent(green, healthPanel);
death = new RectangleComponent(red, healthPanel);
}
private void createPanels(char x)
{
add(healthPanel);
pack();
createBar(x);
createHealth();
mainPanel.add(buttonPanel);
mainPanel.add(healthPanel);
healthPanel.add(death);
healthPanel.add(life);
buttonPanel.add(bar.getSpell1());
buttonPanel.add(bar.getSpell2());
buttonPanel.add(bar.getSpell3());
add(mainPanel);
}
private void createBar(char x)
{
bar = new SpellBarComponent(x, mainPanel);
}
}
public class RectangleComponent extends JComponent
{
Color color;
int width;
int height = 18;
RoundRectangle2D roundedRectangle;
private JPanel panel;
public RectangleComponent(Color color, JPanel panel)
{
this.panel = panel;
this.color = color;
paintComponent(panel.getGraphics());
}
public void paintComponent(Graphics g)
{
Graphics2D graphics2 = (Graphics2D) g;
width = 125;
roundedRectangle = new RoundRectangle2D.Float(10, 10, width, height, 10, 10);
graphics2.setPaint(color);
graphics2.fill(roundedRectangle);
graphics2.draw(roundedRectangle);
}
public void subtractLife(int amount)
{
width -= amount;
roundedRectangle.setRoundRect(10, 10, width, height, 10, 10);
repaint();
}
}
In order for your Swing Application to work as expected, there are many a things you need to keep in mind. There are always certain steps that one must follow in order to escape certain hurdles, that might can arise, since you coded in the wrong way. For this stick to the basics of Swing Programming Strictly, and follow them.
Like as mentioned by #HovercraftFullOfEels , you calling to your
Graphics directly, which one should never do.
Secondly, look at your GameFrame() constructor, you set it to
visible, even before you had added any components to it and much
before it's real size has been established
Such loop holes inside your coding might can give rise to many a headaches, as you sit down to write huge programs, so better to be on the safe road from the beginning, then to curse yourself at the later stage. As they say Prevention is better than Cure.
Now coming to your program, you missed the main thingy, since you failed to specify the size of your CustomComponent i.e. JComponent, hence you are not been able to see it on your screen. As you extends a JCompoent to your class, make it a customary habbit to override it's getPreferredSize(), in the same manner you override it's paintComponent(...) method.
Have a look at this small program, I had crafted for you, might be this be able to help you out, to understand the logic a bit more.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;
public class CustomPainting {
private RectangleComponent life;
private RectangleComponent death;
private void createAndDisplayGUI() {
JFrame frame = new JFrame("Custom Painting");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(0, 2, 5, 5));
// Specifying the WIDTH, HEIGHT and Colour for this JComponent.
life = new RectangleComponent(Color.GREEN.darker(), 20, 20);
death = new RectangleComponent(Color.RED.darker(), 20, 20);
centerPanel.add(life);
centerPanel.add(death);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
JButton incLifeButton = new JButton("INCREASE LIFE");
incLifeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
life.addLife(1);
}
});
JButton decLifeButton = new JButton("DECREASE LIFE");
decLifeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
life.subtractLife(1);
}
});
JButton incDeathButton = new JButton("INCREASE DEATH");
incDeathButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
death.addLife(1);
}
});
JButton decDeathButton = new JButton("DECREASE DEATH");
decDeathButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
death.subtractLife(1);
}
});
buttonPanel.add(incLifeButton);
buttonPanel.add(decLifeButton);
buttonPanel.add(incDeathButton);
buttonPanel.add(decDeathButton);
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String\u005B\u005D args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new CustomPainting().createAndDisplayGUI();
}
});
}
}
class RectangleComponent extends JComponent {
private Color colour;
private static final int MARGIN = 10;
private int width;
private int height;
private int originalWidth;
private RoundRectangle2D roundedRectangle;
public RectangleComponent(Color c, int w, int h) {
colour = c;
width = w;
height = h;
originalWidth = width;
}
/*
* Overriding this method, so that
* the size of the JComponent
* can be determined, on the screen
* or by the LayoutManager concern.
*/
#Override
public Dimension getPreferredSize() {
return (new Dimension(width, height));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
roundedRectangle = new RoundRectangle2D.Float(MARGIN, MARGIN,
width, height, MARGIN, MARGIN);
g2d.setPaint(colour);
g2d.draw(roundedRectangle);
g2d.fill(roundedRectangle);
}
public void subtractLife(int amount) {
width -= amount;
System.out.println("ORIGINAL Width : " + originalWidth);
System.out.println("Width : " + width);
if (width > 0) {
roundedRectangle.setRoundRect(MARGIN, MARGIN, width, height,
MARGIN, MARGIN);
/*
* This repaint() will call the paintComponent(...)
* by itself, so nothing else to be done.
*/
repaint();
} else {
width += amount;
}
}
public void addLife(int amount) {
width += amount;
System.out.println("ORIGINAL Width : " + originalWidth);
System.out.println("Width : " + width);
if (width < originalWidth) {
roundedRectangle.setRoundRect(MARGIN, MARGIN, width, height,
MARGIN, MARGIN);
repaint();
} else {
width -= amount;
}
}
}
Do ask any question, that might can arise as you go through this program :-), I be HAPPY to help on that :-)
**LATEST EDIT WITH TWO COLOURS : **
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;
public class CustomPainting {
private RectangleComponent lifeDeath;
private void createAndDisplayGUI() {
JFrame frame = new JFrame("Custom Painting");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(0, 2, 5, 5));
// Specifying the WIDTH, HEIGHT and Colour for this JComponent.
lifeDeath = new RectangleComponent(Color.GREEN, Color.RED, 20, 20);
centerPanel.add(lifeDeath);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 2, 5, 5));
JButton incLifeButton = new JButton("INCREASE LIFE");
incLifeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
lifeDeath.addLife(1);
}
});
JButton decLifeButton = new JButton("DECREASE LIFE");
decLifeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
lifeDeath.subtractLife(1);
}
});
buttonPanel.add(incLifeButton);
buttonPanel.add(decLifeButton);
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String\u005B\u005D args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new CustomPainting().createAndDisplayGUI();
}
});
}
}
class RectangleComponent extends JComponent {
private Color lifeColour;
private Color deathColour;
private static final int MARGIN = 10;
private int widthLife;
private int widthDeath;
private int height;
private int originalWidth;
private RoundRectangle2D roundedRectangle;
public RectangleComponent(Color lc, Color dc, int w, int h) {
lifeColour = lc;
deathColour = dc;
widthLife = w;
height = h;
originalWidth = widthLife;
widthDeath = 0;
}
/*
* Overriding this method, so that
* the size of the JComponent
* can be determined, on the screen
* or by the LayoutManager concern.
*/
#Override
public Dimension getPreferredSize() {
return (new Dimension(originalWidth, height));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
roundedRectangle = new RoundRectangle2D.Float((MARGIN + widthDeath), MARGIN,
widthLife, height, MARGIN, MARGIN);
g2d.setPaint(lifeColour);
g2d.draw(roundedRectangle);
g2d.fill(roundedRectangle);
roundedRectangle.setRoundRect(MARGIN, MARGIN,
widthDeath, height, MARGIN, MARGIN);
g2d.setPaint(deathColour);
g2d.draw(roundedRectangle);
g2d.fill(roundedRectangle);
}
public void subtractLife(int amount) {
widthLife -= amount;
widthDeath += amount;
System.out.println("ORIGINAL Width : " + originalWidth);
System.out.println("Width Life : " + widthLife);
System.out.println("Width Death : " + widthDeath);
if (widthLife > 0 && widthDeath < originalWidth) {
/*
* This repaint() will call the paintComponent(...)
* by itself, so nothing else to be done.
*/
repaint();
} else {
widthLife += amount;
widthDeath -= amount;
}
}
public void addLife(int amount) {
widthLife += amount;
widthDeath -= amount;
System.out.println("ORIGINAL Width : " + originalWidth);
System.out.println("Width Life : " + widthLife);
System.out.println("Width Death : " + widthDeath);
if (widthLife < originalWidth && widthDeath > 0) {
repaint();
} else {
widthLife -= amount;
widthDeath += amount;
}
}
}
No need to pass JPanel to the constructor of RectangleComponent just to get Graphics, and no need to manually call paintComponent. See Painting in AWT and Swing. Check out this example that demonstrates a custom component that paints a rectangle.
Your code is a bit creative, a bit crazy, and with logic that is very hard to follow. The most unusual aspect is that it has two JFrames, one called "frame", and one the GameFrame object itself, both of which get components added, but only one of which shows. You also have many methods that return void (which if over-used increases code smell) and only add to making the code more confusing.
For example,
public GameFrame(char x) {
// here you set up the "frame" JFrame
frame.setSize(1024, 768);
frame.setTitle("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
FlowLayout layout = new FlowLayout();
createPanels(x);
healthPanel.setLayout(layout);
buttonPanel.setLayout(layout);
mainPanel.setLayout(layout);
// here you add content to the frame JFrame, and pack it
frame.getContentPane().add(mainPanel);
frame.pack();
repaint(); // and then call repaint on the "this" JFrame?
}
public RectangleComponent getLife() {
return life;
}
private void createHealth() {
life = new RectangleComponent(green, healthPanel);
death = new RectangleComponent(red, healthPanel);
}
private void createPanels(char x) {
add(healthPanel); // now you add content to the "this" JFrame
pack(); // and pack it
createBar(x);
createHealth();
mainPanel.add(buttonPanel);
mainPanel.add(healthPanel); // and then re-add a JPanel into a second JPanel?
healthPanel.add(death);
healthPanel.add(life);
buttonPanel.add(bar.getSpell1());
buttonPanel.add(bar.getSpell2());
buttonPanel.add(bar.getSpell3());
add(mainPanel); // and then re -add the mainPanel into the "this" JFrame???
}
This is all very confusing, and not likely going to work.
Then there's your trying to call paintComponent directly and calling getGraphics on a JComponent, both of which should not be done. You will want to go through the graphics tutorials to see how to do this correctly.
I recommend that you consider re-writing this, and first and foremost, using only one JFrame, and organizing your code better.

Categories