How can I let a class add onto my paint function? - java

I know that is poorly worded, but I don't know how to word it better. Essentially I have my own JComponent MyComponent and it paints some stuff onto its graphics. I want it to paint its stuff, then call a method to finish the paint, here is an example:
public class MyComponent extends JComponent{
// etc
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2 = (Graphics2D)g;
g2.drawSomething(); // etc
// Once it is done, check if that function is exists, and call it.
if(secondaryPaint != null){
secondaryPaint(g2);
}
}
}
Then, in a different class:
// etc
MyComponent mc = new MyComponent()
mc.setSecondaryDrawFunction(paint);
// etc
private void paint(Graphics2D g2){
g2.drawSomething();
}
I'm not sure how lambdas work or if they are applicable in this situation, but maybe that?

No lambdas, but the Function interface will work
You can do :
public class MyComponent extends JComponent{
// etc
Function<Graphics2D, Void> secondaryPaint;
public MyComponent(Function<Graphics2D, Void> myfc){
secondaryPaint = myfc;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
//g2.drawSomething(); // etc
// Once it is done, check if that function is exists, and call it.
if(secondaryPaint != null){
secondaryPaint.apply(g2);
}
}
static class Something {
public static Void compute(Graphics2D g){
return null;
}
public Void computeNotStatic(Graphics2D g){
return null;
}
}
public static void main(String[] args) {
Something smth = new Something();
new MyComponent(Something::compute); // with static
new MyComponent(smth::computeNotStatic); // with non-static
}
}

Related

Why do I get an error (Nullpointerexception) when trying to clear Canvas?

I have a project, in which I should create a robot that moves between randomly created squares, till it sticks between two squares, or it reaches the end of the Canvas. For that I have a Super class Figur that has two subclass (Kreis) Circle and (Rechteck) Square, I have a Class Spielfeld(Gamefield) that has methods to populate an arraylist of figure, commands that user gives, of what robot should do, ...and at the end of this methods it calls the method zeichnen(draw) from Class Leinwand(Canvas).
public abstract class Figur{
///..some fields, constructions, methhods..
abstract public void zeichnen(Graphics g);
}
public class Rechteck extends Figur{
///..some fields, constructions, methhods..
public void zeichnen(Graphics g){
g.setColor(getFarbe());
g.drawRect(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
g.fillRect(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
}
public class Kreis extends Figur{
public void zeichnen(Graphics g){
g.setColor(getFarbe());
g.drawOval(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
g.fillOval(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
}
public class Spielfeld {
static ArrayList<Figur> myCharacters = new ArrayList<>();
//some methods that adds points(circles) and Squares to the arraylist MyCharacters
//some methods like movebetweensquares that calls method zeichnen in Leinwand
public class Leinwand{
public void zeichnen(ArrayList<Figur> figur){
loeschen();
zeichenflaeche.repaintFiguren(figur);
}
private void loeschen() {
Color original = graphic.getColor();
graphic.setColor(hintergrundfarbe);
Dimension size = zeichenflaeche.getSize();
graphic.fill(new Rectangle(0, 0, size.width, size.height));
graphic.setColor(original);
}
private class Zeichenflaeche extends JPanel {
private static final long serialVersionUID = 20060330L;
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j=0; j<Spielfeld.get_ myCharacters ().size();j++){
Figur s= Spielfeld.get_ myCharacters ().get(j);
s.zeichnen(g);
}
}
public void repaintFiguren(ArrayList<Figur> figuren{
for( Figur f: Spielfeld.get_ myCharacters ()){
for(int i=0; i<Spielfeld.get_ myCharacters ().size();i++){
if(f instanceof Rechteck){
repaint(figuren.get(i).getPosition().getX(),
figuren.get(i).getPosition().getY(),
figuren.get(i).getBreite(),figuren.get(i).getLaenge()); }
else if(f instanceof Kreis){
repaint(figuren.get(i).getPosition().getX(),
figuren.get(i).getPosition().getY(),
figuren.get(i).getBreite(),
figuren.get(i).getLaenge());}
}
}
}
}

Passing functions to classes

I have a java form implemented using swing on which I want to place a number of panels in which I can draw on using the graphics2D package.
To do this, I implement the panels using an extension of JPanel thus:
public class GraphicsPanel extends JPanel
{
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
// Need to specify a function from the calling class here
MethodFromCallingClass();
}
}
In the calling class I have
public GraphicsPanel Graphics1= new GraphicsPanel() ;
public void Graphics1_Paint()
{
// Code to draw stuff on the Graphics1 panel
}
So question is how do I pass the function (Graphics1_Paint) from the calling class to the GraphicsPanel class?
I've tried reading about interfaces and lambdas but so far they make no sense.
Can anyone enlighten me please.
I think the easiest way is to pass the calling class (or some other interface) to the constructor of your GraphicsPanel like
public class GraphicsPanel extends JPanel {
private CallingClass cc;
public GraphicsPanel(CallingClass cc) {
this.cc = cc;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
cc.MethodFromCallingClass(); // <-- invoke a call-back.
}
}
So it sounds like you want to define what is drawn outside of the custom JPanel class, where you can pass what you want drawn to the JPanel instance at anytime. This is possible.
First, define an interface that contains one method that draws with a Graphics2D instance:
public interface DrawGraphics()
{
public void draw(Graphics2D g);
}
Next you'll want to extend your GraphicsPanel a bit to have the ability to change an underlying instance of DrawGraphics.
So your constructor should now be:
public GraphicsPanel(DrawGraphics graphicsToDraw) { ...
You should also have a set method for the DrawGraphics stored so you can change it at anytime:
public void setDrawGraphics(DrawGraphics newDrawGraphics) { ...
Make sure you add some synchronization somewhere here, or create all DrawGraphics on the EDT because the paintComponents method will execute on the EDT.
Next the paintComponents method can simply draw the graphics:
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
// Need to specify a function from the calling class here
graphicsToDraw(g2d);
}
And when you need to change the DrawGraphics:
// Calling from the EDT
myGraphicsPanel.setDrawGraphics(g -> g.drawString("Hello World!", 50, 50);
I seem to have solved the problem, but I'd like comments on usability and good practice
public class CallingClass
{
public JPanel Graphics1 ;
public CallingClass()
{
Graphics1 = new Graphics1_Paint();
}
public class Graphics1_Paint extends JPanel
{
public Graphics2D g2d;
public void paintComponent (Graphics g)
{
g2d = (Graphics2D) g;
super.paintComponent(g2d);
g2d.drawString("From Calling Class",10,10);
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CallingClass();}
});
}
Seems I don't need my GraphicsPanel class after all.

paintComponent isn't painting anything?

I haven't been able to paint anything using an actionListener and paintComponent. I'm pretty sure I have the image name/path right. What am I doing wrong?
JApplet "Runner.java"
public class Runner extends JApplet{
public void init(){
World world = new World();
Container screen = this.getContentPane();
screen.add(world);
setSize(1200, 800);
repaint();
}
}
part of "World.java"
protected ArrayList<WorldObject> allStillObjects = new ArrayList<WorldObject>();
protected ArrayList<MovableObject> allMovableObjects = new ArrayList<MovableObject>();
protected ArrayList<WorldObject> screenStillObjects = new ArrayList<WorldObject>();
protected ArrayList<MovableObject> screenMovableObjects = new ArrayList<MovableObject>();
public World(){
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(new Color(255,255,255));
this.setFocusable(true);
this.setFocusTraversalKeysEnabled(false);
this.addObject(new Card(this, "Two of Clubs", 0, 0, "card_two_c.png"));
timer = new Timer(60, new ClickListener());
timer.start();
}
public void addObject(WorldObject obj){
if(obj instanceof MovableObject){
this.allMovableObjects.add((MovableObject)obj);
if(isOnScreen(obj))
this.screenMovableObjects.add((MovableObject)obj);
}else{
this.allStillObjects.add(obj);
if(isOnScreen(obj))
this.screenStillObjects.add(obj);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(WorldObject obj : this.screenStillObjects)
obj.paintComponent(g);
for(MovableObject obj : this.screenMovableObjects)
obj.paintComponent(g);
}
private class ClickListener implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
}
}
"ImageObject.java"
protected ImageIcon pic;
public ImageObject(World world, String name, int worldX, int worldY, String imageName){
super(world, name, worldX, worldY);
URL imgURL = getClass().getResource("images/" + imageName);
pic = new ImageIcon(imgURL);
this.width = pic.getIconWidth();
this.height = pic.getIconHeight();
}
public void paintComponent(Graphics g){
super.paintComponent(); //doesn't work with or without this line
pic.paintIcon(world, g, this.getWorldX(), this.getWorldY());
}
If there isn't enough of the code here I can add more
Edit: What's the best alternative to using a JApplet? World extends JPanel, WorldObject extends JPanel, ImageObject extends WorldObject, MovableObject extends ImageObject, Card extends MovableObject
I added the method for addObject above.
Well thank you for your answers, er, comments! They were very helpful. I went and changed my program so that it used a JFrame instead of a JApplet, and after a little fiddling, got an image to print. From there I was able to revert back to a JApplet and it works! Still not sure what my initial problem was though :|

Passing a drawn graphic

I'm trying to pass a graphics element up the chain. I need to have the ability to draw a number of different die and return the correct one for each instance. I can get this to compile but I don't know if i'm doing this correctly. I want to pass the graphics component to a panel to be displayed.
My shortened paint class
import java.awt.*;
import javax.swing.*;
class DiePaint extends JPanel
{
Graphics g;
public Graphics dieSwitch(int inInt)
{
return die1();
}
private Graphics die1()
{
//reset drawing
repaint();
//draw a die with 1 pip
g.setColor(Color.BLACK);
g.drawRect(0,0,50,50);
g.drawOval(24,24,2,2);
g.fillOval(24,24,2,2);
//return graphic
return g;
}
}
A method in my other class i'm trying to use to call it.
private void setDie()
{
//set die labels
die1P.paint(drawDie.dieSwitch(game.getDie(0)));
}
"I want to pass the graphics component to a panel to be displayed."
No, you don't.
You need to see how to Perform Custom Painting. You're going to need a paintComponent method in your panel
#Override
protected void paintComponent(Graphic s) {
super.paintComponent(g);
// draw here
}
You don't explicitly call paint like you are doing here die1P.paint(drawDie.dieSwitch
If you want to be able to set what is being painted, you can have a Die object that you use to draw. Something like
class Die {
public void draw(Graphics g) {
// draw die here
}
}
Then in your panel class have a setter for the Die object, that will repaint the new Die. You will probably want to have a way to differentiate each die. Pass some arguments to a constructor to do that. Then paint the one die.
public class DiePanel extends JPanel {
private Die die;
public void setDie(Die die) {
this.die = die;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (die != null) {
die.draw(g);
}
}
}
You may also, instead, want to make Die an interface, so you can implement difference Die objects, like DieOne, DieTwo, etc. Something like
public interface Die {
void Draw(Grapchis g);
}
public class DieOne {
#Override
public void draw(Graphics g) {
// draw die one
}
}
When you call setDie(), you can pass a specific Die, like
DieOne dieOne = new DieOne();
...
diePanel.setDie(dieOne);
Yes you can pass the drawn component by using BufferedImage....first you draw the graphic on this BufferedImage then pass this image and then draw this image to the Panel...Here is the code:
import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
class DiePaint extends JPanel
{
int width=500; int height=500; //you can change as requred
BufferedImage buffg=new BufferedImage(width,height , BufferedImage.TYPE_INT_ARGB);
Graphics g;
public BufferedImage dieSwitch(int inInt) //change return type to BufferedImage
{
return die1();
}
private BufferedImage die1() // change return type to BufferedImage
{
g=buffg.getGraphics(); //get Graphics from buffg..
//reset drawing
repaint();
//draw a die with 1 pip
g.setColor(Color.BLACK); //draw all the component on buffg using its Graphics g
g.drawRect(0,0,50,50);
g.drawOval(24,24,2,2);
g.fillOval(24,24,2,2);
//return graphic
return buffg;
}
}
now once you get this "buffg" now you can draw it on any panel.....
JPanel p=new JPanel(){
#Override
public void paint(Graphics g){
g.drawImage(drawDie.dieSwitch(game.getDie(0))); //get & draw Image
}
};

Passing values to applets

I have a little problem with passing values from one class into another which extends the Applet class.
for eg. my From.java contains the following code:
public class From{
public static Graphics g;
String name = "Jack Black";
To drawString = new To(g,name);
}
and my To.java contains this:
public class To extends Applet {
To(Graphics g, String name){
g.setColor(Color.black);
g.drawString(name, 20, 20);
}
}
I've made an constructor to pass the values, but i understand that paint method draws the graphics into Applet and thats why my code doesn't work. So, sadly, i cant make it working, I hope you guys can help me out here.
Oh, Hi :)
I watched your code and... You can simply modify your code in this direction as...
A)
public class From{
private String name;
public From(){}
public void setName(String name){this.name=name;}
public String getName(){return this.name;}
}
B) Here is applet...
public class To extends Applet {
Paint paint=new Paint();
...
public void setFrom(From from)
{
paint.drawString(from.getName());
}
}
C) And some simplification...
public class Paint extends JPanel
{
private String name;
public Paint (){}
public void drawString(String name)
{
this.name=name;
this.repaint();
}
public void paintComponent(Graphics g)
{
g.setColor(Color.black);
g.drawString(this.name, 20, 20);
}
}
That should help :)
Good luck

Categories