I'm having a problem randomly selecting a shape from pre-designed shapes in Java. Previously, I was able to create a random shape but I'm getting no-where with this.
My code is below. I need "DIE07" to randomly be DIE01-DIE06. All help is very much appreciated.
import java.awt.*;
import javax.swing.JPanel;
import java.util.Random;
public class FigurePanel extends JPanel {
public static final int DIE01 = 1;
public static final int DIE02 = 2;
public static final int DIE03 = 3;
public static final int DIE04 = 4;
public static final int DIE05 = 5;
public static final int DIE06 = 6;
public static final int DIE07 = 7;
Random rand = new Random();
private int type = 1;
private boolean filled = false;
public FigurePanel() {
}
public FigurePanel(int type) {
this.type = type;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
switch (type) {
case DIE01:
g.setColor(Color.BLACK);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.44 * width), (int)(0.46 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE02:
g.setColor(Color.RED);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.27 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE03:
g.setColor(Color.GREEN);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.27 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.45 * width), (int)(0.46 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE04:
g.setColor(Color.GREEN);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.27 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.27 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE05:
g.setColor(Color.RED);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.27 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.27 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.45 * width), (int)(0.46 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE06:
g.setColor(Color.BLACK);
g.drawRoundRect((int)(0.1 * width), (int)(0.25 * height),
(int)(0.8 * width), (int)(0.5 * height), 20, 20);
g.fillOval((int)(0.27 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.27 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.27 * width), (int)(0.46 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.46 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.58 * height),
(int)(0.1 * width), (int)(0.075 * height));
g.fillOval((int)(0.63 * width), (int)(0.34 * height),
(int)(0.1 * width), (int)(0.075 * height));
break;
case DIE07:
break;
}
}
public void setType(int type) {
this.type = type;
repaint();
}
public int getType() {
return type;
}
public void setFilled(boolean filled) {
this.filled = filled;
repaint();
}
public boolean isFilled() {
return filled;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(80, 80);
}
}
and this...
import java.awt.*;
import javax.swing.*;
public class TestFigurePanel extends JFrame {
public TestFigurePanel() {
setLayout(new GridLayout(1, 7, 1, 1));
add(new FigurePanel(FigurePanel.DIE01));
add(new FigurePanel(FigurePanel.DIE02));
add(new FigurePanel(FigurePanel.DIE03));
add(new FigurePanel(FigurePanel.DIE04));
add(new FigurePanel(FigurePanel.DIE05));
add(new FigurePanel(FigurePanel.DIE06));
add(new FigurePanel(FigurePanel.DIE07));
}
public static void main(String[] args) {
TestFigurePanel frame = new TestFigurePanel();
frame.setSize(1100, 300);
frame.setTitle("TestFigurePanel");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
You can use your Random member instance to instantiate your type randomly if the passed argument is DIE07. If not, you assign it to your type directly.
public FigurePanel(int type) {
if (type == DIE07) {
this.type = DIE01 + rand.nextInt(DIE06);
} else {
this.type = type;
}
}
Random#nextInt(int n) returns a random int value between 0 (inclusive) and the specified value n (exclusive). So, DIE01 + rand.nextInt(DIE06) will return an int value between DIE01 to DIE06 (both inclusive).
Related
I am currently making an analog clock in java using AWT Package and Swing. But the digital clock overlay is currently flickering every once in a while and I'd like to fix that.
I've read about implementing double buffered in conjunction with repaint() but I am stuck on how to implement it.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
public class Clock2d extends Applet {
GregorianCalendar cal;
Timer clockTimer = new Timer();
TimeZone clockTimeZone = TimeZone.getDefault();
public Clock2d() {
clockTimer.schedule(new TickTimerTask(), 0, 1000);
}
#Override
public void init() {
}
public void paint(Graphics g) {
g.setColor(Color.BLUE);
g.fillOval(40, 40, 220, 220);
g.setColor(Color.WHITE);
g.fillOval(50, 50, 200, 200);
double second = cal.get(Calendar.SECOND);
double minute = cal.get(Calendar.MINUTE);
double hours = cal.get(Calendar.HOUR);
for (int i = 0; i < 60; i++) {
int length = 90;
double rad = (i * 6) * (Math.PI) / 180;
if (i % 5 == 0) {
length = 82;
g.setColor(Color.BLUE);
} else {
g.setColor(Color.GRAY);
}
int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));
int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));
int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));
int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));
g.drawLine(x, y, x1, y1);
}
drawHands(g, second, minute, hours);
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
g.setColor(Color.BLUE);
g.setFont(new Font("Tahoma", Font.BOLD, 16));
g.drawString(sdf.format(cal.getTime()), 120, 20);
g.setFont(new Font("Arial", Font.BOLD, 10));
}
public void drawHands(Graphics g, double second, double minute, double hours) {
double rSecond = (second * 6) * (Math.PI) / 180;
double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;
double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;
g.setColor(Color.RED);
g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));
g.setColor(Color.BLACK);
g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));
g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));
}
class TickTimerTask extends TimerTask {
#Override
public void run() {
cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Clock 2D");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(330, 330));
Clock2d clock2d = new Clock2d();
clock2d.setPreferredSize(new Dimension(320, 320));
clock2d.init();
frame.setLayout(new BorderLayout());
frame.getContentPane().add(clock2d, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
The code work exactly as intended aside from the occasional flickering of the Numbered Digital clock.
public class Clock2d extends Applet A java.awt.Applet is not only deprecated, but also not double buffered by default. Change that to extend a JPanel (which is).
Then change public void paint(Graphics g) { to public void paintComponent(Graphics g) { super.paintComponent(g); to respect the paint chain.
class TickTimerTask extends TimerTask use a javax.swing.Timer instead. It runs on the Event Dispatch Thread, and any calls to the GUI should be made on the EDT.
Here are those three points, expressed in the code. Do you see the 'flickering' artifacts in this version?
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import javax.swing.*;
public class Clock2d extends JPanel {
TimeZone clockTimeZone = TimeZone.getDefault();
GregorianCalendar cal =
(GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
ActionListener repaintListener = (ActionEvent e) -> {
cal = (GregorianCalendar) GregorianCalendar.getInstance(clockTimeZone);
repaint();
};
Timer clockTimer = new Timer(100, repaintListener);
public Clock2d() {
clockTimer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(40, 40, 220, 220);
g.setColor(Color.WHITE);
g.fillOval(50, 50, 200, 200);
double second = cal.get(Calendar.SECOND);
double minute = cal.get(Calendar.MINUTE);
double hours = cal.get(Calendar.HOUR);
for (int i = 0; i < 60; i++) {
int length = 90;
double rad = (i * 6) * (Math.PI) / 180;
if (i % 5 == 0) {
length = 82;
g.setColor(Color.BLUE);
} else {
g.setColor(Color.GRAY);
}
int x = 150 + (int) (95 * Math.cos(rad - (Math.PI / 2)));
int y = 150 + (int) (95 * Math.sin(rad - (Math.PI / 2)));
int x1 = 150 + (int) (length * Math.cos(rad - (Math.PI / 2)));
int y1 = 150 + (int) (length * Math.sin(rad - (Math.PI / 2)));
g.drawLine(x, y, x1, y1);
}
drawHands(g, second, minute, hours);
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
g.setColor(Color.BLUE);
g.setFont(new Font("Tahoma", Font.BOLD, 16));
g.drawString(sdf.format(cal.getTime()), 120, 20);
g.setFont(new Font("Arial", Font.BOLD, 10));
}
public void drawHands(Graphics g, double second, double minute, double hours) {
double rSecond = (second * 6) * (Math.PI) / 180;
double rMinute = ((minute + (second / 60)) * 6) * (Math.PI) / 180;
double rHours = ((hours + (minute / 60)) * 30) * (Math.PI) / 180;
g.setColor(Color.RED);
g.drawLine(150, 150, 150 + (int) (100 * Math.cos(rSecond - (Math.PI / 2))), 150 + (int) (100 * Math.sin(rSecond - (Math.PI / 2))));
g.setColor(Color.BLACK);
g.drawLine(150, 150, 150 + (int) (70 * Math.cos(rMinute - (Math.PI / 2))), 150 + (int) (70 * Math.sin((rMinute - (Math.PI / 2)))));
g.drawLine(150, 150, 150 + (int) (50 * Math.cos(rHours - (Math.PI / 2))), 150 + (int) (50 * Math.sin(rHours - (Math.PI / 2))));
}
public static void main(String[] args) {
// Swing / AWT GUIs should be created & changed on the EDT ..
Runnable r = () -> {
JFrame frame = new JFrame("Clock 2D");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(330, 330));
Clock2d clock2d = new Clock2d();
clock2d.setPreferredSize(new Dimension(320, 320));
frame.setLayout(new BorderLayout());
frame.getContentPane().add(clock2d, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
};
// .. this is how we ensure that Runnable is on the EDT.
SwingUtilities.invokeLater(r);
}
}
Further tip re fonts:
g.setFont(new Font("Arial", Font.BOLD, 10));
Given the paint method is called repeatedly, it would be best to establish the fonts (both of them) when the class is constructed and store them a attributes of the class (which can be referenced in the methods).
But better to use logical fonts instead of something like 'Arial', like this:
g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 10));
Not only does that provide compile time checking, but it adapts across OS platforms. For example, the SANS_SERIF font would result in Arial on Windows and probably most *nix boxes, but on OS X the default SANS_SERIF (undecorated) font is Helvetica.
The other font, Tahoma, is more problematic. Again it's likely to be present on many Windows boxes, but it might be best to either test for it and have a list of backups, or supply the font with the clock app. (assuming you have distribution rights).
I'm designing a simple fractal program in Java that will start by drawing a rectangle then recursively draw rectangles 1/4 the size at each corner. This will repeat and span in all directions until the dimensions converge to 0.
I have the program and design completely functional as of now; however, I'm making additions that I am unsure of how to do. When I run the program, the fractal is shown already complete in the JFrame that pops up. What I want to do is have each rectangle appear individually with a short delay between each one being painted.
I have a class for my main method which simply instantiates a GUI object and calls its run() method. For the most part, all the relevant code exists in these two files.
In the GUI class
public GUI()
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
fractal = new Fractal(this, screenSize.width, screenSize.height);
this.setTitle("Fractals");
this.setSize(screenSize.width, screenSize.height);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(fractal);
this.setFocusable(true);
this.setVisible(true);
}
public void run()
{
fractal.repaint();
}
In the Fractal class
public Fractal(GUI gui, int width, int height)
{
this.gui = gui;
this.screenWidth = width;
this.screenHeight = height;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
/* Calculate coordinates and dimensions */
int x = 3 * this.screenWidth / 8;
int y = 3 * this.screenHeight / 8;
int width = this.screenWidth / 4;
int height = this.screenHeight / 4;
/* Draw the center rectangle */
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
/* Adjust dimensions for next rectangles */
width /= 2;
height /= 2;
/* Draw rectangles at the corners */
drawTopLeft(g, x - width, y - height, width, height);
drawBottomLeft(g, x - width, y + (2 * height), width, height);
drawTopRight(g, x + (2 * width), y - height, width, height);
drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
}
public void drawTopLeft(Graphics g, int x, int y, int width, int height)
{
/* Ensure the boundaries lay within the screen */
if(x > 0 && y > 0)
{
/* Draw itself */
g.fillRect(x, y, width, height);
/* Adjust dimensions for next rectangles */
width /= 2;
height /= 2;
/* Draw rectangles at the corners */
if(width > 0 && height > 0)
{
drawTopLeft(g, x - width, y - height, width, height);
drawBottomLeft(g, x - width, y + (2 * height), width, height);
drawTopRight(g, x + (2 * width), y - height, width, height);
}
}
}
public void drawBottomLeft(Graphics g, int x, int y, int width, int height)
{
/* Ensure the boundaries lay within the screen */
if(x > 0 && y + height < screenHeight)
{
/* Draw itself */
g.fillRect(x, y, width, height);
/* Adjust dimensions for next rectangles */
width /= 2;
height /= 2;
/* Draw rectangles at the corners */
if(width > 0 && height > 0)
{
drawTopLeft(g, x - width, y - height, width, height);
drawBottomLeft(g, x - width, y + (2 * height), width, height);
drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
}
}
}
public void drawTopRight(Graphics g, int x, int y, int width, int height)
{
/* Ensure the boundaries lay within the screen */
if(x + width < screenWidth && y > 0)
{
/* Draw itself */
g.fillRect(x, y, width, height);
/* Adjust dimensions for next rectangles */
width /= 2;
height /= 2;
/* Draw rectangles at the corners */
if(width > 0 && height > 0)
{
drawTopLeft(g, x - width, y - height, width, height);
drawTopRight(g, x + (2 * width), y - height, width, height);
drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
}
}
}
public void drawBottomRight(Graphics g, int x, int y, int width, int height)
{
/* Ensure the boundaries lay within the screen */
if(x + width < screenWidth && y + height < screenHeight)
{
/* Draw itself */
g.fillRect(x, y, width, height);
/* Adjust dimensions for next rectangles */
width /= 2;
height /= 2;
/* Draw rectangles at the corners */
if(width > 0 && height > 0)
{
drawBottomLeft(g, x - width, y + (2 * height), width, height);
drawTopRight(g, x + (2 * width), y - height, width, height);
drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
}
}
}
Here is what the output generates.
You need to calculate each rectangle outside of the paintComponent method. Each subsequent one should be stored in an array or list or some data structure. Then call repaint and sleep for 1 second (but don't sleep in the paintComponent method).
Your paintComponent method must then iterate thru the list of rectangles and paint each one. So each time repaint is called, your old ones and then your new one will be painted.
Bottom line, do not do much processing in paintComponent or any other method that runs in the EDT or your application will become unresponsive or not work as desired.
One more thing. Any drawing that you do in paintComponent will not be visible until you leave the method.
I didn't see you image earlier. If you are going to be drawing curves or diagonal lines, then set the following in paintComponent before painting. It will smooth out the graphics.
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
I want to create a custom shape for a JPanel, here's an example of how to shape a JPanel:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FunkyShapedComponent {
public static void main(String[] args) {
new FunkyShapedComponent();
}
public FunkyShapedComponent() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JPanel testPane = new JPanel();
testPane.setBackground(Color.RED);
testPane.setLayout(new GridBagLayout());
testPane.add(new FunkyPane());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class FunkyPane extends JPanel {
public FunkyPane() {
setLayout(new GridBagLayout());
add(new JLabel("This is a simple test"));
setOpaque(false);
}
#Override
public Insets getInsets() {
return new Insets(10, 10, 10, 10);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth() - 1;
int height = getHeight() - 1;
int radius = Math.min(width, height) / 10;
Path2D p = new Path2D.Float();
p.moveTo(0, radius / 2);
p.curveTo(0, 0, 0, 0, radius / 2, 0);
p.curveTo(width / 4, radius, width / 4, radius, (width / 2) - radius, radius / 2);
p.curveTo(width / 2, 0, width / 2, 0, (width / 2) + radius, radius / 2);
p.curveTo(width - (width / 4), radius, width - (width / 4), radius, width - (radius / 2), 0);
p.curveTo(width, 0, width, 0, width, radius / 2);
p.curveTo(width - radius, height / 4, width - radius, height / 4, width - (radius / 2), (height / 2) - radius);
p.curveTo(width, height / 2, width, height / 2, width - (radius / 2), (height / 2) + radius);
p.curveTo(width - radius, height - (height / 4), width - radius, height - (height / 4), width, height - (radius / 2));
p.curveTo(width, height, width, height, width - (radius / 2), height);
p.curveTo(width - (width / 4), height - radius, width - (width / 4), height - radius, (width / 2) + radius, height - (radius / 2));
p.curveTo(width / 2, height, width / 2, height, (width / 2) - radius, height - (radius / 2));
p.curveTo((width / 4), height - radius, (width / 4), height - radius, (radius / 2), height);
p.curveTo(0, height, 0, height, 0, height - (radius / 2));
p.curveTo(radius, height - (height / 4), radius, height - (height / 4), (radius / 2), (height / 2) + radius);
p.curveTo(0, height / 2, 0, height / 2, (radius / 2), (height / 2) - radius);
p.curveTo(radius, (height / 4), radius, (height / 4), 0, (radius / 2));
p.closePath();
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setColor(getBackground());
g2d.fill(p);
g2d.dispose();
}
}
}
This is what it does:
And this is the shape i want:
What i want is to add components to a panel with that shape, but i don't know how to manage path2D, if there's a better way to do it, please tell me
I personally wouldn't attempt to misshape the JPanel, it is essentially what holds everything else and isn't something you should change. Instead I would create a custom shape according to what you would like. I am assuming you want the shape to hide something else; because you originally used the JPanel, so I would paint the shape last; this would give the desired effect.
Here's What You Can Do:
Draw an Arbitrary Shape; Java doesn't support custom shapes directly.
Here is a link which will explain everything: http://docs.oracle.com/javase/tutorial/2d/geometry/arbitrary.html
I Hope This Helped :)
*Just so you know the sample code only leads to the download for the image.
See How to Create Translucent and Shaped Windows
To create that shape you can mask out the top and bottom of a rectangle with two ellipses. Examples here.
I would be inclined to do it with JavaFX such as this.
Your code link points to the image link.
The following code is an animation of a clock.
What changes would have to be made in the program to make it not flicker?
Why does the field initiation have to take place in the addNotify() function for the hands to be displayed?
You can copy all of it into one .java file and it should work (flicker ;) ).
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class ac extends Frame implements Runnable {
// for double buffering
Graphics og;
Image oi;
Thread t = null;
int width, height;
int timeH, timeM, timeS, radius = 50, lenH, lenM, lenS,
lenIn, cx, cy, x1, y1, x2, y2;
private boolean timeToQuit;
ac() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
stopRunning();
dispose();
}
});
setMinimumSize(new Dimension(300, 300));
EventQueue.invokeLater(new Runnable() {
public void run() {
setVisible(true);
}
});
}
public void addNotify() {
super.addNotify();
width = getBounds().width;
height = getBounds().height;
setSize(width, height);
lenH = 5 * radius / 10;
lenM = 6 * radius / 10;
lenS = 7 * radius / 10;
lenIn = 8 * radius / 10;
cx = width / 2;
cy = height / 2;
// for double buffering
oi = createImage(width, height);
og = oi.getGraphics();
}
public static void main(String [] args) {
ac clock = new ac();
clock.start();
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
}
public void stopRunning() {
timeToQuit = true;
}
public void run() {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY - 1);
do {
repaint();
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
}
}
while (!timeToQuit);
System.out.println("Quitting");
}
public void paint(Graphics g) {
og.setColor(new Color(170, 170, 170));
og.fillRect(0, 0, width, height);
Calendar cal = new GregorianCalendar();
timeH = cal.get(Calendar.HOUR);
timeM = cal.get(Calendar.MINUTE);
timeS = cal.get(Calendar.SECOND);
if (timeH >= 12)
timeH -= 12;
for (int i = 1 ; i < 13 ; i++) {
og.setColor(new Color(20, 20, 20));
x2 = (int) (cx + radius * Math.sin(i * 2 * 3.14159f / 12));
y2 = (int) (cy - radius * Math.cos(i * 2 * 3.14159f / 12));
if (i % 3 != 0) {
x1 = (int) (cx + 0.9f * radius * Math.sin(i * 2 * 3.14159f / 12));
y1 = (int) (cy - 0.9f * radius * Math.cos(i * 2 * 3.14159f / 12));
}
else {
x1 = (int) (cx + 0.8f * radius * Math.sin(i * 2 * 3.14159f / 12));
y1 = (int) (cy - 0.8f * radius * Math.cos(i * 2 * 3.14159f / 12));
}
og.drawLine(x1, y1, x2, y2);
og.setColor(new Color(230, 230, 230));
og.drawLine(x1 - 1, y1 - 1, x2 - 1, y2 - 1);
}
og.setColor(new Color(20, 20, 20));
x2 = (int) (cx + lenH * Math.sin((timeH + timeM / 60.0f + timeS / 3600.0f)
* 2 * 3.14159f / 12));
y2 = (int) (cy - lenH * Math.cos((timeH + timeM / 60.0f + timeS / 3600.0f)
* 2 * 3.14159f / 12));
og.drawLine(cx, cy, x2, y2);
og.setColor(Color.red);
og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);
og.setColor(new Color(20, 20, 20));
x2 = (int) (cx + lenM * Math.sin((timeM + timeS / 60.0f) * 2 * 3.14159f
/ 60));
y2 = (int) (cy - lenM * Math.cos((timeM + timeS / 60.0f) * 2 * 3.14159f
/ 60));
og.drawLine(cx, cy, x2, y2);
og.setColor(Color.green);
og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);
og.setColor(new Color(20, 20, 20));
x2 = (int) (cx + lenS * Math.sin(timeS * 2 * 3.14159f / 60));
y2 = (int) (cy - lenS * Math.cos(timeS * 2 * 3.14159f / 60));
og.drawLine(cx, cy, x2, y2);
og.setColor(Color.blue);
og.drawLine(cx - 1, cy - 1, x2 - 1, y2 - 1);
og.setColor(new Color(20, 20, 20));
og.drawOval((width - 2 * radius) / 2, (height - 2 * radius) / 2,
2 * radius, 2 * radius);
og.setColor(new Color(230, 230, 230));
og.drawOval((width - 2 * radius) / 2 - 1, (height - 2 * radius) / 2 - 1,
2 * radius, 2 * radius);
g.drawImage(oi, 0, 0, this);
}
}
This uses awt which is old and it paints on to the main Frame - not the best way to make a swing UI. You can try this :
make the timer - sleep amount to less or more, try 300 or 800
use a Panel to draw on, add the panel to the frame
use swing (use a JComponent, it double buffers automatically, and a JFrame
For 2 and 3 you can keep original class to make Frame/JFrame and a new class for the java.awt.Panel or javax.swing.JComponent which is added to the former.
Does not flicker on my mac system, so i think its an OS + times its refreshed issue. Meaning suggestion 1 might work - try that first. Talking about line of code :
Thread.sleep(800);
Believe it or not, the problem was solved by adding the function:
public void update(Graphics g)
{
paint(g);
}
But the question remains, why? And why aren't the hands displayed when you initiate the class fields outside the addNotify() function?
import java.awt.*;
import javax.swing.JPanel;
public class FigurePanel extends JPanel {
// Define constants
public static final int LINE = 1;
public static final int RECTANGLE = 2;
public static final int ROUND_RECTANGLE = 3;
public static final int OVAL = 4;
public static final int ARC = 5;
public static final int POLYGON = 6;
private int type = 1;
private boolean filled;
/** Construct a default FigurePanel */
public FigurePanel() {
}
/** Construct a FigurePanel with the specified type */
public FigurePanel(int type) {
this.type = type;
}
/** Construct a FigurePanel with the specified type and filled */
public FigurePanel(int type, boolean filled) {
this.type = type;
this.filled = filled;
}
/** Draw a figure on the panel */
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Get the appropriate size for the figure
int width = getSize().width;
int height = getSize().height;
switch (type) {
case LINE: // Display two cross lines
g.setColor(Color.BLACK);
g.drawLine(10, 10, width - 10, height - 10);
g.drawLine(width - 10, 10, 10, height - 10);
break;
case RECTANGLE: // Display a rectangle
g.setColor(Color.BLUE);
if (filled)
g.fillRect((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height));
else
g.drawRect((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height));
break;
case ROUND_RECTANGLE: // Display a round-cornered rectangle
g.setColor(Color.RED);
if (filled)
g.fillRoundRect((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height), 20, 20);
else
g.drawRoundRect((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height), 20, 20);
break;
case OVAL: // Display an oval
g.setColor(Color.BLACK);
if (filled)
g.fillOval((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height));
else
g.drawOval((int)(0.1 * width), (int)(0.1 * height),
(int)(0.8 * width), (int)(0.8 * height));
break;
case ARC: // Display an arc
g.setColor(Color.BLACK);
if (filled) {
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius =
(int)(Math.min(getWidth(), getHeight()) * 0.4);
int x = xCenter - radius;
int y = yCenter - radius;
g.fillArc(x, y, 2 * radius, 2 * radius, 0, 30);
g.fillArc(x, y, 2 * radius, 2 * radius, 90, 30);
g.fillArc(x, y, 2 * radius, 2 * radius, 180, 30);
g.fillArc(x, y, 2 * radius, 2 * radius, 270, 30);
}
else {
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius =
(int)(Math.min(getWidth(), getHeight()) * 0.4);
int x = xCenter - radius;
int y = yCenter - radius;
g.drawArc(x, y, 2 * radius, 2 * radius, 0, 30);
g.drawArc(x, y, 2 * radius, 2 * radius, 90, 30);
g.drawArc(x, y, 2 * radius, 2 * radius, 180, 30);
g.drawArc(x, y, 2 * radius, 2 * radius, 270, 30);
};
break;
case POLYGON: // Display a polygon
g.setColor(Color.BLACK);
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius =
(int)(Math.min(getWidth(), getHeight()) * 0.4);
// Create a Polygon object
Polygon polygon = new Polygon();
// Add points to the polygon
polygon.addPoint(xCenter + radius, yCenter);
polygon.addPoint((int)(xCenter + radius *
Math.cos(2 * Math.PI / 6)), (int)(yCenter - radius *
Math.sin(2 * Math.PI / 6)));
polygon.addPoint((int)(xCenter + radius *
Math.cos(2 * 2 * Math.PI / 6)), (int)(yCenter - radius *
Math.sin(2 * 2 * Math.PI / 6)));
polygon.addPoint((int)(xCenter + radius *
Math.cos(3 * 2 * Math.PI / 6)), (int)(yCenter - radius *
Math.sin(3 * 2 * Math.PI / 6)));
polygon.addPoint((int)(xCenter + radius *
Math.cos(4 * 2 * Math.PI / 6)), (int)(yCenter - radius *
Math.sin(4 * 2 * Math.PI / 6)));
polygon.addPoint((int)(xCenter + radius *
Math.cos(5 * 2 * Math.PI / 6)), (int)(yCenter - radius *
Math.sin(5 * 2 * Math.PI / 6)));
// Draw the polygon
if (filled)
g.fillPolygon(polygon);
else
g.drawPolygon(polygon);
}
}
/** Set a new figure type */
public void setType(int type) {
this.type = type;
// repaint();
}
/** Return figure type */
public int getType() {
return type;
}
/** Set a new filled property */
public void setFilled(boolean filled) {
this.filled = filled;
repaint();
}
/** Check if the figure is filled */
public boolean isFilled() {
return filled;
}
/** Specify preferred size */
public Dimension getPreferredSize() {
return new Dimension(80, 80);
}
}
^ That is Figure Panel class
import java.awt.*;
import javax.swing.*;
public class fan extends JFrame {
public static void main(String[] args) {
JFrame frame = new fan();
frame.setSize(300, 300);
frame.setTitle("Exercise13_09");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null); // Center the frame
frame.setVisible(true);
}
public fan() {
setLayout(new GridLayout(2, 2));
add(new FigurePanel(FigurePanel.ARC, true));
add(new FigurePanel(FigurePanel.OVAL));
add(new FigurePanel(FigurePanel.ARC, true));
add(new FigurePanel(FigurePanel.OVAL, true));
}
}
This is the fan class
I'm currently trying to make a picture of a fan to show up on the screen and was wondering if there was a way to make it draw both the arc and oval in the same spot? I have been messing around with the Figure panel class but I'm not quite sure how I could merge ARC true with OVAL. Help would be appreciated thank you
Add drawOval() at the end of the fill branch of case ARC:
g.drawOval(x, y, 2 * radius, 2 * radius);
Also consider RenderingHints:
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);