Excuse me,May I ask java repaint repeatlyed questions,
I meet a trouble that I use drafting repeatedly to express Pacman Open&Close mouth motion.
But this program Only once will not move...
Somebody can help me to solve this problem...
Very thanks so much!:D
My code as below:
package Strive;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
class CDrawF extends JFrame {
CDrawF (){
setTitle("繪製各式圖形"); //JFrame interface
setBounds(50, 50, 490, 260); setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for(int i = 0; i<= 360; i++){ //repeatly 360 times
repaint();
g2.setColor(new Color(1.0f, 0.0f, 1.0f));
g2.fill(new Arc2D.Double(100, 100, 80, 80, 30, 300, Arc2D.PIE));
//PacMan close mouth
repaint();
try{ //Delay setions
Thread.sleep(1000);
}catch(InterruptedException ex){}
g2.fill(new Arc2D.Double(100, 100, 80, 80, 10, 340, Arc2D.PIE));
//PacMan open mouth
repaint();
}
}
}
public class NewClass { //Main
public static void main(String[] args){
new CDrawF ();
}
}
Suggestions:
Don't draw directly in the JFrame
Don't draw in the paint(...) method.
Never call Thread.sleep(...) on the Swing event thread
And especially don't call it in a paint(...) or paintComponent(...) method.
Instead draw in a JPanel or JComponent's paintComponent(...) method
Read the Java graphics tutorials as they will explain all of this.
Don't call repaint() inside of paint(...) or paintComponent(...)
Use a Swing Timer for your animation loop. Again the tutorials will help you do this.
Related
Why doesn't JPanel (panel) get drawn on the green background (the jpanel)? I want to be able to do this without extending j panel to...
Furthermore, for java games should i use keybindings or keylistener in java.
import javax.swing.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Game {
JFrame window;
JPanel panel;
int charPosX = 0;
int charPosY = 0;
public Boolean createGui() {
window = new JFrame("Game");
window.setSize(1000,500);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
panel = new JPanel();
panel.setVisible(true);
panel.setLayout(null);;
panel.setBackground(new Color(65,130,92));
window.add(panel);
return true; //returns true if ran and will be ran by check status in Main.
}
public void paintComponent(Graphics g) {
panel.paintComponents(g);
g.setColor(Color.RED);
g.drawRect(100,10,30,40);
g.fillRect(10, 10, 20, 10);
}
}
Let's take your code for a second and add #Override to your paintComponent method...
public class Game {
//...
#Override
public void paintComponent(Graphics g) {
panel.paintComponents(g);
g.setColor(Color.RED);
g.drawRect(100, 10, 30, 40);
g.fillRect(10, 10, 20, 10);
}
}
And now we have a compiler error! This is because Game extends Object and does not have a paintComponent method. This means that there is no way that the method could be called by any part of the existing painting system, so, it never gets called.
Components make poor "game" entities, they have a lot of "plumbing" which doesn't make them very efficient for this kind of work, you're generally better off heading down a complete custom painting route
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Game {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game().createGui();
}
});
}
JFrame window;
GamePanel panel;
int charPosX = 0;
int charPosY = 0;
public Boolean createGui() {
window = new JFrame("Game");
window.setSize(1000, 500);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new GamePanel();
panel.setBackground(new Color(65, 130, 92));
window.add(panel);
window.setVisible(true);
return true; //returns true if ran and will be ran by check status in Main.
}
public class GamePanel extends JPanel {
private Rectangle entity = new Rectangle(100, 10, 30, 40);
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.draw(entity);
g2d.setColor(Color.BLUE);
g2d.fill(entity);
g2d.dispose();
}
}
}
Also note, I called window.setVisible(true); only after I had added the panel to the window, this is because Swing is lazy when it comes to adding/removing components. If you want to add/remove components after the UI has been realized on the screen, you'll need to call revalidate and repaint on the container to trigger a layout and paint pass
Also, beware, there is a difference between paintComponent and paintComponents ;)
I would highly recommend having a look at Painting in AWT Swing and Performing Custom Painting to gain a better understanding of how painting works in Swing and how you can take advantage of it
What I Want To Do: Animate the rectangles so that they go from the right of the screen to the left side of the screen. Here's the code for painting:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class graphics extends JPanel{
public static Timer a;
public static int animation = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(new Color(40,40,40));
g.setColor(new Color(197,255,172));
g.fillRect(animation, 0, 800, 35);
g.setColor(new Color(141,229,123));
g.fillRect(animation, 35, 800, 35);
g.setColor(new Color(112,183,98));
g.fillRect(animation, 70, 800, 35);
g.setColor(new Color(84,137,73));
g.fillRect(animation, 105, 800, 35);
g.setColor(new Color(42,68,36));
g.fillRect(animation, 140, 800, 35);
g.setFont(new Font("Dekar Light", Font.PLAIN, 30));
g.setColor(Color.WHITE);
g.drawString("Graphics Test", 326, 300);
a = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
repaint();
int velx = 5;
animation = animation - velx;
System.out.println(animation);
}
});
a.start();
}
}
And here is the frame:
My Problem: As you can see, it seems that the rectangles move double the distance than what they last moved.
My Question: What am I doing wrong? I need to know if it's something with either the timer or the equation I'm using.
I need to know if it's something with either the timer
A painting method should only ever do painting!
It should NOT start the Timer. Every time you paint the component you start another Timer so you end up generating multiple repaint() requests. The RepaintManager will then combine multiple requests into a single repaint of the component.
The Timer should be started in the constructor of the class or you should create a startAnimation() method method and add it to your panel. Then that method can be invoked after the frame is made visible (or as required).
Also, class names should ALWAYS start with an upper case character. However you should NOT use "Graphics" since there is already a Java class with that name. Make your class name more descriptive.
I am trying to add a border to a Rectangle element and for some reason it will not work, is it not compatible with JFrame? I can set my entire JFrame to having a border, but it can't find setBorder with my rectangles. Here is my code:
package trivia;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class Main extends JFrame{
boolean mainMenu = true;
static Color tan = Color.decode("#F4EBC3");
static Color darkGreen = Color.decode("#668284");
static Color buttonColor = Color.decode("#A2896B");
Rectangle header = new Rectangle(0, 0, 500, 100);
Rectangle body = new Rectangle(0, 100, 500, 400);
Rectangle start = new Rectangle(150, 150, 200, 40);
public Main() {
setTitle("Trivia Game!");
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
#Override
public void paint(Graphics g) {
Dimension d = this.getSize();
Border blackline;
blackline = BorderFactory.createLineBorder(Color.black);
if(mainMenu = true){
g.setColor(darkGreen);
g.fillRect(header.x, header.y, header.width, header.height);
g.setFont(new Font("Courier", Font.BOLD, 24));
g.setColor(Color.BLACK);
drawCenteredString("Trivia Game!", d.width, 125, g);
g.setColor(tan);
g.fillRect(body.x, body.y, body.width, body.height);
g.setColor(buttonColor);
g.fillRect(start.x, start.y, start.width, start.height);
}
}
public void drawCenteredString(String s, int w, int h, Graphics g) {
FontMetrics fm = g.getFontMetrics();
int x = (w - fm.stringWidth(s)) / 2;
int y = (fm.getAscent() + (h- (fm.getAscent() + fm.getDescent())) / 2);
g.drawString(s, x, y);
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Main m = new Main();
}
}
And when I add this in my paint function:
start.setBorder(blackline);
It gives me the error:
The method setBorder(Border) is undefined for the type Rectangle
I am not sure how I can make it recognize the setBorder function, can anyone help? All help is much appreciated!
Rectangle does not have a setBorder method, instead, set the color of the Graphics context using Graphics#setColor(Color) and either use Graphics#drawRect(int, int, int, int) or Graphics2D#draw(Shape)
You're breaking the paint chain. Painting is made up of a series of chained method calls, which when called correctly, paint the current component and its child components. By not calling super.paint you're preventing from doing this and could cause any number of nasty side effects, none of which you really want...
You should avoid overriding paint of top level containers, like JFrame, for a number of reasons; they're not double buffered; there a bunch of other components sitting on top of the frame which may paint over it; etc. Instead, create a custom component, extending from something like JPanel and override it's paintComponent method instead (ensuring that you call super.paintComponent first)...
See Painting in AWT and Swing,
Performing Custom Painting and 2D Graphics for more details
Sounds like you're trying to draw the rectangle referenced by start. In that case, you want to be invoking a method on a Graphics, not on a Rectangle. So:
g.drawRect(start.x, start.y, start.width, start.height);
So ive been doing a bit of java recently and i have run into a bit of a problem. I have been playing around with 2d drawing and added an image to the project.
The problem is that when the window gets resized, it redraws and duplicates the image. I have made a little workaround, but its not ideal... So why does the image duplicate?
Before:
http://i.imgur.com/PmHRZBQ.png
(window is resized)
After:
http://i.imgur.com/bhsvVZz.png
Code
main.java
import javax.swing.JFrame;
public class main
{
public static void main(String [] args) throws InterruptedException
{
JFrame f = new JFrame("Title");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas testing = new Canvas();
f.add(testing);
f.setSize(800, 600);
f.setVisible(true);
}
}
canvas.java
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Canvas extends JPanel
{
public void paintComponent (Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.WHITE);
g.setColor(Color.BLACK);
g.fillRect(25, 25, 100, 30);
g.setColor(new Color(190,81,215));
g.fillRect(25, 68, 10, 10);
g.setColor(Color.RED);
g.drawString("Matt is da best", 100, 10);
try
{
BufferedImage image = ImageIO.read(new File("C:/face.png"));
JLabel picLabel = new JLabel(new ImageIcon(image));
System.out.println("Added pic");
add(picLabel);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Don't load the image in the paintComponent(Graphics) method! It could be declared as a class attribute and loaded in the constructor.
Don't add components in the paintComponent method either! It will trigger a repaint.
This should work more reliably..
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class main
{
public static void main(String [] args) throws InterruptedException
{
JFrame f = new JFrame("Title");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas testing = new Canvas();
f.add(testing);
f.setSize(800, 600);
f.setVisible(true);
}
}
class Canvas extends JPanel
{
BufferedImage image;
Canvas() {
image = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB);
JLabel picLabel = new JLabel(new ImageIcon(image));
System.out.println("Added pic");
add(picLabel);
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.WHITE);
g.setColor(Color.BLACK);
g.fillRect(25, 25, 100, 30);
g.setColor(new Color(190,81,215));
g.fillRect(25, 68, 10, 10);
g.setColor(Color.RED);
g.drawString("Matt is da best", 100, 10);
}
}
Other tips
Have the Canvas return a preferred size and pack() the frame rather than set a size to it.
Start and update a Swing GUI on the EDT.
Don't give your custom class the same name as a J2SE class. That can get confusing. Maybe call it JCanvas.
Take a look at your paintComponent method...
Each time paintComponent is called, you are creating a new JLabel and adding it back to the panel...
try
{
BufferedImage image = ImageIO.read(new File("C:/face.png"));
JLabel picLabel = new JLabel(new ImageIcon(image));
System.out.println("Added pic");
add(picLabel);
}
catch (IOException e)
{
e.printStackTrace();
}
This in turn will produce another repaint request and the sync will begin all over again.
NEVER modify the state of any component from within any paint method. This will simple...blow up in your face...
You should load your image and add the label within the constructor or some other method (that paintXxx doesn't call)
The important thing to remember about painting in Swing is, you don't control it. The repaint engine may update your component at any time, with or without your interaction, based on it's own needs. You can encourage a paint by calling repaint, but there is no guarantee of when or what will be repainted.
import javax.swing.*; // For JPanel, etc.
import java.awt.*; // For Graphics, etc.
import java.awt.geom.*; // For Ellipse2D, etc.
import java.awt.event.*;
public class ShapeExample extends JPanel {
private Rectangle2D.Double square =
new Rectangle2D.Double(50, 50, 100, 100);
private Rectangle2D.Double square1 =
new Rectangle2D.Double(10, 10, 200, 200);
private Ellipse2D.Double circle =
new Ellipse2D.Double(50, 50, 100, 100);
public void paintComponent(Graphics g) {
clear(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(Color.red);
//g2d.fill(square);
g2d.draw(square);
g2d.draw(square1);
g2d.fill(square1);
}
}
// super.paintComponent clears offscreen pixmap,
// since we're using double buffering by default.
protected void clear(Graphics g) {
super.paintComponent(g);
}
protected Rectangle2D.Double getsquare() {
return(square);
}
public static void main(String[] args) {
WindowUtilities.openInJFrame(new ShapeExample(), 100, 100);
}
}
Get rid of the WindowUtilites class and build your frame manually so you understand what is going on. Then you add a panel containing your sliders to the top/bottome of the frame. Add your painting panel to the center. Start by reading the Swing tutorial on How to Use Sliders for working examples of creating a basic GUI with sliders. You can then post your SSCCE if you have problems.