Moving Graphics Smoothly Rather Than Skipping in Java - java

I was practicing moving graphics in Java and I seem to be coming to a problem. What I drew right now is 2 alien faces. At the moment my program is set up to move the faces 1 step at a time in a certain direction based on user input. What I would like to do is have the alien faces move from point A to point B. For example, right now it moves 1 step at a time because I have the parts of the faces increase by 1 on it's x and y. My thoughts were to start a loop before the method MoveHorizontal(), that way it would run so many times and I would have a smooth transition from one point to another. It's not working like that for me though. It would skip from where it started to where the loops ends rather than 1 step at a time. So my question is, how would I be able to do that? lol. Thank you.
//First Class
import javax.swing.JFrame;
import java.util.Scanner;
public class AlienFace
{
public static void main(String[] args)
{
String userInput;
Scanner input = new Scanner(System.in);
JFrame frame = new JFrame();
frame.setSize(700, 700);
frame.setTitle("An Alien Face");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FaceComponent component = new FaceComponent();
frame.add(component);
frame.setVisible(true);
System.out.println("Which direction would you like the Alien faces to move? ");
System.out.print("H/h for horizontally, V/v for vertically, D/d for diagonally, or Q/q to quit: ");
userInput = input.nextLine();
System.out.println(userInput);
while (!userInput.equals("q") || !userInput.equals("Q"))
{
System.out.println("Which direction would you like the Alien faces to move? ");
System.out.print("H/h for horizontally, V/v for vertically, D/d for diagonally, or Q/q to quit: ");
userInput = input.nextLine();
if (userInput.equals("H") || userInput.equals("h"))
{
component.MoveHorizontal();
frame.repaint();
}
if (userInput.equals("V") || userInput.equals("v"))
{
component.MoveVertical();
frame.repaint();
}
if (userInput.equals("D") || userInput.equals("d"))
{
component.MoveDiagonal();
frame.repaint();
}
}
if (userInput.equals("q") || userInput.equals("Q"))
{
frame.setVisible(false);
}
}
}
//Second Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
public class FaceComponent extends JComponent
{
int head2X = 5;
int head2Y = 10;
int head3X = 105;
int head3Y = 115;
int eye2X = 25;
int eye2Y = 75;
int eye3X = 125;
int eye3Y = 175;
int mouth2X1 = 30;
int mouth2Y1 = 110;
int mouth3X1 = 130;
int mouth3Y1 = 210;
int mouth2X2 = 80;
int mouth2Y2 = 110;
int mouth3X2 = 180;
int mouth3Y2 = 210;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(head2X, head2Y, 100, 150);
g2.draw(head);
Ellipse2D.Double head1 = new Ellipse2D.Double(head3X, head3Y, 100, 150);
g3.draw(head1);
g2.setColor(Color.GREEN);
Rectangle eye = new Rectangle(eye2X, eye2Y, 15, 15);
g2.fill(eye);
eye.translate(50, 0);
g2.fill(eye);
g3.setColor(Color.GREEN);
Rectangle eye1 = new Rectangle(eye3X, eye3Y, 15, 15);
g3.fill(eye1);
eye1.translate(50, 0);
g3.fill(eye1);
Line2D.Double mouth = new Line2D.Double(mouth2X1, mouth2Y1, mouth2X2, mouth2Y2);
g2.setColor(Color.RED);
g2.draw(mouth);
Line2D.Double mouth1 = new Line2D.Double(mouth3X1, mouth3Y1, mouth3X2, mouth3Y2);
g3.setColor(Color.RED);
g3.draw(mouth1);
g2.setColor(Color.BLUE);
g2.drawString("Hello, World!", 5, 175);
}
public void MoveHorizontal()
{
head2X++;
head3X++;
eye2X++;
eye3X++;
mouth2X1++;
mouth3X1++;
mouth2X2++;
mouth3X2++;
}
public void MoveVertical()
{
head2Y++;
head3Y++;
eye2Y++;
eye3Y++;
mouth2Y1++;
mouth3Y1++;
mouth2Y2++;
mouth3Y2++;
}
public void MoveDiagonal()
{
head2X++;
head3X++;
eye2X++;
eye3X++;
mouth2X1++;
mouth3X1++;
mouth2X2++;
mouth3X2++;
head2Y++;
head3Y++;
eye2Y++;
eye3Y++;
mouth2Y1++;
mouth3Y1++;
mouth2Y2++;
mouth3Y2++;
}
}

Related

Drawing lines the full height of JPanel

I've gotten my code to work for the most part except for one last thing. When the number of lines drawn > 20, the lines aren't being drawn to take up the full amount of panel
** Look at the bottom right side of my screenshot. The lines go part way down the full height of the panel. I need it to go the full length of the height down. **
Here's my code for DrawPanelTest
// Creating JPanel to display DrawPanel
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class DrawPanelTest
{
public static void main(String[] args)
{
int nValue = 0; // declare variable to store user input. Default value 0.
Boolean flag = true; // initalize flag to true for argument value of while-loop
// while-loop to prompt user input
while (flag) {
// prompt user for the value of N
nValue = Integer.parseInt(JOptionPane.showInputDialog("Enter number of lines between 2 and 100."));
// user input validation. Valid input is nValue [2, 100]
if (nValue < 2 || nValue > 100) {
nValue = Integer.parseInt(JOptionPane.showInputDialog("Enter number of lines between 2 and 100."));
} else {
flag = false; // if user input is correct, while-loop will end
} // end if-else
} // end while-loop
// displays the value of N to make sure it really is correct; This works
// String message = String.format("The value of n is: %d ", nValue);
// JOptionPane.showMessageDialog(null, message);
// create a panel that contains our drawing
DrawPanel drawPanel = new DrawPanel(nValue);
// create a new frame to hold the panel
JFrame application = new JFrame();
// set the frame to exit when closed
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(drawPanel); // add panel to the frame
application.setSize(600, 600); // set the size of the frame
application.setVisible(true); // make the frame visible
}
} // end class DrawPanelTest
Here's my code DrawPanel
// Using drawLine() to connect the corners of a panel
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel
{
int numLines;
// constructor initializes DrawPanel and initializes
// numLines with the argument value of n
public DrawPanel(int n)
{
numLines = n;
}
// draws a X from the corners of the panel
public void paintComponent( Graphics g)
{
// call paintComponent to ensure the panel displays correctly
super.paintComponent(g);
int width = getWidth(); // total width
int height = getHeight(); // total height
int x1 = 0; // starting x-coordinate
int y1 = height / 2; // starting y-coordinate
int x2 = width; // initial value for end x-coordinate
int spaceValue = 0; // represents the space between the lines
int stepValue = height/numLines; // represents the increment value starting from top right corner
for (int i = 0; i <= numLines; i++) {
if (numLines == 2) {
g.drawLine(x1, y1, x2, 0);
g.drawLine(x1, y1, x2, height);
break;
} // end numLines == 2
else if (numLines >= 3) {
g.drawLine(x1, y1, x2, spaceValue);
spaceValue += stepValue;
} // end else if
} // end for-loop
} // end paintComponent
} // end class DrawPanel
I think my problem lies in DrawPanel line 41. I don't think I'm calculating the spaces between the lines correctly so that they end up taking the entire height of the panel.
Thanks in advance for your help.
Your calculation of the "stepValue" has two problems:
the stepValue is to small, so the last line will never appear at the bottom
the stepValue is truncated because of integer math so each addition of the truncated value to the "spaceValue" will yield a slightly less accurate value.
Lets say you have a panel with a height of 600 and the number of lines is 3.
Your calculation is:
int stepValue = 600 / 3 = 200
which I would suggest is wrong as you would draw 3 lines with a "spaceValue" of 0, 200, 400, so the last line (at 600) would never be drawn.
In reality I think the calculation should be:
double stepValue = (double)height / (numLine - 1);
which gives:
double stepValue = 600 / (3 - 1) = 300.
which will give lines with a "spaceValue" of 0, 300, 600 which would be a line at the top, middle and bottom.
So your painting loop simply becomes:
for (int i = 0; i < numLines; i++)
{
g.drawLine(x1, y1, x2, spaceValue);
spaceValue += stepValue;
}
I think (one of) the issue you're having is a "integer division" issue.
int stepValue = height / numLines;
is truncating the result. For example, if the height is 400 and the number of lines is 6 the stepValue will be 66 instead of 67 (which would allow 66.6666 to be rounded up)
Now, you could "round" the value up yourself, but I'd prefer to make use of the available APIs to do these things for me.
Line2D.Double supports double precision parameters, which makes it perfect for this job
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (lineCount > 1) {
double gap = getHeight() / (double)(lineCount - 1);
for (int i = 0; i < lineCount; i++) {
Line2D line = new Line2D.Double(0, getHeight() / 2, getWidth(), i * gap);
g2d.draw(line);
}
} else {
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
}
g2d.dispose();
}
Runnable example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(32, 32, 32, 32));
frame.setContentPane(contentPane);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int lineCount = 1;
public TestPane() {
setBorder(new LineBorder(Color.RED));
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
lineCount++;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(Integer.toString(lineCount), 10, fm.getAscent());
if (lineCount > 1) {
double gap = getHeight() / (double) (lineCount - 1);
for (int i = 0; i < lineCount; i++) {
Line2D line = new Line2D.Double(0, getHeight() / 2, getWidth(), i * gap);
g2d.draw(line);
}
} else {
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
}
g2d.dispose();
}
}
}
In the for loop, change
for (int i = 0; i < numLines; i++) {
to
for (int i = 0; i <= numLines; i++) {
to iterate the full height of the component. The i must equal numLines to reach unity.

How do I flip the drawRect so that it draws up?

I have some code here, and it graphs exponentially but, it graphs the wrong way. negative exponential growth. Here is my code, I'm trying to flip it up. I'll be working on it, but if you have an answer please tell me.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Graphics extends JPanel{
public static void main(String[] args) {
JFrame f =new JFrame ("Function");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Graphics g = new Graphics();
f.add(g);
f.setSize(700, 700);
f.setVisible(true);
}
public void paintComponent (java.awt.Graphics g) {
super.paintComponent(g);
int i = this.getWidth()-this.getWidth() + 5;
int xoffset = this.getWidth()/2;
int yoffset = this.getHeight()/2;
for (int x = 0 ; x < 20 ; x++){
g.setColor(Color.BLACK);
this.setBackground(Color.WHITE);
int p = x*x;
g.fillRect(i+xoffset,10+yoffset,5,p);
i = i + 10;
}
}
}
Does anyone know how to fix this?
Change the x/y position at where the rectangle starts to draw from (it always draws right/down)
So instead of
g.fillRect(i+xoffset,10+yoffset,5,p);
you could have...
g.fillRect(i + xoffset, 10 + yoffset - p, 5, p);
I've got no idea what your intentions are for int i = this.getWidth()-this.getWidth() + 5;, but clearly makes no sense (width - width == 0?)

Drawing circles in 2d grid array in java

I understand how to make 2d array grid. I experimented to put random numbers in it but i do not know how to draw them on jframe. For instance, 0 for red circle , 1 for green circle and so on. I need to figure out how represent them in grid manner too.
public class Game {
public static void initGrid(){
//clumn and row 4 x 4
int col = 4;
int row = 4;
//initialize 2d grid array
int[][] a = new int[row][col];
Random rand = new Random();
//for loop to fill it with random number
for(int x = 0 ; x < col ; x++) {
for(int y = 0; y < row; y++) {
a[x][y] = (int) rand.nextInt(4);
System.out.print(a[x][y]);
}//inner for
System.out.println();
}//outer for
}//method
public static void main(String[] args){
initGrid();
}
}
I understand JFrame and JPanel as far as drawing on empty canvas but not the way i want. I want to combine both code but my knowledge is limited.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game2 extends JPanel{
#Override
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval(0, 0, 30, 30);
g2d.drawOval(0, 50, 30, 30);
g2d.fillRect(50, 0, 30, 30);
g2d.drawRect(50, 50, 30, 30);
g2d.draw(new Ellipse2D.Double(0, 100, 30 ,30));
}
public static void main(String[] args){
JFrame frame = new JFrame("Mini Tennis");
frame.add(new Game2());
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
My suggestion is:
Pass the Game class as a parameter to the constructor of Game2 and store it as a local variable in the Game2 class as illustrated below:
Game game;
public Game2(Game game){
this.game = game;
//Rest of your constructor.
}
Next you declare a getter method in the Game class to retrieve the array which stores the position grid like as below:
public int[][] getPositions(){
return this.a;
}
Create a method that will return the colour to paint based on the int value stored as the element of the grid like this:
private Color getColor(int col){
switch(col){
case 0:
return Color.red;
case 1:
.
.
.
.
}
}
Now instead of overriding the paint method of your Game2 class override the paintComponent and draw the circles in the paintComponent method as illustrated(Here I have considered the circles to be of 30px diameter with a gap of 20px between them):
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int[][] pos = this.game.getPositions();
for(int i = 0; i < pos.length; i++){
for(int j = 0; j < pos[i].length; j++){
g2d.setColor(getColor(pos[i][j]));
g2d.fillOval(i*50, j*50, 30, 30);
}
}
}
I hope this will solve your problem of accessing the Game representing the model from the Game2 class representing the view.

Dynamic Graphics Object Painting

Trying to figure out the best way to do this (And without crossing any specifics DO NOTs that I don't know about).
I'm working on visually displaying a graph (Various nodes, with edges connecting them) with circles and lines to represent such. Each node will be added during runtime and I can't hardcode this. From what I understand, all painting needs to be done in the paint(Graphics g) method - which isn't that helpful, since I can't be change the parameters and it seems this is only called during the initial creation?
Right now I was thinking about having it call various other methods, passing the Graphics object, and depending on other variables - I'll decide whether that's what I even want to call (Since the paint() method is the only one I can call).
Am I going about this completely wrong? Never bothered with this before.
To give you a better idea of what I want to end up with: I want to be able to pass the coordinates of the shape I want to add for the node, and then add it to whatever I have on the graph so far. And then same with the edges, I want to be able to pass the beginning and end point of the line to repaint on top of whatever is existing at that time.
Not exactly what I want right now - but you'll get the idea from what I patched together so far:
import java.awt.*;
import javax.swing.*;
public class MyCanvas extends Canvas
{
public MyCanvas()
{
}
public void paint(Graphics graphics)
{
// Keep this until I figured out if it's painted on load or not.
graphics.drawLine(10, 20, 350, 380);
}
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.getContentPane().add(canvas);
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);
}
}
Edit: (Response for Andrew)
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyCanvas extends JPanel
{
public MyCanvas() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
public static void main(String[] args)
{
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
JFrame frame = new JFrame();
JLabel label = new JLabel();
BufferedImage bImage = new BufferedImage(canvasSize, canvasSize, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bImage.createGraphics();
g2d.drawLine(50, 50, 300, 300);
ImageIcon iIcon = new ImageIcon(bImage);
label.setIcon(iIcon);
frame.add(label);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g2d = drawNode(1,1,g2d);
label.repaint();
}
public static Graphics2D drawNode(int x, int y,Graphics2D g2d)
{
// 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;
g2d.setColor(Color.white);
g2d.fillOval(xLoc, yLoc, 8, 8);
g2d.drawOval(xLoc, yLoc, 8, 8);
return g2d;
}
public static void drawArc(int x, int y, int xx, int yy)
{
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);
}
}
There are various strategies you might pursue for this.
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:
Get the graphics instance of the image and draw the new element.
Dispose of the graphics object.
Call repaint() on the label.
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:
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.

Custom Java Swing Meter Control

I'm trying to make a custom swing control that is a meter.
Swing Meter http://dl.dropbox.com/u/2363305/Programming/Java/swing_meter.gif
The arrow will move up and down. Here is my current code, but I feel I've done it wrong.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Polygon;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class meter extends JFrame {
Stroke drawingStroke = new BasicStroke(2);
Rectangle2D rect = new Rectangle2D.Double(105, 50, 40, 200);
Double meterPercent = new Double(0.57);
public meter() {
setTitle("Meter");
setLayout(null);
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
public void paint(Graphics g) {
// Paint Meter
Graphics2D g1 = (Graphics2D) g;
g1.setStroke(drawingStroke);
g1.draw(rect);
// Set Meter Colors
Point2D start = new Point2D.Float(0, 0);
Point2D end = new Point2D.Float(0, this.getHeight());
float[] dist = { 0.1f, 0.5f, 0.9f };
Color[] colors = { Color.green, Color.yellow, Color.red };
LinearGradientPaint p = new LinearGradientPaint(start, end, dist,
colors);
g1.setPaint(p);
g1.fill(rect);
// Make a triangle - Arrow on Meter
int[] x = new int[3];
int[] y = new int[3];
int n; // count of points
// Set Points for Arrow
Integer meterArrowHypotenuse = (int) rect.getX();
Integer meterArrowTip = (int) rect.getY()
+ (int) (rect.getHeight() * (1 - meterPercent));
x[0] = meterArrowHypotenuse - 25;
x[1] = meterArrowHypotenuse - 25;
x[2] = meterArrowHypotenuse - 5;
y[0] = meterArrowTip - 20; // Top Left
y[1] = meterArrowTip + 20; // Bottom Left
y[2] = meterArrowTip; // Tip of Arrow
n = 3; // Number of points, 3 because its a triangle
// Draw Arrow Border
Polygon myTriShadow = new Polygon(x, y, n); // a triangle
g1.setPaint(Color.black);
g1.fill(myTriShadow);
// Set Points for Arrow Board
x[0] = x[0] + 1;
x[1] = x[1] + 1;
x[2] = x[2] - 2;
y[0] = y[0] + 3;
y[1] = y[1] - 3;
y[2] = y[2];
Robot robot = new Robot();
Color colorMeter = robot.getPixelColor(x[2]+10, y[2]);
// Draw Arrow
Polygon myTri = new Polygon(x, y, n); // a triangle
Color colr = new Color(colorMeter.getRed(), colorMeter.getGreen(), colorMeter.getBlue());
g1.setPaint(colr);
g1.fill(myTri);
}
public static void main(String[] args) {
new meter();
}
}
Thanks for looking.
In addition to #Jonas' example, you might like to look at the article How to Write a Custom Swing Component.
Addendum: On reflection, it looks a little intimidating, but you can extend BasicSliderUI and reuse some of your code in paintThumb() and paintTrack().
JSlider slider = new JSlider();
slider.setUI(new MySliderUI(slider));
...
private static class MySliderUI extends BasicSliderUI {
public MySliderUI(JSlider b) {
super(b);
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Rectangle r = trackRect;
g2d.setPaint(new GradientPaint(
r.x, r.y, Color.red, r.x + r.width, r.y + r.height, Color.blue));
g.fillRect(r.x, r.y, r.width, r.height);
}
#Override
public void paintThumb(Graphics g) {
super.paintThumb(g); // replace with your fill()
}
}
You could use a JSlider and use setValue(int n) to set the value whenever you need. You can also change the default appearance, so you get an arrow and a gradient as you want.

Categories