Java JFrame distance between ovals not equal - java

I had to implement a JFrame with the size of 500 x 500 pixels that should have a 9 x 9 "field" of circles, but as you can see in the picture the distance between the first line of ovals and the second line of ovals is not equal.
The diameter should be 20 pixel and the distance between the center of one oval to another oval should be 40 pixel, but I don't know if I did this correctly:
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Color;
public class KreisFrame extends JFrame {
public KreisFrame() {
//Set JFrame size
setSize(500,500);
//Make JFrame visible
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, 500, 500);
for (int j = 0; j < 500; j += 60){
for (int i = 0; i < 500; i += 60) {
// draw circle
g.drawOval(i, 20, 20, 20);
g.drawOval(i, j, 20, 20);
// fill circle
g.fillOval(i, 20, 20, 20);
g.fillOval(i, j, 20, 20);
g.setColor(Color.BLUE);
}
}
}
public static void main(String[]args) {
KreisFrame myframe = new KreisFrame();
}
}
Can someone tell me what I did wrong?

You should really subclass a JPanel, not the JFrame. And all of this should be done on the EventDispatchThread, not the main thread. Further, don't use "magic" numbers like 500, 20, and 40. Here's a solution that paints the entire panel, regardless of what size it is (note that there is no provision here for having a border on the panel).
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Kreis extends JPanel {
protected int dia = 20;
protected int sep = 40;
public Kreis() {
// Set JFrame size
setPreferredSize(new Dimension(500, 500));
setBackground(Color.green);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = getSize();
g.setColor(Color.BLUE);
for (int y = 0; y < d.height; y += sep) {
for (int x = 0; x < d.width; x += sep) {
// draw circle
g.fillOval(x, y, dia, dia);
}
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Create and set up the window.
JFrame jf = new JFrame();
Kreis panel = new Kreis();
jf.add(panel);
jf.pack();
jf.setVisible(true);
jf.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing( WindowEvent arg0) {
System.exit(0);
}
});
}
});
}
}

Related

Why does the star rotation slows down automatically after some time

I have a program where I have to use internal Timer event to rotate a star in circular motion. There is a button in the frame that changes the direction of the star and a slider which changes the speed of the star rotation.
This is my Main Class
import javax.swing.JFrame;
public class Main {
public static void main(String args[]) {
// Making an instance of the class that makes the frame
MainFrame frame = new MainFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
}
MainFrame Class that makes the frame.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class MainFrame extends JFrame{
private StarGraphics frameStar;
private JButton starToggle;
public JSlider starSpeed;
public MainFrame() {
// Setting some properties of the frame
setTitle("Star Moving with Internal Events");
setLayout(new BorderLayout());
// Initializing the panel which has rotating star
frameStar = new StarPainter(this);
// Adding the bottom toggle button and slider
addToggler();
}
// Getter for the slider value
public int sliderSpeed() {
return starSpeed.getValue();
}
// Adds Button to change the direction of the star
private void addToggler() {
// Adding another jpanel which has layout set to null so i can add button of my size
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(20,80));
panel.setBackground(Color.WHITE);
// Initializing button and its action listener to change star direction
starToggle = new JButton("Toggle");
starToggle.setBounds(190, 0, 80, 20);
starToggle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == starToggle) {
frameStar.ChangeDirections();
}
}
});
// Adding button to panel
panel.add(starToggle);
// Adding slider to the panel
addSlider(panel);
// Adding panel to the main Panel at the bottom
add(panel, BorderLayout.SOUTH);
}
private void addSlider(JPanel panel) {
// Adding Slider and it's properties
starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
starSpeed.setMajorTickSpacing(10);
starSpeed.setMinorTickSpacing(1);
starSpeed.setPaintTicks(true);
starSpeed.setPaintLabels(true);
starSpeed.setBounds(70,30,400, 45);
// Adding Slider-ChangeListener to change the rotation speed of the star
starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class
// handle change in slider value
#Override
public void stateChanged(ChangeEvent e) {
frameStar.ChangeSpeed(starSpeed.getValue());
}
}
);
// Adding label besides the slider
JLabel label = new JLabel("Speed : ");
label.setBounds(10 , 10, 80, 80);
panel.add(label);
panel.add(starSpeed);
}
}
Class to create the panel that has star rotation
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class StarGraphics extends JPanel{
private boolean toggleDir = false;
private int speed = 10;
private Timer timer;
protected double angleOfStarRotation = 0;
public StarGraphics(JFrame frame) {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
startTimer();
}
public void startTimer() {
timer = new Timer(speed, new ActionListener() {
public void actionPerformed(ActionEvent e){
// System.out.println(angleOfStarRotation);
if(!toggleDir) //rotates clockwise
angleOfStarRotation = angleOfStarRotation + 1;
else //rotates counterclockwise
angleOfStarRotation = angleOfStarRotation - 1;
// if (angleOfStarRotation == 360 || angleOfStarRotation == -360) // If there is a full circle, it will reset the angle to zero
// angleOfStarRotation = 0;
repaint();
}});
timer.start();
}
public void ChangeSpeed(int newSpeed) {
this.speed = newSpeed;
timer.setDelay(speed);
}
public void ChangeDirections() {toggleDir = !toggleDir; }
}
And a class that paints the star into the panel
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.security.SecureRandom;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class StarPainter extends StarGraphics{
private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
GeneralPath starDesign = new GeneralPath();
public StarPainter(JFrame frame) {
super(frame);
}
public void drawStar(GeneralPath path) {
path.moveTo(starXPoints[0], starYPoints[0]);
for(int i=0; i<10; i++)
path.lineTo(starXPoints[i], starYPoints[i]);
path.closePath();
}
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
// rotate around origin and draw stars in random colors
for (int count = 1; count <= 1; count++)
{
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawStar(starDesign);
g2d.translate(250,150);
starActions(g2d);
}
}
After running the code, the output will show a frame with coloring star rotating around the panel in circular motion, but after 2 full rotation, the star rotation slow down automatically. Does anyone know why that happens?
Your "core" problem is right here...
public void drawStar(GeneralPath path) {
path.moveTo(starXPoints[0], starYPoints[0]);
for(int i=0; i<10; i++)
path.lineTo(starXPoints[i], starYPoints[i]);
path.closePath();
}
This gets called each time you re-draw the component, which means, you're adding new points to the shape, making it infinitely more complex on each paint pass.
Instead, just create the shape in the constructor...
public StarPainter() {
starDesign.moveTo(starXPoints[0], starYPoints[0]);
for (int i = 0; i < 10; i++) {
starDesign.lineTo(starXPoints[i], starYPoints[i]);
}
starDesign.closePath();
}
As has already been pointed out, you're disposing of a Graphics context which you did not create.
If your going to change the transformation of the context, you should always create a copy of your own, for example...
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
g = (Graphics2D) g.create();
// rotate around origin and draw stars in random colors
//for (int count = 1; count <= 1; count++) {
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
//}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(250, 150);
starActions(g2d);
g2d.dispose();
}
Also, passing a reference of the JFrame to the component...
public StarGraphics(JFrame frame) {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
startTimer();
}
is a bad idea. The component has no need for, nor is it its responsibility too, interact with the frame. You're just exposing implementation detail unnecessarily.
Runnable example
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.security.SecureRandom;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MainFrame frame = new MainFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
});
}
public class MainFrame extends JFrame {
private StarGraphics frameStar;
private JButton starToggle;
public JSlider starSpeed;
public MainFrame() {
// Setting some properties of the frame
setTitle("Star Moving with Internal Events");
setLayout(new BorderLayout());
// Initializing the panel which has rotating star
frameStar = new StarPainter();
add(frameStar);
// Adding the bottom toggle button and slider
addToggler();
}
// Getter for the slider value
public int sliderSpeed() {
return starSpeed.getValue();
}
// Adds Button to change the direction of the star
private void addToggler() {
// Adding another jpanel which has layout set to null so i can add button of my size
JPanel panel = new JPanel();
panel.setLayout(null);
panel.setPreferredSize(new Dimension(20, 80));
panel.setBackground(Color.WHITE);
// Initializing button and its action listener to change star direction
starToggle = new JButton("Toggle");
starToggle.setBounds(190, 0, 80, 20);
starToggle.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == starToggle) {
frameStar.ChangeDirections();
}
}
});
// Adding button to panel
panel.add(starToggle);
// Adding slider to the panel
addSlider(panel);
// Adding panel to the main Panel at the bottom
add(panel, BorderLayout.SOUTH);
}
private void addSlider(JPanel panel) {
// Adding Slider and it's properties
starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
starSpeed.setMajorTickSpacing(10);
starSpeed.setMinorTickSpacing(1);
starSpeed.setPaintTicks(true);
starSpeed.setPaintLabels(true);
starSpeed.setBounds(70, 30, 400, 45);
// Adding Slider-ChangeListener to change the rotation speed of the star
starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class
// handle change in slider value
#Override
public void stateChanged(ChangeEvent e) {
frameStar.ChangeSpeed(starSpeed.getValue());
}
}
);
// Adding label besides the slider
JLabel label = new JLabel("Speed : ");
label.setBounds(10, 10, 80, 80);
panel.add(label);
panel.add(starSpeed);
}
}
public class StarGraphics extends JPanel {
private boolean toggleDir = false;
private int speed = 10;
private Timer timer;
protected double angleOfStarRotation = 0;
public StarGraphics() {
setPreferredSize(new Dimension(500, 470));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
startTimer();
}
public void startTimer() {
timer = new Timer(speed, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println(angleOfStarRotation);
if (!toggleDir) //rotates clockwise
{
angleOfStarRotation = angleOfStarRotation + 1;
} else //rotates counterclockwise
{
angleOfStarRotation = angleOfStarRotation - 1;
}
System.out.println("tick");
// if (angleOfStarRotation == 360 || angleOfStarRotation == -360) // If there is a full circle, it will reset the angle to zero
// angleOfStarRotation = 0;
repaint();
}
});
timer.start();
}
public void ChangeSpeed(int newSpeed) {
this.speed = newSpeed;
timer.setDelay(speed);
}
public void ChangeDirections() {
toggleDir = !toggleDir;
}
}
public class StarPainter extends StarGraphics {
private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
GeneralPath starDesign = new GeneralPath();
public StarPainter() {
starDesign.moveTo(starXPoints[0], starYPoints[0]);
for (int i = 0; i < 10; i++) {
starDesign.lineTo(starXPoints[i], starYPoints[i]);
}
starDesign.closePath();
}
public void starActions(Graphics2D g) {
int startAngle = 360;
// For Random Color
SecureRandom random = new SecureRandom();
g = (Graphics2D) g.create();
// rotate around origin and draw stars in random colors
//for (int count = 1; count <= 1; count++) {
double angle = startAngle - 90;
// rotate coordinate system
g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle //
// set random drawing color
g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
// draw filled star
g.fill(starDesign);
// dispose the star
g.dispose();
//}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(250, 150);
starActions(g2d);
g2d.dispose();
}
}
}

Drawing rectangle within the loop?

I'm trying to animate a rectangle based on a coordinate determined by for-loop, inside a button. Here is my JComponent Class:
public class Rect extends JComponent {
public int x;
public int y;
public int w;
public int h;
public Rect (int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
repaint();
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(Color.green);
g2.drawRect(x+15, y+15, w, h);
}
}
and here is my button and button inside JFrame class:
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
}
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
validate();
repaint();
}
}
});
}
But when I run the code and click the button, nothing happens. What's wrong?
EDIT: I run the frame inside my main class like this:
public class OrImage {
public static void main(String[] args) throws Exception
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
});
}
}
I changed the code of class MainFrame such that when you press the animate button, something happens, but I don't know if that is what you want to happen.
I did not change class Rect and I added main() method to MainFrame just to keep everything in one class.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
lm.add(R);
}
lm.revalidate();
lm.repaint();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
The main change is in method actionPerformed(). You need to add R to the JPanel. You need to call revalidate() on the JPanel because you have changed the number of components that it contains. And after calling revalidate() you should call repaint() (again, on the JPanel) to make it redraw itself.
This is how it looks before pressing animate.
And this is how it looks after pressing animate
EDIT
As requested – with animation.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
private int x;
private int y;
private Timer timer;
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
timer = new Timer(500, event -> {
if (x < 500) {
lm.remove(R);
x += 50;
y += 50;
R = new Rect(x, y, 50, 50);
lm.add(R);
lm.revalidate();
lm.repaint();
}
else {
timer.stop();
}
});
timer.setInitialDelay(0);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}

Add a rectangle to the center of JPanel

I'm trying to draw a Rectangle to the center of a JPanel. I have made this code but when I run it, the rectangle does not appears in the panel. If I try with JFrame, the rectangle appears. Can someone help me?
RectangleTester
package eventi5;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RectangleTester {
public static void main(String[] args) {
JFrame frame = new JFrame("Rectangle");
frame.setSize(250, 250);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final RectangleComponent component = new RectangleComponent();
frame.setVisible(true);
JPanel panel=new JPanel();
panel.add(component);
frame.add(panel);
}
}
RectangleComponent
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class RectangleComponent extends JPanel{
private Rectangle box;
public RectangleComponent(){
box=new Rectangle(10,20,30,40);
}
public void paintComponent(Graphics g){
Graphics2D g2=(Graphics2D) g;
g2.draw(box);
g2.setColor(Color.BLUE);
g2.fill(box);
}
}
1) You need override getPreferredSize() of RectangleComponent like next:
#Override
public Dimension getPreferredSize() {
return new Dimension(box.width+box.x*2,box.height+box.y*2);
}
2) call super() method of paintComponent()( super.paintComponent(g);) before your customizations.
EDIT:
public class RectangleComponent extends JPanel {
private List<Rectangle> boxes;
private int width = 30;
private int height = 40;
private int startX = 10;
private int startY = 20;
public RectangleComponent() {
boxes = new ArrayList<Rectangle>();
for (int i = 0; i < 3; i++){
boxes.add(new Rectangle(startX+(width+startX)*i, startY, width, height));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < boxes.size(); i++){
g2.draw(boxes.get(i));
}
g2.setColor(Color.BLUE);
for (int i = 0; i < boxes.size(); i++){
g2.fill(boxes.get(i));
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(boxes.size()*(width+startX)+startX, height+startY*2);
}
}

JPanel causing extra space to the side?

I made a simple program that uses drawString() to draw on a JPanel that gets repainted to change the background to a random color. It works fine, other than the ~10 pixel spaces to the right side and bottom side of the JPanel, which remain the default color. I think this problem might be happening because of the way I use pack() or getPrefferedSize(). Any help or suggestions to fix this are appreciated.
Birthday.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Birthday {
DrawString panel = new DrawString();
public Birthday() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.setTitle("Happy Birthday!");
f.setLocation(10, 10);
f.pack();
f.setVisible(true);
f.setResizable(false);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
timer.start();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Birthday();
}
});
}
}
DrawString.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawString extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int x = 350;
int y = 250;
int red = random(0,255);
int green = random(0,255);
int blue = random(0,255);
Color black = new Color(0,0,0);
Color newColor = new Color(red,green,blue);
g.setColor(newColor);
g.fillRect(0,0,1000,500);
g.setColor(black);
g.setFont(new Font(null,Font.BOLD,40));
g.drawString("Happy Birthday!",x,y);
}
public static int random(int min, int max)
{
int range = max - min + 1;
int number = (int) (range * Math.random() + min);
return number;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 500);
}
}
You never want to explicitly call paintComponent. Instead if you want the panel to repaint, you can call panel.repaint(), and the panel with implicitly call its own paintComponent method for you.
Don't do every thing inside the main method, you'll find you're going to run into a lot of problems with static references.
Don't use Thread.sleep(), it will block the Event Dispatch Thread., as that's where you should be running you Swing apps from. Instead use a java.swing.Timer. See this example for Timer usage.
As noted in 3, run your Swing apps from the EDT like this
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new MyApp();
}
});
}
Don't set the size of your frame. Instead override getPreferredSize() of your DrawingPanel and just pack() the frame.
You can center the frame by using setLocationRelativeTo(null)
Should make it a habit to use the #Override annotation to make sure you are override correctly.
Add-on to 2. What you make a habit of doing, is doing your work from the constructor, then just calling the constructor in the main. Here is a refactor of your code with all the above mentioned things fixed. You can run it.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Birthday {
DrawString panel = new DrawString();
public Birthday() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.setTitle("Happy Birthday!");
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setResizable(false);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
});
timer.start();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Birthday();
}
});
}
}
class DrawString extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int x = 350;
int y = 250;
int red = random(0, 255);
int green = random(0, 255);
int blue = random(0, 255);
Color black = new Color(0, 0, 0);
Color newColor = new Color(red, green, blue);
g.setColor(newColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(black);
g.setFont(new Font(null, Font.BOLD, 40));
g.drawString("Happy Birthday!", x, y);
}
public static int random(int min, int max) {
int range = max - min + 1;
int number = (int) (range * Math.random() + min);
return number;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 500);
}
}

Getting Unexpected output with the swing code

I'm trying to built a simple app which has a translucent frame and it draws lines where the user wants.I have also added listeners to catch the mouse events and these are displayed accordingly .Everything is working fine but the problems are:
1)the window is not transparent
2)it is completely black and the lines are appearing white.
Can anyone
Here is the code:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MouseListen2 extends JFrame implements MouseListener {
String str = "Nothing";
int x[][] = new int[100][2];
int count = 0;
int flag = 1;
boolean draw = false;
MouseListen2() {
super("Line Draw App");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
this.addMouseListener(this);
setBackground(new Color(0, 0, 0, 0));
JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Paint gp = new GradientPaint(300, 700, new Color(20, 20, 210, 0), 100, 00, new Color(10, 20, 40, 255));
g2.setPaint(gp);
g2.fillRect(0, 0, getWidth(), getHeight());
}
};
setContentPane(jp);
setVisible(true);
//c.setOpaque(true);
}
public void paint(Graphics g) {
//Graphics g=this.getGraphics();
//super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.clearRect(0, 0, getWidth(), getHeight());
g2.drawString(str, 50, 50);
//initially count=0 hence i<-1 so loop will not automatically run in the beginning
for (int i = 0; i < count - 1; i = i + 2) {
g2.drawLine(x[i][0], x[i][1], x[i + 1][0], x[i + 1][1]);
}
//repaint(); using this here creates an infinite loop as after mouse event paint is called and at the end
//this method is again called using the repaint() and so on the loop continues.
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MouseListen2();
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
str = "clicked";
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
str = "pressed";
repaint();
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
}
#Override
public void mouseReleased(MouseEvent e) {
str = "released";
draw = true;
x[count][0] = e.getX();
x[count][1] = e.getY();
count++;
//draw();
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
str = "entered";
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
str = "exited";
repaint();
}
}
have to add MouseListener to the JPanel, because you added MouseListener to the JFrame (this.addMouseListener(this);)
this code line setContentPane(jp); put JPanel to the BorderLayout.CENTER possition to the JFrame, in this case (isn't there any another JComponent added to the JFrame) fills whole / all available space into JFrame
then for mouse event is accesible only JPanel, mouse can't access to the JFrame's RootPane or ContentPane
remove / comment public void paint(Graphics g) and rellated code block move to the paintComponent for the JPanel
See How to Create Translucent and Shaped Windows.

Categories

Resources