Paintcomponent() VS Paint() and JPAnel VS Canvas in a Paintbrush-Type Gui

paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI

I've been trying to find a workarounds, but have not found one,
especially for the getGraphics() method: how else can the graphics be
added to the panel?

You remember what needs to be painted as a variable and use that in paintComponent().
For example, what you seemed to be trying to do in your other question would look like:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintRectangle extends JPanel {

private Point mouseLocation;

public PaintRectangle() {
setPreferredSize(new Dimension(500, 500));

MouseAdapter listener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
updateMouseRectangle(e);
}

private void updateMouseRectangle(MouseEvent e) {
mouseLocation = e.getPoint();
repaint();
}

@Override
public void mouseDragged(MouseEvent e) {
updateMouseRectangle(e);
}

@Override
public void mouseReleased(MouseEvent e) {
mouseLocation = null;
repaint();
}
};
addMouseListener(listener);
addMouseMotionListener(listener);
}

private Rectangle getRectangle() {
if(mouseLocation != null) {
return new Rectangle(mouseLocation.x - 5, mouseLocation.y - 5, 10, 10);
}
else {
return null;
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle rectangle = getRectangle();
if(rectangle != null) {
Graphics2D gg = (Graphics2D) g;
gg.setColor(Color.BLUE);
gg.fill(rectangle);
gg.setColor(Color.BLACK);
gg.draw(rectangle);
}
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new PaintRectangle());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

See also http://docs.oracle.com/javase/tutorial/uiswing/painting/

Java custom drawing with paintComponent() and paint()

Start with the java tutorials.

http://docs.oracle.com/javase/tutorial/uiswing/painting/index.html

Dynamic Graphics Object Painting

There are various strategies you might pursue for this.

  1. If the objects are never removed from the drawing once done, use a BufferedImage, put it in a (ImageIcon in a) JLabel. When it comes time to update:

    1. Get the graphics instance of the image and draw the new element.
    2. Dispose of the graphics object.
    3. Call repaint() on the label.
  2. Keep a list of the drawn elements. In the paint method, paint them all. When a new element is added, call repaint() on the rendering component.

Here is an example of the 1st technique:

MyCanvas

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

public class MyCanvas
{
JLabel view;
BufferedImage surface;
Random random = new Random();

public MyCanvas()
{
surface = new BufferedImage(600,400,BufferedImage.TYPE_INT_RGB);
view = new JLabel(new ImageIcon(surface));
Graphics g = surface.getGraphics();
g.setColor(Color.ORANGE);
g.fillRect(0,0,600,400);
g.setColor(Color.BLACK);
// Keep this until I figured out if it's painted on load or not.
g.drawLine(10, 20, 350, 380);
g.dispose();

ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addNewElement();
}
};
Timer timer = new Timer(200, listener);
timer.start();
}

public void addNewElement() {
boolean drawArc = random.nextBoolean();
int x = random.nextInt(60);
int y = random.nextInt(40);
Graphics g = surface.getGraphics();
if (drawArc) {
g.setColor(Color.BLUE);
int xx = random.nextInt(60);
int yy = random.nextInt(40);
drawArc(x,y,xx,yy,g);
} else {
drawNode(x,y,g);
}
g.dispose();
view.repaint();
}

public static void main(String[] args)
{
MyCanvas canvas = new MyCanvas();
JFrame frame = new JFrame();
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
frame.setSize(canvasSize, canvasSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(canvas.view);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public void drawNode(int x, int y, Graphics g)
{
// Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
g.setColor(Color.white);
g.fillOval(xLoc, yLoc, 8, 8);
g.drawOval(xLoc, yLoc, 8, 8);
}

public void drawArc(int x, int y, int xx, int yy, Graphics g)
{
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
int xxLoc = (xx*10) - 5;
int yyLoc = (yy*10) - 5;
g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
}
}

Further tip

You might notice that the lines look quite 'jagged' & ugly. Both the BufferedImage or a JComponent has access to the more useful Graphics2D object (for the JComponent it is necessary to cast it in paintComponent()). A Graphics2D instance accepts rendering hints that can be used to smooth (dither) the elements drawn.

Using addMouseListener() and paintComponent() for JPanel

You must add the mouseListener to the panel. That doesn't happen by default as you might have expected ;-)

MainClass1() {
addMouseListener(this);
}

BTW: it's not recommended to expose public api that's only meant to be used internally. So instead of letting the panel implement MouseListener (which enforces the public exposure), let the panel create and use a MouseListener:

private MouseListener mouseListener;
MainClass1() {
mouseListener = createMouseListener();
addMouseListener(mouseListener);
}

protected MouseListener createMouseListener() {
MouseListener l = new MouseListener() {

}
return l;
}

BTW 2: calling the repaint on the limited area isn't exactly what you want (?) - it temporarily adds the squares to the painting, they are lost whenever the whole panel is repainted (same effect as with getGraphics). Depending on what you really want,

  • paint a single square at the most recently clicked position: call repaint()
  • paint squares at all locations ever clicked: store the locations in a list and implement repaint to loop over that list. Here you may call the repaint with parameters, but why bother?

Error when trying to use paint method inside JFrame in Java

So, you're basic problem is here...

thehandler hand = new thehandler();

The constructor of thehandler requires an instance of Background...

private class thehandler implements ActionListener {
//...
thehandler(Background thisone) {

so, it should actually be...

thehandler hand = new thehandler(this);

That gets rid of the compiler error.

The cause of it not painting anything is because you've broken the paint chain by overriding paint of JFrame and the failing to call super.paint.

See Painting in AWT and Swing and Performing Custom Painting for more details of how painting works

The general answer, is don't do this, there are lots of reasons why you shouldn't override paint of a JFrame:

  • paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI
  • How can I set in the midst?
  • Java JFrame .setSize(x, y) not working?
  • How to get the EXACT middle of a screen, even when re-sized
  • Graphics rendering in title bar

and this is just another one of them.

Instead, create a separate component (extending from JPanel for example) and override it's paintComponent method and perform your custom painting (calling super.paintComponent first)

Have a look at JFrame shows up grey, blank for a more detailed example

Background color for JPanel replaced by grey when method paint() added

The answer is that paint (a java 1.0 - 1.1 method) calls paintBackground in JComponents. When you overrode it, it isn't calling all of the swing paint methods. But if you add super.paint(g), it will look like it did before.

Also - please note that the default ContentPane in JFrame is already a JPanel. Rather than replacing the ContentPane with your JPanel, you could just call:

((JPanel) myFrame.getContentPane()).setBackground(Color.blue);

Specifying the location of Canvas in Swing

"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods. JPanel or JComponent are common choices, as suggested here. You can control placement using a suitable layout.

Addendum: How does this relate to Canvas?

The class java.awt.Canvas is an AWT component; instead use the Swing component javax.swing.JPanel. Here's a variation of your program that merely selects a random color, but it might give you an idea how to address your other properties. There's a related example here.

image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MainCode {

public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
MainView fc = new MainView();
}
});
}

private static class MainView implements ActionListener {

private JFrame f = new JFrame();
private JButton colorButton = new JButton("Color");
private JButton quitButton = new JButton("Quit");
private JButton infoButton = new JButton("Info");
private JLabel x_loc = new JLabel("X:");
private JLabel y_loc = new JLabel("Y:");
private JLabel w_label = new JLabel("Width:");
private JLabel h_label = new JLabel("Height:");
private JTextField x_loc_box = new JTextField("0");
private JTextField y_loc_box = new JTextField("0");
private JTextField w_loc_box = new JTextField("100");
private JTextField h_loc_box = new JTextField("100");
private JOptionPane info1 = new JOptionPane();
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private GraphicsClass graphicsClass = new GraphicsClass();

public MainView() {
panel1.add(x_loc);
panel1.add(x_loc_box);
panel1.add(y_loc);
panel1.add(y_loc_box);
panel1.add(w_label);
panel1.add(w_loc_box);
panel1.add(h_label);
panel1.add(h_loc_box);
colorButton.addActionListener(this);
quitButton.addActionListener(this);
infoButton.addActionListener(this);
panel2.add(colorButton);
panel2.add(quitButton);
panel2.add(infoButton);
f.add(panel1, BorderLayout.NORTH);
f.add(graphicsClass, BorderLayout.CENTER);
f.add(panel2, BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Graphics Toolbox v2");
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == infoButton) {
JOptionPane.showMessageDialog(f, "hahahahahaha");
} else if (e.getSource() == quitButton) {
System.exit(0);
} else if (e.getSource() == colorButton) {
graphicsClass.randomColor();
graphicsClass.repaint();
}
}
}

private static class GraphicsClass extends JPanel {

private static final int SIZE = 128;
private static final Random r = new Random();
private Color color = Color.green;

@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}

public void randomColor() {
this.color = new Color(r.nextInt());
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
int w = getWidth();
int h = getHeight();
g.fillArc(0, h / 4, w, h, 45, 90);
}
}
}


Related Topics



Leave a reply



Submit