BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Java Graphics Interface III paintComponent - 2020

Duke 512




Bookmark and Share





bogotobogo.com site search:




Java Graphics Interface III - paintComponent

When we want to draw our own graphics on the screen, we should put our graphics code inside the paintComponent() method. But we never call this method directly. The system calls it.

A Graphics object is the argument to this method. It is the actual drawing canvas that will be displayed. We should give it to the system. However, we can ask the system to refresh the display by calling repaint(). The repaint() call eventually leads to paintComponent() being called.

In the following code, we make a subclass of JPanel and override one method, paintComponent().

Applications that have components with any custom rendering may need to override this method to perform that custom rendering. This rendering may include drawing graphics inside a canvas, but it also include doing anything custom to a standard component, such as rendering a gradient for the background of a button. Standard Swing components already handle this functionality for their graphics, so it is only for the case of custom components with specialized rendering that this method must be overridden.


Overriding paintComponent() is arguably the most important concept to understand in writing custom Swing components.

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

public class OvalPaint extends JPanel {

  public void paintComponent(Graphics g) {
    g.setColor(Color.orange);
    g.fillRect(0, 0, getWidth(), getHeight());
    g.setColor(Color.red);
    g.fillOval(getWidth()/4, getHeight()/4, 
		getWidth()/2, getHeight()/2);
  }

  public static void main(String args[]) {
    JFrame frame = new JFrame("OvalPaint");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    OvalPaint panel = new OvalPaint();
    
    frame.add(panel);

    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

OvalPaint
public class OvalPaint extends JPanel {

Here, we're making a subclass of JPanel which is a widget that we can add to a frame:

JFrame frame = new JFrame("OvalPaint");
...
OvalPaint panel = new OvalPaint();
frame.add(panel);

The following block of code Graphics method which is the key in this section. We'll never call this directly. The system calls it:

public void paintComponent(Graphics g) {
...
}

Inside that block of code, we have:

 public void paintComponent(Graphics g) {
	g.setColor(Color.orange);
	g.fillRect(0, 0, getWidth(), getHeight());
	g.setColor(Color.red);
	g.fillOval(getWidth()/4, getHeight()/4, 
	getWidth()/2, getHeight()/2);
}

The Graphics.g is a kind of painting tool. We're telling it what color to paint with and then what shape to paint, where it goes, and how big it is.



Graphics 2D Object

The argument for paintComponent() is a type Graphics which is from java.awt.Graphics:

public void paintComponent(Graphics g) {}

The parameter g is a Graphics object. Actually, the object referenced by g is an instance of the Graphics2D class.

So, if we need to use a method from the Graphics2D class, we can' use the g in paintComponent(Graphics g) directly. However, we can cast it with a new Graphics2D variable:

Graphics2D graphics2d = (Graphics2D) g;

Why do we care?
That's because there are things we can do with a Graphics2D reference that we can't do with a Graphics reference. Actually, a Graphics2D object can do more than a Graphics object.

Here are the methods we can call on a Graphics reference:

  1. drawImage()
  2. drawLine()
  3. drawPolygon()
  4. drawRect()
  5. drawOval()
  6. fillRect()
  7. fillOval()
  8. fillRoundRect()
  9. setColor()

Here are the methods we can call on a Graphics2D object:

  1. fill3DRect()
  2. draw3DRect()
  3. rotate()
  4. scale()
  5. shear()
  6. transform()
  7. setRenderingHints()

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

public class OvalPaint extends JPanel {

  public void paintComponent(Graphics g) {
	Graphics2D graphics2d = (Graphics2D)g;
	graphics2d.setColor(Color.orange);
	graphics2d.fillRect(0, 0, getWidth(), getHeight());

	GradientPaint gradient = new GradientPaint (
		getWidth()/4, getHeight()/4, Color.red, 
		getWidth()*3/4, getHeight()*3/4, Color.orange); 
				
	graphics2d.setPaint(gradient);
	graphics2d.fillOval(getWidth()/4, getHeight()/4, getWidth()/2, getHeight()/2);
  }

  public static void main(String args[]) {
    JFrame frame = new JFrame("OvalPaint with Gradient");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    OvalPaint panel = new OvalPaint();
    
    frame.add(panel);

    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

OvalPaintWithGradient




Which One? - Multiple Widgets

The following example has a drawing panel at the center with two buttons to control the shape and color. When we click one of the two buttons, however, the program does not know what we want. That's because we have only one actionPerformed(ActionEvent event) method. Clearly, there is a problem.

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

public class WhichOne implements ActionListener
{
  JFrame frame;
  public static void main(String args[]) {
	  WhichOne w = new WhichOne();
	  w.go();
  }
  
  public void go() {
    frame = new JFrame("Which One?");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyDrawing drawPanel = new MyDrawing();
    
    JButton colorButton = new JButton("Color");
    JButton shapeButton = new JButton("Shape");

    colorButton.addActionListener(this);
    shapeButton.addActionListener(this);
    
    frame.getContentPane().add(BorderLayout.WEST, colorButton);
    frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
    frame.getContentPane().add(BorderLayout.EAST, shapeButton);

    frame.setSize(300, 200);
    frame.setVisible(true);
  }
  
  public void actionPerformed(ActionEvent event) {
    frame.repaint();
  }
}

class MyDrawing extends JPanel 
{
	public void paintComponent(Graphics g) {
	    g.setColor(Color.orange);
	    g.fillRect(0, 0, getWidth(), getHeight());
	    g.setColor(Color.red);
	    g.fillOval(getWidth()/4, getHeight()/4, 
			getWidth()/2, getHeight()/2);
	}
}

WhichOneA


Using the Same Listener

How do we get action events for two different buttons so that each button can do perform its own task?

The following code register the same listener for both buttons:

String messageColor = "Color Changed";
String messageShape = "Shape Changed";
...
colorButton.addActionListener(this);
shapeButton.addActionListener(this);

It's querying the event object to find out which button has been clicked:

public void actionPerformed(ActionEvent event) {
	if(event.getSource() == colorButton) {
		System.out.println(messageColor);
	} else {
		System.out.println(messageShape);
	}
	frame.repaint();
}

This works!
However, when we need to change the task for one event, we are actually touching the task for other events, because the one event handler doing things for others as well. So, it has some issues related to the maintainability and extensibility.




Creating Two Separate Listener Classes

The following code create two separate ActionListener classes. It instantiate the two listeners and register one with the color button and the other with the shape button.

So, instead of pass this to the button's listener registration method, we pass a new instance of the new class:

colorButton.addActionListener(new ColorButtonListener());
shapeButton.addActionListener(new ShapeButtonListener());

However, we cannot use the reference variables such as messageColor and messageShape of the WhichOne class. These classes (ColorButtonListener and ShapeButtonListener) won't have access to the variables they need to act on, in the example, messages.

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

public class WhichOne 
{
  JFrame frame;
  JButton colorButton;
  JButton shapeButton;

  String messageColor = "Color Changed";
  String messageShape = "Shape Changed";
  
  public static void main(String args[]) {
	  WhichOne w = new WhichOne();
	  w.go();
  }
  
  public void go() {
    frame = new JFrame("Which One?");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyDrawing drawPanel = new MyDrawing();
    
    colorButton = new JButton("Color");
    shapeButton = new JButton("Shape");
    
    colorButton.addActionListener(new ColorButtonListener());
    shapeButton.addActionListener(new ShapeButtonListener());
    
    frame.getContentPane().add(BorderLayout.WEST, colorButton);
    frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
    frame.getContentPane().add(BorderLayout.EAST, shapeButton);

    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

class ColorButtonListener implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		System.out.println(messageColor);
	}
}

class ShapeButtonListener implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		System.out.println(messageShape);

	}
}

class MyDrawing extends JPanel 
{
	public void paintComponent(Graphics g) {
	    g.setColor(Color.orange);
	    g.fillRect(0, 0, getWidth(), getHeight());
	    g.setColor(Color.red);
	    g.fillOval(getWidth()/4, getHeight()/4, 
			getWidth()/2, getHeight()/2);
	}
}



Using Inner Classes

The access problem in the previous example can be resolved by using inner classes. By putting two ActionListers inside the WhichOne classes, we have an access to the reference variables.

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

public class WhichOne 
{
  JFrame frame;
  JButton colorButton;
  JButton shapeButton;
  String messageColor = "Color Changed";
  String messageShape = "Shape Changed";
  
  public static void main(String args[]) {
	  WhichOne w = new WhichOne();
	  w.go();
  }
  
  public void go() {
    frame = new JFrame("Which One?");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyDrawing drawPanel = new MyDrawing();
    
    colorButton = new JButton("Color");
    shapeButton = new JButton("Shape");
    
    colorButton.addActionListener(new ColorButtonListener());
    shapeButton.addActionListener(new ShapeButtonListener());
    
    frame.getContentPane().add(BorderLayout.WEST, colorButton);
    frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
    frame.getContentPane().add(BorderLayout.EAST, shapeButton);

    frame.setSize(300, 200);
    frame.setVisible(true);
  }
  
  class ColorButtonListener implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		System.out.println(messageColor);
	}
  }

  class ShapeButtonListener implements ActionListener {
	public void actionPerformed(ActionEvent event) {
		System.out.println(messageShape);
	}
  }
}

class MyDrawing extends JPanel 
{
	public void paintComponent(Graphics g) {
	    g.setColor(Color.orange);
	    g.fillRect(0, 0, getWidth(), getHeight());
	    g.setColor(Color.red);
	    g.fillOval(getWidth()/4, getHeight()/4, 
			getWidth()/2, getHeight()/2);
	}
}






Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Java Tutorials



Java Tutorial Home

Basics - Compiling and Launching

Inner Classes

Constructor

Enums

Static & Finally

Default and Protected

Polymorphism

Exception Handling

Exception Handling II

String Class

Threads

Threads II - State Transition

Threads III - Synchronization

Object Class

File I/O

Serialization

ArrayList

Autoboxing

Java Graphics Interface I - Basics

Java Graphics Interface II - Labels, Text Fields, Layouts

Java Graphics Interface III - paintComponent

TCP Sockets Server/Client

Scala - Functional Java Programming

Apache CXF install

Tomcat 7 Ubuntu 14 Install on Amazon EC2 instance

What is Apache Maven?

Maven life cycle

Eclipse Maven 3 plugin on Ubuntu 14.04

Apache Maven 3 - Setting up and creating a project

Apache Maven 3 - Compile, build, and install a Maven project

Apache Maven 3 - Dependencies

Apache Maven 3 - Web Application

Apache Maven 3 - Plugins (compiler)

Apache Maven 3 - Plugins (Jetty)

Eclipse CDT / JNI (Java Native Interface) / MinGW



Spring Framework

Hello World App with Spring 4 & Maven 3 - Part I




Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Spring Boot



Spring Boot : Hello world with Mavan 3

Spring Boot : Hello world with Gradle 2

Spring Boot (Gradle 2) : Hello world with Authentication

Spring Boot : Deploying War file to Tomcat 8's webapps

How to Setup Apache as Reverse Proxy for Tomcat Server using mod proxy

Maven : mvn command cheat sheet

Spring-Boot REST API with CORS App Maven war file deploy to Tomcat

Spring-Boot / Spring Security with AngularJS - Part I (Introduction)

Spring-Boot / Spring Security with AngularJS - Part II (Dynamic resource load from Angular)

Spring-Boot / Spring Security with AngularJS : Part III (Form-based Authentication)





JUnit & Maven Tutorial



JUnit 4 Introduction (Hello World)

JUnit 4 Test with Eclipse Luna (Hello World)

JUnit 4 Test with Maven (Hello World)











Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master