Jlabel ImageIcon is drawn in negative coordinates - java

I have this piece of code from my Graphics Engine library:
package WG;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
public class window {
public static boolean running=true;
public static int WIDTH = 800, HEIGHT = 600;
public static String TITLE = "New Window";
public static JFrame frame;
public static int[] pixels;
public static BufferedImage img;
public static Thread thread;
public window(){}
public static void create() {
img = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
frame = new JFrame("WINDOW");
//frame.setResizable(false);
frame.setLayout(new FlowLayout(FlowLayout.LEADING,0,0));
frame.add(new JLabel(new ImageIcon(img)));
frame.pack();
//frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void render() {
BufferStrategy bs=frame.getBufferStrategy();
if(bs==null){
frame.createBufferStrategy(2);
return;
}
Graphics g= bs.getDrawGraphics();
g.drawImage(img, 0,0, WIDTH, HEIGHT, null);
g.dispose();
bs.show();
}
public static void clear_screen(){
for (int i = 0; i < WIDTH * HEIGHT; i++)
pixels[i] =0;
};
}
and this piece of code in my main java file:
import WG.*;
public class Main_window{
private static boolean running = true;
public static window wind = new window();
public static Thread thread;
public static void main(String[] args) {
window.create();
start();
}
public static void start() {
while (running) {
window.clear_screen();
Forms.drawRect(0, 0, 100, 100);//my own method
wind.render();
}
}
}
I have 2 problems here:
1-->The image on the window is displayed on negative coordinates(the rectangle is not 100x100)
If I re-size the window the image is trying to be drawn at 0 0 coordinates but then again is drawn at negative coordinates.
2-->I get 2 different errors:
a)Component must be a valid peer at Graphics g= bs.getDrawGraphics();
b)Buffers have not been created at bs.show();
What are these problems?
I saw on YouTube on this channel he used Canvas and stuff but he is not getting any errors (I know about not mixing the swing with the awt)
EDIT
//from graphics library
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, WIDTH, HEIGHT, null);
g.dispose();
}
//from the main file
public static void start() {
while (running) {
window.clear_screen();
Forms.drawRect(0, 0, 100, 100);//my own method
wind.frame.repaint();
}
}

Your Graphics context, g, is not valid until the host's peer component is extant. The exceptions are thrown because it would cause serious problems for a program to write into host memory or devices at will.
Instead, override paintComponent(), as shown here and here, where you have complete control over the component's geometry in local coordinates.

There's nothing wrong with coordinates. It seems you're using the wrong object. The square is exactly 100x100 if measured from the top of the entire JFrame so negative coordinates are not an issue. Add components to the JFrame's content pane and not to the JFrame itself.
Replace:
frame.add(new JLabel(new ImageIcon(img)));
with
frame.getContentPane().add(new JLabel(new ImageIcon(img)));
There might be something more to it but this is certainly the starting point. Consult the Javadoc in case of further problems

Related

How to display a graphic from another class

I am trying to display a graphic from a separate class on a JPanel of my main class.
The main class is mytest and the separate class is Ball. Ball has a paint component method and simply draws a colored circle. In mytest, I instantiate a ball and add it to a JPanel (dp): dp.add(ball). Very simple, but all I get is the white panel background and no ball is drawn.
Here is the mytest code:
package myStuff;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class mytest {
private JFrame frame=new JFrame();
private JPanel dp = new JPanel();
public static void main(String[] args) {
mytest gui = new mytest();
gui.go();
}
public void go() {
frame.setTitle("Test");
frame.setSize(1000,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel dp=new JPanel();
dp.setBackground(Color.WHITE);
Ball ball = new Ball(dp.getWidth(),dp.getHeight());
dp.add(ball);
frame.add(dp);
frame.setVisible(true);
}
}
and here is the class Ball code:
package myStuff;
import java.awt.*;
import javax.swing.*;
public class Ball extends JComponent{
private int Width;
private int Height;
public Ball (int width, int height ) {
Width=width;
Height=height;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
g2d.setColor(Color.RED);
g2d.fillOval(Width/2,Height/2,40,40);
System.out.println("Doing graphics....");
}
}
An red ball should show up on the dp panel. All I get is the panel background and no ball. I know it is trying since the "Doing graphics" prints out twice.
Here is a working example.
import java.awt.*;
import javax.swing.*;
public class Mytest {
private JFrame frame = new JFrame();
public static void main(String[] args) {
Mytest gui = new Mytest();
SwingUtilities.invokeLater(() -> gui.go());
}
public void go() {
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel dp = new JPanel();
dp.setPreferredSize(new Dimension(500, 500));
dp.setBackground(Color.WHITE);
Ball ball = new Ball(150, 150);
dp.add(ball);
frame.add(dp);
frame.pack(); // invokes layout and sizes components
frame.setLocationRelativeTo(null); // centers on screen
frame.setVisible(true);
}
}
class Ball extends JComponent {
private int width;
private int height;
// A ball should probably only have a "diameter"
public Ball(int width, int height) {
this.width = width;
this.height = height;
setPreferredSize(new Dimension(width, height));
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
g2d.setColor(Color.RED);
// smooths out the graphics
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(0, 0, width, height);
System.out.println("Doing graphics....");
}
}
The two biggest suggestions are to:
Ensure when you change a Swing component you do so on the Event Dispatch Thread.
And use the anti aliasing to make your drawing look smoother (note this is optional and it can add extra processing overhead.)
The reason no red ball was drawn (or only 1/4 of one) was because you changed the location of where to draw it within the Component window. You tried to draw it at width/2 and height/2 which was the center of the Component. It should have been at 0,0 for normal rendering.
Also read about painting in the The Java Tutorials 1
You are setting the size of the frame, but the panel has zero size. You should set the preferred size of the panel, not the size of the frame. Then get the preferred size of the panel to pass to the Ball constructor, and pack the frame before making it visible.
Set the panel size before the line,
Ball ball = new Ball(dp.getWidth(),dp.getHeight());
Then add this code
setPreferredSize(new Dimension(Width, Height));
at the end of the "Ball" Constructor.
See this stack question for more details.

Java Graphics trying to draw rectangle

My goal is to make a class that contains rectangle and then use it and change it in other classes.
I tried to write this code and make an object Rect rect = new Rect(); but when i start the program the rectangle doesn't show up.
I also tried to add it with window.add(rect); but had same problem i'm sure im doing something wrong but i don't really know what.
One more thing that i tried was calling method from other class Rect.drawRect(g); but then it asks for "Argument" and if i add Argument g like i had in method drawRect it says "g cannot be resolved to a variable"
I hope someone can explain and tell me what did i do wrong, also would be great to know how to make rectangle or a circle and later use it in other classes and maybe change its color and size, I only found how to do it in one class.
import javax.swing.JFrame;
public class Main extends Rect{
public static void main(String[] args ) {
JFrame window = new JFrame("test");
window.setSize(1000, 800);
window.setVisible(true);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Rect rect = new Rect();
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Rect extends JPanel{
public void drawRect(Graphics g){
g.setColor(Color.RED);
g.fillRect(100, 100, 200, 200);
}
}
The most important thing is that you need to write some code to do the painting. This is done by overriding the paintComponent method inside your Rect class a bit like this:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(100, 100, 200, 200);
}
Your second issue is that you want to be able to change the colour and size of your rectangle from other classes. For a simple example, this can easily be done by adding some static values inside your Rect class:
public static Color myColor = Color.RED;
public static int myX = 100;
public static int myY = 100;
public static int myWidth = 200;
public static int myHeight = 200;
Now update your paint method to use the static values:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(myColor);
g.fillRect(myX, myY, myWidth, myHeight);
}
Now, whenever or wherever you use the Rect panel it will now show the rectangle according to the static values.
For example, below is a simple and working program, note how it uses the following:
//create Rect
Rect rect = new Rect();
//set the size of the new panel
rect.setPreferredSize(new Dimension(800, 600));
//add the rect to your JFrame
window.add(rect);
//now you can change the color for all Rect instances
//Note how I use Rect instead of rect, however, both will work.
Rect.myColor = Color.BLUE;
//And dont forget to repaint it if you want to see the changes immediatly
rect.repaint();
Full example, main class:
import javax.swing.JFrame;
import java.awt.Color;
public class Main{
//Note how we don't need to extend the Rect class (It just adds confusion)
public static void main(String[] args ) {
JFrame window = new JFrame("test");
window.setSize(1000, 800);
window.setVisible(true);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create Rect
Rect rect = new Rect();
//set the size of the new panel
rect.setPreferredSize(new Dimension(800, 600));
//add the rect to your JFrame
window.add(rect);
//now you can change the color for all Rect instances
//Note how I use Rect instead of rect, however both will work.
Rect.myColor = Color.BLUE;
//And dont forget to update it
rect.repaint();
}
}
And the Rect class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Rect extends JPanel{
public static Color myColor = Color.RED;
public static int myX = 10;
public static int myY = 10;
public static int myWidth = 200;
public static int myHeight = 200;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(myColor);
g.fillRect(myX, myY, myWidth, myHeight);
}
}
Note, if you don't want to call Rect.repaint() every time you make a color/size change then just make a new method that changes each value and include repaint(), for example:
public void changeWidth(int width){
myWidth = width;
repaint();
}
UDP: You need override void paintComponent(Graphics g) instead void drawRect(Graphics g)and call super.paintComponent(g) inside method. Then you can use window.add(rect);.
Thanks #FredK for correction

Transitioning to an abstract class

I am desperately trying to implement some things which I don't think I fully understand. I am attempting to set it up so the commented out actions can be taken (I will need to change syntax but I want to make sure I am on the right track first).
Am I going about this the right way? Where will my drawing actions go if not in the draw method? I get lots of errors when I move it there. Thanks
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics2D;
import java.awt.Graphics;
public class Test extends JPanel{
abstract class graphic {
public Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private int[] location = new int[] {screenSize.width/2,screenSize.height/2};
}
public class gladiator extends graphic {
void draw() {
//g2d.setColor(Color.green);
//g2d.fillArc(location[0], location[1], 100, 100, 45, 90);
//g2d.setColor(Color.black);
//g2d.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// setLocation((location[0]+1),location[1]);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
//this.location[0] = x;
//this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
My original code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test extends JPanel{
private int[] location = new int[2];
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillArc(location[0], location[1], 100, 100, 45, 90);
g.setColor(Color.black);
g.fillArc((location[0]+50-10),(location[1]+50-10), 20, 20, 0, 360);
new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setLocation((location[0]+50),50);
repaint();
System.out.println("repainting");
}
}).start();
}
public void setLocation(int x, int y){
this.location[0] = x;
this.location[1] = y;
}
public static void main(String[] args){
JFrame jf=new JFrame();
jf.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(new Dimension(300,500));
jf.setLocation(100,100);
jf.add(new Test());
jf.pack();
jf.setVisible(true);
}
}
Edit: Should have included this bit, first commenter was right.
The error is cannot find symbol, referring to g2d or g, whichever. I take it to mean that drawing can only happen inside of paint components and that I will have to find a way to include all the instructions for drawing there. I want to make sure I'm just doing something fundamentally wrong, though as this is my first brush with both abstract classes and 2d drawing in java. Also, I know the location[0] etc will not work as is. Lets ignore that.
The bottom code is what I am trying to accomplish (at least at first), but I am trying to use something similar to the top code to create multiple instances of it which can operate independently.
Move the timer out of paintcomponent.
You have declared an abstract class that has a draw method that needs a Graphics2D object to be able to draw, it has no access to it. It also makes little sense to declare a class just to hold two values (screensize and location) if that class also does stuff like drawing.
To fix the issues with 2, you can either let your gladiator extend JComponent, override its paintcomponent and place your draw() code in there and add gladiator to the panel as a component.
You can alternatively do active rendering, which means that you get the Graphic2D object of your canvas (the panel in this case) and take control of the rendering yourself instead of relying on swing.
Since you are working with swing I will give you a working example of what you probably intend to do. If you have more specific questions please do leave a comment.
public class Test extends JPanel {
public static abstract class graphic extends JComponent {
public Dimension dim = new Dimension(500, 500);
private int[] loc = new int[] { 250, 250 };
#Override
#Transient
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public int[] getLoc() {
return loc;
}
public Dimension getDim() {
return dim;
}
}
public static class gladiator extends graphic {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.green);
g2d.fillArc(getLoc()[0], getLoc()[1], 100, 100, 45, 90);
g2d.setColor(Color.black);
g2d.fillArc((getLoc()[0] + 50 - 10), (getLoc()[1] + 50 - 10), 20,
20, 0, 360);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
Test canvas = new Test();
gladiator gladiator = new gladiator();
canvas.add(gladiator);
frame.getContentPane().add(canvas);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
This renders

Window frame covering graphics content

this is my first post here and I have a question that seems really nooby, but this has been troubling me for the past hour or so.
I'm making a simple JFrame with a JPanel in it, but the Windows 7 border frame appears to be blocking my view of parts of the panel. For instance, if I draw a little square at coordinate 0,0, it will not appear and I suspect it's behind the window frame.
I've tried messing around with pack, setsize, setpreferred size, setresizable, and different layouts, but I can't get it to show the top 20 pixels or so!
This is what I have:
public RedSunGame() {
super("Red Sun");
rs = new JPanel(new BorderLayout(), true);
rs.setPreferredSize(new Dimension(WIDTH, HEIGHT));
add(rs, "Center");
setPreferredSize(new Dimension(WIDTH, HEIGHT));
pack();
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
EDIT:
Thanks for all of your replies, sorry for the lack of info :)
I'm using a double buffer strategy I saw in a book. gameRender and paintScreen are in a standard game loop. My RedSunGame class extends JFrame. All the relevant code you could ask for in addition to above:
private static final int WIDTH = 500;
private static final int HEIGHT = 500;
private JPanel rs;
private Graphics2D g2d;
private Image dbImage;
private void gameRender() {
//create buffer
if (dbImage == null){
dbImage = createImage(WIDTH, HEIGHT);
g2d = (Graphics2D)dbImage.getGraphics();
}
//clear screen
g2d.setColor(Color.white);
g2d.fillRect(0, 0, WIDTH, HEIGHT);
g2d.setColor(Color.blue);
g2d.setFont(font);
g2d.drawString("FPS: " + FPS, 0, HEIGHT);
g2d.fillRect(30, 30, 10, 10);
}
private void paintScreen() {
Graphics g;
try {
g = getGraphics();
if ((g != null) && (dbImage != null))
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
catch (Exception e)
{ System.out.println("Graphics context error: " + e); }
}
With my current settings it looks like this.
http://i.imgur.com/qaabC.png
This is what happens if I have g2d.fillRect(30, 30, 10, 10), the only change being the coordinates 30,30 instead of 0,0. It's definitely hiding behind the border up top.
http://i.imgur.com/uzfFe.png
Also, setting it to BorderLayout.CENTER doesn't seem to make a difference in any of these cases.
(sorry it won't let new users post images)
EDIT:
I figured it out. I was drawing directly to the JFrame. #Guillaume Polet I see why you shouldn't override the paint method of JFrames as it draws to the frame and not the panel that should actually display content!! Thanks
Here is a sample code that shows how your goal can be achieved. Try to spot the differences with your code to find what is wrong:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RedSunGame {
private static final int SQUARE_SIZE = 20;
private JPanel rs;
private JFrame frame;
private void initUI() {
frame = new JFrame("Red Sun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
rs = new JPanel(new BorderLayout()) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.YELLOW);
g.fillRect(0, 0, SQUARE_SIZE, SQUARE_SIZE);
}
#Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
// Let's make sure that we have at least our little square size.
preferredSize.width = Math.max(preferredSize.width, SQUARE_SIZE);
preferredSize.height = Math.max(preferredSize.height, SQUARE_SIZE);
return preferredSize;
}
};
frame.add(rs);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
RedSunGame redSunGame = new RedSunGame();
redSunGame.initUI();
}
});
}
}
Verify that WIDTH and HEIGHT are > 0.
Try this:
//add(rs, "center");
add(rs, BorderLayout.CENTER);
you may got your answer but for a newbie to java swing i suggest that you should the Net-beans IDE. it graphically adds and lays out the GUI and you dont need to write any hand-written code. It's a great place to start, as stated here:
http://docs.oracle.com/javase/tutorial/uiswing/learn/index.html

Add image from website to Frame in Java

I'm trying to make a Frame from which I want to add an image from a website.
Do I set the background as an image?
import java.awt.*;
import java.net.*;
class NewFrame extends Frame {
// Constructor.
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Exercise 9.5");
this.setResizable (true);
this.setBackground (Color.cyan);
this.setSize (width, height);
// Show the frame.
this.setVisible (true);
}
// Override paint():
public void paint (Graphics g)
{
}
} // End of class "NewFrame"
public class ex5 {
public static void main (String[] argv)
{
NewFrame nf = new NewFrame (300, 250);
}
}
You can use the following
// load the image once
BufferedImage bi = ImageIO.read(new URL(imageLocAsString));
// now in paint(Graphics g) do
g.drawImage(bi, 0, 0, null);
Look here for more information.

Categories