How can I draw vertical line when I press the button? - java

I am unable to draw line when I press the component in Java Swing. How can I do this? I already used paint method, my problem is when program executes paint method invoke automatically, DrawLine() method will be there in paint method, so is there any way that I can get the lines other than paint method?
Please give some suggestion.
Below code I have tried, it's displaying lines but I want to display the lines when I click the component.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class ReferenceLink1 extends JFrame
{
JLabel l1;
JLabel l2;
JPanel p1;
ReferenceLink1()
{
p1 = new JPanel();
p1.setLayout(null);
p1.setBackground(Color.ORANGE);
p1.setOpaque(true);
p1.setBounds(0,0,300,400);
setLayout(null);
l1 = new JLabel();
l1.setText("l1");
l1.setBounds(20, 40, 100, 40);
l1.setHorizontalAlignment(SwingConstants.CENTER);
l1.setBackground(Color.GREEN);
l1.setOpaque(true);
l2 = new JLabel(); ;
l2.setText("l2");
l2.setBounds(20, 100,100,40);
l2.setBackground(Color.BLUE);
l2.setHorizontalAlignment(SwingConstants.CENTER);
l2.setOpaque(true);
p1.add(l1);
p1.add(l2);
add(p1);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setBounds(0,0,400,400);
}
public void paint(Graphics g)
{
super.paint(g);
g.drawLine(77,110,77,130);
}
public static void main(String args[])
{
ReferenceLink1 rf = new ReferenceLink1();
}
}

class Surface extends JPanel {
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
Dimension size = getSize();
Insets insets = getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random r = new Random();
for (int i = 0; i < 1000; i++) {
int x = Math.abs(r.nextInt()) % w;
int y = Math.abs(r.nextInt()) % h;
g2d.drawLine(x, y, x, y);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
public class Points extends JFrame {
public Points() {
initUI();
}
private void initUI() {
setTitle("Points");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Surface());
setSize(350, 250);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Points ps = new Points();
ps.setVisible(true);
}
});
}
}

You could simply add a mouse listener to the label that represents your button.
l2.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
p1.getGraphics().drawLine(77,110,77,130);
}
});

public class ReferenceLink1 extends JFrame {
JLabel l1;
JButton l2;
JPanel p1;
public static class MyListener implements ActionListener{
Graphics g;
public MyListener(Graphics g) {
this.g = g;
}
#Override
public void actionPerformed(ActionEvent e) {
g.drawLine(77, 110, 77, 130);
}
}
public ReferenceLink1() {
p1 = new JPanel();
setVisible(true);
p1.setLayout(null);
p1.setBackground(Color.ORANGE);
p1.setOpaque(true);
p1.setBounds(0,0,300,400);
setLayout(null);
l1 = new JLabel();
l1.setText("l1");
l1.setBounds(20, 40, 100, 40);
l1.setHorizontalAlignment(SwingConstants.CENTER);
l1.setBackground(Color.GREEN);
l1.setOpaque(true);
l2 = new JButton();
l2.addActionListener(new MyListener(this.getGraphics()));
l2.setText("l2");
l2.setBounds(20, 100,100,40);
l2.setBackground(Color.BLUE);
l2.setHorizontalAlignment(SwingConstants.CENTER);
l2.setOpaque(true);
p1.add(l1);
p1.add(l2);
add(p1);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(0,0,400,400);
}
public static void main(String args[]) {
ReferenceLink1 rf = new ReferenceLink1();
}
}

Related

Repaint method not working on JComponent java swing

I want to have a text field to input an integer, then select 1) Grow or 2) Shrink, and then click the button so that the circle gets redrawn on the screen based on the selected options.
I don't know why it isn't repaining. (Don't worry about the layout, just want to get it to work first)
My Frame:
public class Main {
public static void main(String[] args) {
var frame = new JFrame();
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
var circleComp = new circleComponent();
var panel1 = new JPanel();
var multiplierLabel = new JLabel("Grow Multiplier");
var multiplierField = new JTextField(20);
var radio1 = new JRadioButton("Grow Circle");
var radio2 = new JRadioButton("Shrink Circle");
var bg = new ButtonGroup();
bg.add(radio1);
bg.add(radio2);
JButton button = new JButton("Rivizato");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(radio1.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())*rrComp.getWidth(), Integer.parseInt(multiplierField.getText())*rrComp.getHeight());
}
else if(radio2.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())/rrComp.getWidth(), Integer.parseInt(multiplierField.getText())/rrComp.getHeight());
}
}
}
);
panel1.add(multiplierLabel);
panel1.add(multiplierField);
panel1.add(button);
panel1.add(radio1);
panel1.add(radio2);
frame.add(panel1);
frame.add(circleComp);
}
}
My CircleComponent class:
public class CircleComponent extends JComponent {
public void paintComponent(Graphics g){
super.paintComponent(g);
var g2 = (Graphics2D) g;
var circle = new Ellipse2D.Double(0,0,100,100);
g2.draw(circle);
}
}
var circle = new Ellipse2D.Double(0,0,100,100); means that your circle will never change size.
You should also be careful with repaint(x, y, width, height) as it could leave regions of your component "dirty". Better to just use repaint.
As a conceptual example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private CirclePane circlePane;
public MainPane() {
setLayout(new BorderLayout());
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton growButton = new JButton("Grow");
growButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.grow();
}
});
JButton shrinkButton = new JButton("Shrink");
shrinkButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.shrink();
}
});
actionsPane.add(growButton);
actionsPane.add(shrinkButton);
circlePane = new CirclePane();
add(circlePane);
add(actionsPane, BorderLayout.SOUTH);
}
}
public class CirclePane extends JPanel {
private Ellipse2D circle;
public CirclePane() {
circle = new Ellipse2D.Double(0, 0, 100, 100);
}
public void grow() {
double width = circle.getWidth() + 10;
double height = circle.getHeight() + 10;
circle.setFrame(0, 0, width, height);
repaint();
}
public void shrink() {
double width = Math.max(0, circle.getWidth() - 10);
double height = Math.max(0, circle.getHeight() - 10);
circle.setFrame(0, 0, width, height);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double x = (getWidth() - circle.getWidth()) / 2d;
double y = (getHeight() - circle.getHeight()) / 2d;
g2d.translate(x, y);
g2d.draw(circle);
g2d.dispose();
}
}
}
nb: I know I've not used JTextField to specify the size of the circle, that's on purpose. You will need to adapt your requirements to work in a similar way - can you see where you might pass parameters to the CirclePane?

Drawing rectangle within the loop?

I'm trying to animate a rectangle based on a coordinate determined by for-loop, inside a button. Here is my JComponent Class:
public class Rect extends JComponent {
public int x;
public int y;
public int w;
public int h;
public Rect (int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
repaint();
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(Color.green);
g2.drawRect(x+15, y+15, w, h);
}
}
and here is my button and button inside JFrame class:
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
}
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
validate();
repaint();
}
}
});
}
But when I run the code and click the button, nothing happens. What's wrong?
EDIT: I run the frame inside my main class like this:
public class OrImage {
public static void main(String[] args) throws Exception
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
});
}
}
I changed the code of class MainFrame such that when you press the animate button, something happens, but I don't know if that is what you want to happen.
I did not change class Rect and I added main() method to MainFrame just to keep everything in one class.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
lm.add(R);
}
lm.revalidate();
lm.repaint();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
The main change is in method actionPerformed(). You need to add R to the JPanel. You need to call revalidate() on the JPanel because you have changed the number of components that it contains. And after calling revalidate() you should call repaint() (again, on the JPanel) to make it redraw itself.
This is how it looks before pressing animate.
And this is how it looks after pressing animate
EDIT
As requested – with animation.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
private int x;
private int y;
private Timer timer;
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
timer = new Timer(500, event -> {
if (x < 500) {
lm.remove(R);
x += 50;
y += 50;
R = new Rect(x, y, 50, 50);
lm.add(R);
lm.revalidate();
lm.repaint();
}
else {
timer.stop();
}
});
timer.setInitialDelay(0);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}

Buttons are not displaying until mouse hover on it in java

JButtons are not displayed until or unless I hover on the buttons.
package paint;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* #author Rehan Shakir
*/
public class PaintFrame extends JFrame implements MouseMotionListener,ActionListener
{
private int x=0;
private int y=0;
private final JButton red,yellow,blue,green;
private final JPanel p;
//private final JLabel l;
private final Container c;
private Color color;
public PaintFrame()
{
setTitle("Paint");
setSize(800,600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//setLayout(new FlowLayout());
p = new JPanel();
p.setLayout(new GridLayout(4,1));
red = new JButton("Red");
red.setBackground(Color.red);
p.add(red);
yellow = new JButton("Yellow");
yellow.setBackground(Color.yellow);
p.add(yellow);
blue = new JButton("Blue");
blue.setBackground(Color.blue);
p.add(blue);
green = new JButton("Green");
green.setBackground(Color.green);
p.add(green);
red.addActionListener(this);
yellow.addActionListener(this);
blue.addActionListener(this);
green.addActionListener(this);
c = this.getContentPane();
c.setLayout(new BorderLayout());
JLabel l = new JLabel("Drag the mouse to draw",JLabel.RIGHT);
c.add(l,BorderLayout.SOUTH);
c.add(p,BorderLayout.WEST);
c.addMouseMotionListener(this);
setVisible(true);
}
#Override
public void mouseDragged(MouseEvent e )
{
x= e.getX();
y= e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e)
{
}
#Override
public void actionPerformed(ActionEvent e)
{
String s = e.getActionCommand();
if(s.equals("Red"))
color = Color.red;
else if(s.equals("Yellow"))
color = Color.yellow;
else if(s.equals("Blue"))
color = Color.blue;
else if(s.equals("Green"))
color = Color.green;
else
color = Color.BLACK;
}
#Override
public void paint(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, 4, 4);
}
}
Main Class
public class Paint {
package paint;
public static void main(String[] args) {
// TODO code application logic here
PaintFrame Jf = new PaintFrame();
}
}
When I execute this program only the first JButton is displayed on the screen. I have to hover on other buttons so that they can be displayed on the screen.
Why does this happen?
Immediately from your title, I could guess that you weren't calling the super's painting method in your override -- and I was right:
#Override
public void paint(Graphics g)
{
// ********** no super call here! *******
g.setColor(color);
g.fillOval(x, y, 4, 4);
}
By not doing this, you're not allowing the component to do its important house-keeping painting, including the painting of child components and removal of "dirty" pixels
This:
#Override
public void paint(Graphics g)
{
super.paint(g);
g.setColor(color);
g.fillOval(x, y, 4, 4);
}
will likely fix things
Having said this, I must add:
Don't paint directly in a JFrame
Do paint in the paintComponent method override of a class that extends JPanel instead
Call the super.paintComponent(g) in your JPanel's overridden method (for the same reasons).
Example using a BufferedImage:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class MainPaintPanel extends JPanel {
private PaintPanel paintPanel = new PaintPanel();
public MainPaintPanel() {
MyMouse myMouse = new MyMouse();
paintPanel.addMouseListener(myMouse);
paintPanel.addMouseMotionListener(myMouse);
JPanel btnPanel = new JPanel(new GridLayout(0, 1, 3, 3));
addColorButton(btnPanel, Color.RED, "Red");
addColorButton(btnPanel, Color.YELLOW, "Yellow");
addColorButton(btnPanel, Color.BLUE, "Blue");
addColorButton(btnPanel, Color.GREEN, "Green");
setLayout(new BorderLayout());
add(paintPanel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.LINE_START);
}
class MyMouse extends MouseAdapter {
Point p1 = null;
private void moveOval(MouseEvent e) {
if (p1 == null) {
return;
}
Point p2 = e.getPoint();
paintPanel.addLine(p1, p2);
}
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
moveOval(e);
p1 = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
moveOval(e);
p1 = null;
}
}
private void addColorButton(JPanel btnPanel, Color color, String name) {
JButton button = new JButton(new ButtonAction(name, color));
button.setBackground(color);
btnPanel.add(button);
}
class ButtonAction extends AbstractAction {
private Color color;
public ButtonAction(String name, Color color) {
super(name);
this.color = color;
}
#Override
public void actionPerformed(ActionEvent e) {
paintPanel.setOvalColor(color);
}
}
private static void createAndShowGui() {
MainPaintPanel mainPanel = new MainPaintPanel();
JFrame frame = new JFrame("Painting GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class PaintPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final int OVAL_WIDTH = 4;
private static final Stroke BASIC_STROKE = new BasicStroke(OVAL_WIDTH);
private BufferedImage img;
private Color ovalColor;
public PaintPanel() {
img = new BufferedImage(PREF_W, PREF_W, BufferedImage.TYPE_INT_ARGB);
}
public void addLine(Point p1, Point p2) {
if (img != null && ovalColor != null) {
Graphics2D g2 = img.createGraphics();
g2.setStroke(BASIC_STROKE);
g2.setColor(ovalColor);
g2.drawLine(p1.x, p1.y, p2.x, p2.y);
g2.dispose();
repaint();
}
}
public void setOvalColor(Color ovalColor) {
this.ovalColor = ovalColor;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}

Java Doesn't draw on JPanel

This is my main class:
public class Sad {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Sad window = new Sad();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Sad() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 512, 399);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel();
frame.getContentPane().add(panel, "name_12361565901507");
panel.setLayout(null);
JButton btnNes = new JButton("Nes");
btnNes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Grafik grafik = new Grafik(20, 20, 100);
panel.add(grafik);
}
});
btnNes.setBounds(90, 146, 89, 23);
panel.add(btnNes);
}
}
And this is drawing class
public class Grafik extends JPanel{
private int x;
private int y;
private int r;
public Grafik(int x, int y, int r){
this.x = x;
this.y = y;
this.r = r;
}
public void paintComponent(Graphics g) {
Graphics2D g2 =(Graphics2D) g;
Ellipse2D circ = new Ellipse2D.Float(x, y, r, r);
g2.setColor(Color.RED);
g2.draw(circ);
}
}
They are in same package. And when i click button its suposed to draw Ellipse in red color, but it doesn't show anything. Can someone help me? BTW Sorry for bad english
It's because you don't call panel.setBounds(), revalidate() and repaint().
But you shouldn't use a null layout anyway: Use layout
managers.
You should call super.paintComponent(g) at the beginning of
the paintComponent method.
Rather than adding a new component to the panel after every button press you might want to just toggle a boolean value inside the Grafik instance which determines wheter the ellipse should be visible or not.
If you want the ellipse to be "smooth", you can call g2.setRenderingHint(hintKey, hintValue).
Modified code including my suggestions:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Sad {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Sad window = new Sad();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Sad() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 512, 399);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Grafik grafik = new Grafik(20, 20, 100);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(grafik);
JButton btnNes = new JButton("Nes");
btnNes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
grafik.setEllipseVisible(true);
panel.repaint();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(btnNes);
panel.add(btnPanel, BorderLayout.SOUTH);
frame.setContentPane(panel);
}
}
class Grafik extends JPanel {
private int x;
private int y;
private int r;
private boolean ellipseVisible;
public Grafik(int x, int y, int r) {
this.x = x;
this.y = y;
this.r = r;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (isEllipseVisible()) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Ellipse2D circ = new Ellipse2D.Float(x, y, r, r);
g2.setColor(Color.RED);
g2.draw(circ);
}
}
public boolean isEllipseVisible() {
return ellipseVisible;
}
public void setEllipseVisible(boolean ellipseVisible) {
this.ellipseVisible = ellipseVisible;
}
}

JLayeredPane and painting

I am writing an application which has a JLayeredPane (call it layers) containing two JPanels in different layers. I override the paintComponent method of the JPanel at the bottom (call it grid_panel) so it paints a grid, and the the paintComponent method of the one at the top (call it circuit_panel) so it paints a circuit.
Here's a summary of the structure:
layers -
|-circuit_panel (on top)
|-grid_panel (at bottom)
I want the grid_panel to stay static, ie, not to do any repaint (except the initial one) since it does not change.
The trouble is, whenever I call circuit_panel.repaint(), grid_panel gets repainted as well! This is a definitely not efficient.
I think this is due to the eager painting behavior of JLayeredPane. Is there a way to disable this feature in JLayeredPane?
In case you're interested to see the above effect, I've written a small demo program:
public class Test2 extends JFrame {
public Test2() {
JLayeredPane layers = new JLayeredPane();
layers.setPreferredSize(new Dimension(600, 400));
MyPanel1 myPanel1 = new MyPanel1();
MyPanel2 myPanel2 = new MyPanel2();
myPanel1.setSize(600, 400);
myPanel2.setSize(600, 400);
myPanel1.setOpaque(false);
myPanel2.setOpaque(false);
myPanel2.addMouseListener(new MyMouseListener(myPanel2));
layers.add(myPanel1, new Integer(100)); // At bottom
layers.add(myPanel2, new Integer(101)); // On top
this.getContentPane().add(layers, BorderLayout.CENTER);
this.setSize(600, 400);
}
class MyPanel1 extends JPanel {
Color getRandomColor() {
int r = (int) (256 * Math.random());
int g = (int) (256 * Math.random());
int b = (int) (256 * Math.random());
return new Color(r, g, b);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getRandomColor());
g2d.fillRoundRect(30, 30, 60, 60, 5, 5);
}
}
class MyPanel2 extends JPanel {
Color getRandomColor() {
int r = (int) (256 * Math.random());
int g = (int) (256 * Math.random());
int b = (int) (256 * Math.random());
return new Color(r, g, b);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getRandomColor());
g2d.fillRoundRect(45, 45, 75, 75, 5, 5);
}
}
class MyMouseListener extends MouseAdapter {
JPanel panel;
MyMouseListener(JPanel panel) {
this.panel = panel;
}
#Override
public void mouseClicked(MouseEvent e) {
panel.repaint();
}
}
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
(new Test2()).setVisible(true);
}
});
}
}
As you found, a BufferedImage is an effective way to cache complex content for efficient rendering; CellTest is an example. A flyweight renderer, shown here, is another approach. Finally, I've re-factored your instructive example in a way that may make experimentation easier.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/** #see https://stackoverflow.com/q/9625495/230513 */
public class LayerDemo extends JFrame {
private static final Dimension d = new Dimension(320, 240);
public LayerDemo() {
JLayeredPane layers = new JLayeredPane();
layers.setPreferredSize(d);
layers.add(new LayerPanel(1 * d.height / 8), 100);
layers.add(new LayerPanel(2 * d.height / 8), 101);
layers.add(new LayerPanel(3 * d.height / 8), 102);
this.add(layers, BorderLayout.CENTER);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setLocationByPlatform(true);
}
private static class LayerPanel extends JPanel {
private static final Random r = new Random();
private int n;
private Color color = new Color(r.nextInt());
public LayerPanel(int n) {
this.n = n;
this.setOpaque(false);
this.setBounds(n, n, d.width / 2, d.height / 2);
this.addMouseListener(new MouseHandler(this));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
g2d.setColor(Color.black);
g2d.drawString(String.valueOf(n), 5, getHeight() - 5);
}
private void update() {
color = new Color(r.nextInt());
repaint();
}
}
private static class MouseHandler extends MouseAdapter {
LayerPanel panel;
MouseHandler(LayerPanel panel) {
this.panel = panel;
}
#Override
public void mouseClicked(MouseEvent e) {
panel.update();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
(new LayerDemo()).setVisible(true);
}
});
}
}

Categories

Resources