Related
So, I need to make the stick-man movable by a user-input. When the user clicks on a part (Head, hands, feet and posterior) and he should move, and have no idea how to go about this..
If possible, there also needs to be a confine around the character, likely rectangular, so that there is a limit to how far each part can be pulled.
See below for my code;
// Created by Charlie Carr - (28/11/17 - /11/17)
import java.awt.*;
import java.applet.Applet;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
//Imports complete
//Suppress warning about undeclared static final serialVersionUID field in VS Code
#SuppressWarnings("serial")
public class Animator extends JPanel {
public static class AnimatorWindow extends JPanel {
public void paint(Graphics page) {
setBackground(Color.gray);
setForeground(Color.white);
super.paintComponent(page);
page.drawString("Stickmen Animation Station", 150, 15);
//draw the head
//x1, y1, x2, y2
page.drawOval(90, 60, 20, 20);
// draw the body
page.drawLine(100, 80, 100, 110);
// draw the hands
page.drawLine(100, 90, 80, 105);
page.drawLine(100, 90, 120, 105);
//draw the legs, he hasn't a leg to stand on..
page.drawLine(100, 110, 85, 135);
page.drawLine(100, 110, 115, 135);
}
}
public static void main(String[] args) {
AnimatorWindow displayPanel = new AnimatorWindow();
JPanel content = new JPanel();
content.setLayout(new BorderLayout());
content.add(displayPanel, BorderLayout.CENTER);
//declare window size
int x = 480;
int y = 240;
JFrame window = new JFrame("GUI");
window.setContentPane(content);
window.setSize(x, y);
window.setLocation(101, 101);
window.setVisible(true);
}
}
Use MouseListenerto deal with mouse events.
Also, you should override the paintComponent() method instead of paint(), because paint() also paints the border and other stuff.
public static class AnimatorWindow extends JPanel implements MouseListener{
public AnimatorWindow(){
setBackground(Color.gray);
setForeground(Color.white);
//add the listener
addMouseListener(this);
}
public void paintComponent(Graphics page) {
super.paintComponent(page);
//You should not alter the Graphics object passed in
Graphics2D g = (Graphics2D) page.create();
//draw your stuff with g
g.drawString("Stickmen Animation Station", 150, 15);
.......
//finish
g.dispose();
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){
//implement your clicking here
//Use e.getX() and e.getY() to get the click position
}
}
For more on swing events, check this site
EDIT: Your problem also includes animation, and you can use a javax.swing.Timer to do that.
I tried, adding the flowlayout as seen in other answers, but it still doesn't work.
I've also tried moving around my JLabel code into a constructor but that doesn't work either.
public class Paint {
public static void main(String[] args) {
JFrame frame = new JFrame("Paint");
frame.setSize(500,500);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
Draw draw = new Draw();
frame.add(draw);
frame.setVisible(true);
}
}
public class Draw extends JPanel{
public Draw(){
JLabel one = new JLabel("12",JLabel.CENTER);
setLayout(new FlowLayout());
add(one);
}
public void paint(Graphics g){
g.drawOval(70, 60, 190, 190);
g.setColor(Color.BLACK);
g.drawLine(90, 160, 170, 160);
g.drawLine(120, 190,170 , 160);
g.setColor(Color.GRAY);
g.fillOval(155, 153, 20, 20);
}
}
Change paint to override paintComponent
Call super.paintComponent before doing any custom painting
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Paint {
public static void main(String[] args) {
JFrame frame = new JFrame("Paint");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
Draw draw = new Draw();
frame.add(draw);
frame.setVisible(true);
}
public static class Draw extends JPanel {
public Draw() {
JLabel one = new JLabel("12", JLabel.CENTER);
setLayout(new FlowLayout());
add(one);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(70, 60, 190, 190);
g.setColor(Color.BLACK);
g.drawLine(90, 160, 170, 160);
g.drawLine(120, 190, 170, 160);
g.setColor(Color.GRAY);
g.fillOval(155, 153, 20, 20);
}
}
}
i have been working on a flashing beacon on java using Jpanel, paint component and timers, however i am having trouble trying to get the buttons within the code to function. when the code is run, the flash button is supposed to prompt the beacon to start blinking/flashing whereas the steady button keeps it on the same colour. the alternating colours for the beacon are orange and grey.As well as this i cant seem to get rid of a button that keeps appearing in the top left of the window when the code is run. so far, this is what i have
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
/**
* Created by Enoch on 26/03/2015.
*/
class BelishaBeacon extends JPanel {
Color startLight, stopLight, color;
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(color);
Ellipse2D firstOval = new Ellipse2D.Double(130, 70, 50, 50);
g2.draw(firstOval);
g2.fill(firstOval);
g2.setColor(Color.BLACK);
Rectangle rect1 = new Rectangle(150, 119, 10, 35);
g2.draw(rect1);
g2.fill(rect1);
g2.setColor(Color.WHITE);
Rectangle rect2 = new Rectangle(150, 150, 10, 35);
g2.draw(rect2);
g2.fill(rect2);
g2.setColor(Color.BLACK);
Rectangle rect3 = new Rectangle(150, 180, 10, 35);
g2.draw(rect3);
g2.fill(rect3);
g2.setColor(Color.WHITE);
Rectangle rect4 = new Rectangle(150, 210, 10, 35);
g2.draw(rect4);
g2.fill(rect4);
g2.setColor(Color.BLACK);
Rectangle rect5 = new Rectangle(150, 240, 10, 35);
g2.draw(rect5);
g2.fill(rect5);
g2.setColor(Color.WHITE);
Rectangle rect6 = new Rectangle(150, 270, 10, 35);
g2.draw(rect6);
g2.fill(rect6);
g2.setColor(Color.BLACK);
Rectangle rect7 = new Rectangle(150, 300, 10, 35);
g2.draw(rect7);
g2.fill(rect7);
g2.setColor(Color.WHITE);
Rectangle rect8 = new Rectangle(150, 330, 10, 35);
g2.draw(rect8);
g2.fill(rect8);
g2.setColor(Color.BLACK);
Rectangle rect9 = new Rectangle(150, 360, 10, 35);
g2.draw(rect9);
g2.fill(rect9);
g2.setColor(Color.WHITE);
Rectangle rect10 = new Rectangle(150, 390, 10, 35);
g2.draw(rect10);
g2.fill(rect10);
}
public BelishaBeacon() {
startLight = Color.ORANGE;
stopLight = Color.LIGHT_GRAY;
color = startLight;
new Blinker(this);
setBackground(Color.white);
}
public void blink()
{
color = (color == startLight ? stopLight : startLight);
repaint();
}
}
//
class Blinker
{
BelishaBeacon blinkPanel;
public Blinker(BelishaBeacon bp)
{
blinkPanel = bp;
new Timer(500, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
blinkPanel.blink();
}
}).start();
}
}
//
class BelishaBeaconViewer extends JFrame {
JButton jbtFlash = new JButton("Flash");
JButton jbtSteady = new JButton("Steady");
JPanel bPanel = new JPanel();
BelishaBeacon bBPanel = new BelishaBeacon();
public BelishaBeaconViewer() {
bPanel.add(jbtFlash);
this.add(bPanel, BorderLayout.SOUTH);
bPanel.add(jbtSteady);
this.add(bBPanel, BorderLayout.CENTER);
jbtFlash.addActionListener(new FlashListener());
jbtSteady.addActionListener(new SteadyListener());
}
class FlashListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
}
}
class SteadyListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
}
}
public static void main(String[] args) {
JFrame bBFrame = new BelishaBeaconViewer();
bBFrame.setTitle("Belisha Beacon");
bBFrame.setSize(300, 300);
bBFrame.setDefaultCloseOperation((JFrame.EXIT_ON_CLOSE));
bBFrame.setVisible(true);
}
}
i cant seem to get rid of a button that keeps appearing in the top left of the window
//super.paintComponents(g); // typo
super.paintComponent(g); // should be
Don't start the Timer automatically.
The FlashListener should start the Timer, no need for the repaint
The SteadyListner should stop the Timer, no need for the repaint.
I'm making a program where hovering over a grid will place an image into the cell hovered over. Currently I have it working so that only a color is filled in, but I have no idea how to make it so an image is drawn in instead. Here's my program:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class Test
{
Image img=Toolkit.getDefaultToolkit().getImage("img.gif");
public static void main(String[]args)
{
new Test();
}
public Test()
{
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PixelGrid());
frame.setSize(new Dimension(364,357));
frame.setVisible(true);
}
public class PixelGrid extends JPanel
{
private List<Shape>grid,square;
public PixelGrid()
{
grid=new ArrayList<>();
square=new ArrayList<>();
addMouseMotionListener(new MouseAdapter()
{
public void mouseMoved(MouseEvent e)
{
for(Shape shape:grid)
{
if(shape.contains(e.getPoint()))
square.add(shape);
}
repaint();
}
}
);
for(int row=0;row<5;row++)
{
for(int col=0;col<5;col++)
grid.add(new Rectangle(col*25+112,row*25+50,25,25));
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(112,50,237,50);
g.drawLine(112,75,237,75);
g.drawLine(112,100,237,100);
g.drawLine(112,125,237,125);
g.drawLine(112,150,237,150);
g.drawLine(112,175,237,175);
g.drawLine(112,50,112,175);
g.drawLine(137,50,137,175);
g.drawLine(162,50,162,175);
g.drawLine(187,50,187,175);
g.drawLine(212,50,212,175);
g.drawLine(237,50,237,175);
Graphics2D g2=(Graphics2D)g;
for(Shape cell:square)
g2.fill(cell);
}
}
}
I want to make the image "img" become the "pixel" that is filled in. However, I'm confused on how to do this as I don't think I can use for-each loops and Graphics2D. If anyone can help, thanks so much!
Define ImageHolder class which has 2 fields shape and image.
class ImageHolder {
Shape shape;
Image img;
public void paint(Graphics2D g2) {
if (img!=null) {
g2.drawImage(img);
}
else {
g2.fill(shape);
}
}
}
Your grid should be List. On init all the ImageHolders have squares and null images. On click image is assigned to the clicked holder.
In the paintComponent() you just call the holder's paint() method
take a look at this one.
all you need to do is repalce your g2.fill(cell); with g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
read drawimage api here
for (Shape cell : square) {
//g2.fill(cell);
g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
System.out.println(cell.getBounds().x);
}
however use Dimention list or 2D list instead Shape in this case
complete code
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class Test {
Image img = Toolkit.getDefaultToolkit().getImage("img.gif");
public static void main(String[] args) {
new Test();
}
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PixelGrid());
frame.setSize(new Dimension(364, 357));
frame.setVisible(true);
}
public class PixelGrid extends JPanel {
int x=0;
int y=0;
private List<Shape> grid, square;
public PixelGrid() {
grid = new ArrayList<>();
square = new ArrayList<>();
addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
for (Shape shape : grid) {
if (shape.contains(e.getPoint())) {
square.add(shape);
}
}
repaint();
}
}
);
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
grid.add(new Rectangle(col * 25 + 112, row * 25 + 50, 25, 25));
}
}
}
public void paintComponent(Graphics g) {
System.out.println(x);
g.drawLine(112, 50, 237, 50);
g.drawLine(112, 75, 237, 75);
g.drawLine(112, 100, 237, 100);
g.drawLine(112, 125, 237, 125);
g.drawLine(112, 150, 237, 150);
g.drawLine(112, 175, 237, 175);
g.drawLine(112, 50, 112, 175);
g.drawLine(137, 50, 137, 175);
g.drawLine(162, 50, 162, 175);
g.drawLine(187, 50, 187, 175);
g.drawLine(212, 50, 212, 175);
g.drawLine(237, 50, 237, 175);
Graphics2D g2 = (Graphics2D) g;
//g2.drawImage(img,x,y,null);
for (Shape cell : square) {
//g2.fill(cell);
g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
System.out.println(cell.getBounds().x);
}
}
}
}
output>>
I am currently trying to draw a figure by clicking a button. My problems occurs when I click the button and it does not show up in the panel, but I know it's drawing because it runs through the loop.
The drawing will occur when I request the panel to draw it inside the constructor, but not inside the button, inside the constructor
If i put the code in the method "stuff()" inside the constructor it will draw everything just fine.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainFrame{
public static void main(String[]args){
MainFrame f = new MainFrame();
}
public JFrame frame = new JFrame();
public JPanel panel = new JPanel(new BorderLayout());
public MainFrame(){
JButton button1 = new JButton("Shweet Button");
button1.setBounds(185, 10, 130, 20);
frame.setBounds(1680/4,1050/4,500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(panel);
panel.setBackground(Color.black);
frame.setVisible(true);
frame.getContentPane().setLayout(null);
frame.add(button1);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stuff();
}
});
}
public void stuff(){
for(int i = 0;i<1000;i++){
panel.add(new paintComponent());
panel.setBackground(Color.black);
frame.repaint();
try {
Thread.sleep(80);
} catch (InterruptedException e1){e1.printStackTrace();}
}
}
static class paintComponent extends JComponent{
public int options;
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.white);
if(options == 0){
options = 1;
g2.drawOval(50, (JFrame.HEIGHT/2)+100, 50, 50);
g2.drawOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawArc(65, (JFrame.HEIGHT/2)+130, 100, 0, 140, 30);
g2.drawLine(75, (JFrame.HEIGHT/2)+150, 75, (JFrame.HEIGHT/2)+220);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 100, (JFrame.HEIGHT/2)+160);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 65, (JFrame.HEIGHT/2)+210);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 50, (JFrame.HEIGHT/2)+260);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 100, (JFrame.HEIGHT/2)+260);
}else if(options == 1){
options = 0;
g2.drawOval(50, (JFrame.HEIGHT/2)+100, 50, 50);
g2.drawOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawArc(65, (JFrame.HEIGHT/2)+130, 100, 0, 140, 30);
g2.drawLine(75, (JFrame.HEIGHT/2)+150, 75, (JFrame.HEIGHT/2)+220);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 100, (JFrame.HEIGHT/2)+180);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 65, (JFrame.HEIGHT/2)+210);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 50, (JFrame.HEIGHT/2)+260);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 100, (JFrame.HEIGHT/2)+260);
}
}
}
}
You are blocking the Event Dispatching Thread, which is responsible for, amongst other things, processing paint requests.
You should never do anything like this...
for(int i = 0;i<1000;i++){
panel.add(new paintComponent());
panel.setBackground(Color.black);
frame.repaint();
try {
Thread.sleep(80);
} catch (InterruptedException e1){e1.printStackTrace();}
}
Within the EDT. Apart from the fact you are adding multiple new components to your UI every 80 milliseconds, you are also blocking the thread that is responsible for updating your screen...
Check out Concurrency in Swing for more details.
Animation of this type should be handled by a javax.swing.Timer.
Custom painting should be performed in the paintComponent method, as a general rule. You should also be calling super.paintXxx first as a matter of course. There's a lot of working going in the background that needs to be taken care of, especially if the component is transparent.
Check out Performing Custom Painting and Painting in AWT and Swing for more details.
Save your sanity and learn how to use layout managers, they will make your life easier in the long run.
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 javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MainFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MainFrame f = new MainFrame();
}
});
}
public JFrame frame = new JFrame();
public JPanel panel = new JPanel(new BorderLayout());
private WavePane waver;
public MainFrame() {
waver = new WavePane();
JButton button1 = new JButton("Shweet Button");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
panel.setBackground(Color.black);
frame.add(button1, BorderLayout.SOUTH);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stuff();
}
});
panel.add(waver);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void stuff() {
// for (int i = 0; i < 1000; i++) {
// panel.add(new paintComponent());
// panel.setBackground(Color.black);
// frame.repaint();
// try {
// Thread.sleep(80);
// } catch (InterruptedException e1) {
// e1.printStackTrace();
// }
// }
waver.walk(!waver.isWaving());
}
public class WavePane extends JComponent {
private int options;
private Timer timer;
public WavePane() {
setOpaque(false);
timer = new Timer(80, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
options++;
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void walk(boolean walk) {
if (walk) {
timer.start();
} else {
timer.stop();
}
}
public boolean isWaving() {
return timer.isRunning();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
int height = getHeight();
if (options % 2 == 0) {
g2.drawOval(50, 100, 50, 50);
g2.drawOval(60, 110, 8, 8);
g2.fillOval(60, 110, 8, 8);
g2.drawOval(80, 110, 8, 8);
g2.fillOval(80, 110, 8, 8);
g2.drawArc(65, 130, 100, 0, 140, 30);
g2.drawLine(75, 150, 75, 220);
g2.drawLine(75, 180, 100, 160);
g2.drawLine(75, 180, 65, 210);
g2.drawLine(75, 220, 50, 260);
g2.drawLine(75, 220, 100, 260);
} else {
g2.drawOval(50, 100, 50, 50);
g2.drawOval(60, 110, 8, 8);
g2.fillOval(60, 110, 8, 8);
g2.drawOval(80, 110, 8, 8);
g2.fillOval(80, 110, 8, 8);
g2.drawArc(65, 130, 100, 0, 140, 30);
g2.drawLine(75, 150, 75, 220);
g2.drawLine(75, 180, 100, 180);
g2.drawLine(75, 180, 65, 210);
g2.drawLine(75, 220, 50, 260);
g2.drawLine(75, 220, 100, 260);
}
}
}
}
You shouldn't be using JFrame.HEIGHT this actually has nothing to do with the frames height, but is part of the ImageObserver support... or any type of magic number for that matter