I am fairly new to java programming and I am trying to make a simple game however, I need to render my image I have made here is the code I put in eclipse:
public class MainMenu extends JFrame{
public static void main(String[] args){
new MainMenu();
}
public MainMenu(){
this.setSize(300, 450);
this.setLocationRelativeTo(null);
this.setResizable(true);
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
int xPos = (dim.width / 2) - (this.getWidth() / 2);
int yPos = (dim.height / 2) - (this.getHeight() / 2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(xPos, yPos);
this.setTitle("Frame For Flamedash Testing");
this.setVisible(true);
}
public void paint(Graphics g){
Image img1 = Toolkit.getDefaultToolkit().getImage("mainmenuscreen.png");
g.drawImage(img1, 20, 20, null);
} // public void paint(Graphics g)
public void putit() {
boolean MainMenu = true;
while (MainMenu == true){
repaint();
}
}
}
When I put that it is all fine and it does not give me any errors what so ever then I run it and it shows the frame but shows no picture than I full screen it because I set re-sizable true and it shows the default color in one spot with the size I set the frame too and another one identical but on the corner and black everywhere else. Any help to rendering this .png image will help, thank you in advance.
Don't override paint() in a JFrame.
The easiest way to display an image is to use a JLabel with an Icon.
Read the section from the Swing tutorial on How to Use Icons for more information and examples. The tutorial will show you how to better structure your code.
The tutorial also has a section on Custom Painting, if you really want to paint the image yourself. Custom painting is done by overriding the paintComponent() of a JPanel and then you add the panel to the frame.
First of all, in your paint method you should always call super.paint, else you break the paint chaining.
As for your issue,
You can call the repaint to force the painting. Keep a variable to hold the instance in your main and call repaint :
public MainMenu() {
...
repaint();
}
Note that loading an image from the paint method is a really bad idea as it will be loaded each time the frame is painted.
You've got several problems in that code including:
Drawing directly within the JFrame, something that can have unpleasant side effects
Trying to read in an image from within a painting method.
Your actual problem is often due to specifying the wrong path to the image, and to solve this you need to identify the actual user's directory that Java is looking at as the base of the path. This can be found by calling
System.out.println(System.getProperty("user.dir"));
Related
This question already has answers here:
Repaint without clearing
(2 answers)
Closed 3 years ago.
I am implementing a simple Canvas where items can be drawn like a person would in real life with a paper and a pencil, without clearing the entire page every time an object is drawn.
What I have so far...
A Canvas to implement the drawing:
public class Canvas extends JPanel {
private final Random random = new Random();
public Canvas() {
setOpaque(false); // I thought setting this flag makes the drawn pixels be preserved...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(random.nextInt(getWidth()), random.nextInt(getHeight()), 5, 5);
}
}
The Window as an actual window:
public class Window extends JFrame {
public Window(Canvas canvas) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(canvas);
pack();
setVisible(true);
}
}
And the Controller with an entry-point to the application. Also starts a timer so the repaint on Canvas is called every second to force drawing another circle.
public class Controller {
public static void main(String[] args) {
Canvas canvas = new Canvas();
SwingUtilities.invokeLater(() -> new Window(canvas));
new Timer(1000, e -> canvas.repaint()).start();
}
}
The problem is that whenever a new circle is drawn, the previous one is cleared. Seems like there is still some process filling the JPanel or maybe the entire JFrame with white color.
Painting in Swing is destructive. It is an expected requirement that each time a component is painted, it is painted from scratch, again.
You need to define a model which maintains the information needed in order to restore the state from scratch.
Your paint routines would then iterate this model and draw the elements each time.
This has the benefit of allowing you to modify the model, removing or inserting elements, which would allow you to update what is been painted simply.
Alternatively, you could use a "buffer" (ie a BufferedImage) on to which all you painting is done, you would then simply paint the image to the component each time the component is painted.
This, however, means that you can't undo or layer the paintings, it's drawn directly to the image. It also makes resizing the drawing image area more difficult, as you need to make these updates manually, where as the "model" based implementation is far more adaptable
Consider calling the alternate constructor of repaint(...)
repaint(long tm, int x, int y, int width, int height)
This allows you to set a specified area to be repainted.
Also you can just store what you drew in a list and then reprint the drawing to the canvas after repaint is called.
I have a little issue with my GUI in NetBeans. I draw images (dots) when a user clics in a JPanel at the mouse clic location. This part works just fine. I store each image locations in two different ArrayList that contains the X location and Y location. Now what I want to do is to delete the latest image drawn in the Panel after a button is clicked. So what I did is remove the last index of both ArrayList, and then call repaint() to draw all the images from the locations in both X and Y ArrayList (code below).
What is weird is that I need to resize the GUI (put it in full screen or just change its' size) in order for the drawn images to show up again in the JPanel otherwise, the panel remains empty.
Here's the parts of code that are affected :
public void paint(Graphics g) {
super.paint(g);
for(int i=0;i<=listePointsX.size()-1;i++) {
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/myimage.png"));
Graphics graphe = jPanel1.getGraphics();
graphe.setColor(Color.BLACK);
graphe.drawImage(icon, this.listePointsX.get(i),this.listePointsY.get(i), rootPane);
}catch(Exception e1){
}
}
private void jButtonUndoActionPerformed(java.awt.event.ActionEvent evt) {
if(listePointsX.size()>0){
int lastObject= listePointsX.size();
listePointsX.remove(lastObject-1);
listePointsY.remove(lastObject-1);
jPanel1.repaint();
}
else{
}
}
Any idea what I need to do to some kind of "refresh" the whole thing? Am I doing something wrong? Tried searching about that but did not find anyting...
Graphics graphe = jPanel1.getGraphics(); is NOT how painting should work, instead, you should have overriden the panel's paintComponent method and painted the points within in.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
Instead, your panel should be doing ALL the work, managing the points in the ArrayList and painting them. You parent component "might" have the ability to add or remove points if that meets your design requirements, but the core responsibility remains with the panel.
Avoid performing any long running or block operations within the paint methods, they should run as fast as possible. Since the image never changes, you should simply load once (either when the class is constructed or when you first need the image) and keep using the same reference.
Alright it worked just fine now. I had to do it the way you told me up here. I created a new class that extends jPanel (below). Then in my main Form, had to create an object of this class. Whenever a user makes a click, it will call this Drawing class object and add an item to the ArrayList (this object manages everything regarding created points... It looks like this :
public class MyDrawingClass extends JPanel {
ArrayList<Integer> arrayListPointX = new ArrayList<>();
ArrayList<Integer> arrayListPointY = new ArrayList<>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/images/dot.png"));
g.setColor(Color.BLACK);
if(arrayListPointX.size()<=0){
...
}
else{
for(int i=0;i<listePointsX.size();i++){
g.setColor(Color.BLACK);
g.drawImage(icon, listePointsX.get(i), listePointsY.get(i), rootPane);
}
}
}catch(Exception e){
...
}
}
So if I want to "undo", let's say my object of "MyDrawingClass" is called "draw". I can do : draw.arrayListPointX.remove(draw.arrayListPointX.size()-1); and call repaint(); to display remaining points.
Thanks for your tips appreciate it ! :)
I'm attempting to code a simple animation or physics example in a Java Swing application. I have the actual windows application open and working, but I can't figure out how to actually draw my shapes, and how I'd format the code for calculations between frames, that sort of stuff.
I've read some stuff about over riding a paint method, but I don't know what that means, and I don't believe I'm using it in the code I'm using right now. This is my code:
public class Physics extends JFrame{
public Physics() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setLayout(null);
final JLabel label = new JLabel("Hi, press the button to do something");
label.setBounds(20, 0, 2000, 60);
final JButton submitButton = new JButton("Start");
submitButton.setBounds(20, 150, 80, 20);
submitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Put button code here later
}
});
panel.add(label);
panel.add(submitButton);
setTitle("Program");
setSize(300, 250);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Physics ex = new Physics();
ex.setVisible(true);
}
});
}
}
So I have some blank space above my button where I'd like to draw maybe a square or circle moving across the screen to start off with, once I get that down I can start getting into the more advanced stuff. Any hints on how to do that would be appriciated :D
Thanks!
"I've read some stuff about over riding a paint method, but I don't know what that means"
So you've overridden actionPerformed, so you know what an #Override is. As you'll notice from the ActionListener, you never actually explicitly call actionPerformed, but whatever you put in the there, still get's used. That's because the ActionListener implicitly call it for you.
The same is true with painting. In the Swing painting process, there is a paint chain that Swing uses to paint components. Along the way paint is called somewhere. So just like actionPerformed, you can override paint and it will get implicitly called for you.
#Override
public void paint(Graphics g) {
super.paint(g);
}
The Graphics object passed to the method is the graphics context that Swing will use for the painting. You can look at the Graphics API to see the methods you can use. You can use drawOval to draw a circle
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawOval(x, y, width, height);
}
Now here's the thing. You don't actually want to override paint. In the tutorials linked above, some of the examples will use applets and override paint, but you shouldn'y paint on top level containers like JFrame or JApplet. Instead paint on a JPanel or JComponent and just add it the JFrame. When you do paint on JPanel or JComponent, you'll instead override paintComponent (which also gets called along the paint chain), instead of paint
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, width, height);
}
You see how I used variables for the drawOval method. The x is the x location from the top-let of the screen, and y and the y point. width and height are width and height of the circle. The great thing about using variables is that their values can be changed at runtime.
That's where the animation comes to play. As pointed out, you an use a javax.swing.Timer
The basic construct is
public Timer(int delay, ActionListener listener) {
}
The delay is the milliseconds to delay each call to the listener. The listener will have your actionPerformed call back that will do what's inside, every delay milliseconds. So what you can do, is just change the x from the drawOval and repaint(), and it will animate. Something like
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
x += 5;
repaint();
}
});
timer.start();
The timer code you can just put in the constructor. That's probably simplest explanation I can give. Hope it helps.
Don't forget the to see Custom Painting and Grapics2D for more advance topics on graphics. Also see some example of timers and animation here and here and here and here and here
Also avoid using null layouts. See Laying out Components Within a Container to learn how to use layout managers, as should be done with Swing apps.
Take a look at the Swing tutorial on Custom Painting.
The example shows you how to do painting. If you want animation, then you would use a Swing Timer to schedule the animation. The tutorial also has a section on How to use a Swing Timer.
Put the two tutorial together and you have a solution.
There are any number of ways to achieve this.
Start by taking a look at:
Performing Custom Painting
2D Graphics
For details about how painting in Swing is done.
Animation is not as simple as just pausing a small period of time and then repainting, theres acceleration and deceleration and other concepts that need to be considered.
While you could write your own, that's not a small task, a better solution might be to use a pre-existing engine, for example...
Then take a look at:
Timing Framework
Trident
java-universal-tween-engine
Which are all examples of animation engines in Swing. While I prefer the Timing Framework as it provides me with a lower level API, this is a personal opinion. Both Trident and the JUWE seem to be geared more towards component/property based animation (which the Timing Framework can do if you want to build some of the feature sets up)
I created a simple animation with two rockets blasting off. The full eclipse project is here: https://github.com/CoachEd/JavaExamples/tree/master/RaceToSpace. Here's a screenshot:
I am trying to call the paint() method from another class, but it just doesn't work.
Here is the code:
Main.java:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private int WIDTH = 600;
private int HEIGHT = 400;
private String NAME = "Dark Ages";
private String VERSION = "0.0.1 Pre-Alpha";
static boolean running = false;
private Image dbImage;
private Graphics dbg;
public Main() {
//Initialize window
JFrame frame = new JFrame();
frame.setTitle(NAME + " - " + VERSION);
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//Running
running = true;
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
// Draw Images
repaint();
}
public static void main(String args[]) {
new Main();
Player player = new Player();
}
}
Player.java:
public class Player {
public void paint(Graphics g) {
g.drawRect(100, 100, 100, 100);
}
}
How do I call the paint() method from another class in java?
In brief, you don't. And in fact, you shouldn't call it directly from the same class either. Instead you should change the state of the class (change its fields), and then call repaint() on it, which will suggest to the JVM that the component should be painted.
Other issues and suggestions:
An obvious issue I see immediately in your code is that your class has a Graphics field, something that is dangerous to do. I suggest that you get rid of that field so that you're not tempted to use it.
Do not draw directly within a JFrame, JDialog or other top-level window. These windows have too many roles to play behind the scenes that you don't really want to mess with how they render themselves or their children (unless you really know what you're doing and have definite need).
Better to draw in the paintComponent(...) method override of a JPanel or other JComponents.
In your paintComponent(...) override, don't forget to call the super's method: super.paintComponent(g);. This will allow Swing to do housekeeping drawing, such as erasing old out of date or deleted images, before you do your drawing.
Run, don't walk to your nearest Swing painting tutorial.
Your current Player class extends no Swing component and is added to no top level window, so its code will do nothing useful. Again, read the tutorials.
Never call repaint() from within paint(...) or paintComponent(...).
Please post modified code if possible.: please don't ask us to create code for you as that's your job. Please understand that the more code you create, the better a coder you'll be, and because of this, most of us don't feel that we should cheat you out of the opportunity to create your own code.
Useful Java Tutorials:
The Really Big Index: The main tutorial where you should start.
Using Swing Components: How to create Swing GUI's
Lesson: Performing Custom Painting: Introductory tutorial to Swing graphics
Painting in AWT and Swing: Advanced tutorial on Swing graphics
I have a jFrame with a Canvas on it. When I run my program in Windows XP/Vista and resize the window the canvas resizes proportionately along with the window.
However, in Ubuntu linux, when I compile the same java application and resize my window, the Canvas stays the same size.
What do I need to do to make my Canvas resize with my window in both Windows and Linux? What is the deal with the discrepancy?
Main.java
public class Main {
public static void main(String[] args)
{
JFrame frame = new JFrame("BallBounce");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
BallCanvas ballCanvas = new BallCanvas();
frame.getContentPane().add(ballCanvas);
frame.getContentPane().add(controlPanel);
frame.pack();
frame.setVisible(true);
}
}
BallCanvas.java
public class BallCavnas extends Canvas {
public BallCanvas()
{
setPreferredSize(new Dimension(640, 400));
setIgnoreRepaint(true);
... various gui controls are wired up here
}
... rest of canvas code
}
Edit: My source code is zipped up here incase someone wants to take a look:
http://www.filedropper.com/ballbounce
I've done the suggestions made by Dave Ray, and it still isn't resizing the Canvas? Remember, it resizes for me fine when I compile this java program and run it in windows. Only in linux does it does this to me. I'm also running Java 6 Sun 1.6.0.10 JVM, if it matters.
alt text http://img158.imageshack.us/img158/7642/screenshotww0.png
Perhaps my canvas is resizing by my BufferStrategy/Graphics aren't resizing ?
Edit 2: From the screenshot, it is definitely set to CENTER:
frame.getContentPane().add(ballCanvas, BorderLayout.CENTER);
frame.getContentPane().add(controlPanel, BorderLayout.SOUTH);
Resolved
Apparently the "Canvas" was getting resized but I was doing something weird with it's buffer strategy that wasn't allowing IT to be resized. I fixed it. Thanks everyone!
Perhaps, the layout manager is just attempting to honor your preferred size.
I would:
A) remove the preferred just to see what happens ( not a very good idea anyway )
or
B) not use canvas in first place but JComponent. After all Canvas is AWT component, and I not pretty sure how they work as today anyway. JComponent is a light weight component and since you're using a JComponent as container they would... mmhhh work better together?
Gee.. I'm giving voodoo programming suggestions now. Better get to work.
C) What have always worked for me. Make an small proof of concept, by adding step by step the stuff in my code. Start with empty canvas, then add the preffered size, then etc. etc. Chances are, the bug is on the paint method :P
Good luck.
:)
Use a border layout instead:
frame.getContentPane().setLayout(new BorderLayout());
BallCanvas ballCanvas = new BallCanvas();
frame.getContentPane().add(ballCanvas, BorderLayout.CENTER);
frame.getContentPane().add(controlPanel, BorderLayout.SOUTH);
Also get rid of setPreferredSize() in favor of frame.setSize() to set the initial size of the display.
Another good solution is put the canvas into an JPanel,
like i did
panel.add(new JPanel() {
#Override
public void paint(Graphics g) {
// do not paint
}
}.add(capture));
and in the canvas function something like
#Override
public void paint(Graphics g) {
Dimension currentSize = getParent().getSize();
int width = currentSize.width;
int height = currentSize.height;
if (offscreenImage == null || !currentSize.equals(offscreenDimension)) {
// call the 'java.awt.Component.createImage(...)' method to get an
// image
offscreenImage = createImage(width, height);
offscreenGraphics = offscreenImage.getGraphics();
offscreenDimension = currentSize;
}
if (image != null) {
offscreenGraphics.drawImage(image, 0, 0, width, height, null);
} else {
offscreenGraphics.setColor(Color.BLACK);
offscreenGraphics.fillRect(0, 0, width, height);
}
//scratch image
g.drawImage(offscreenImage, 0, 0, this);
}
for example. This make it very simple. Take the parent Panel to fit to your needs.
If you followed Dave's advice, esp. putting the ballCanvas in the CENTER, then you must be setting a maximum size for ballCanvas.