why isn't an oval displayed in my jPanel? [duplicate] - java

This question already has answers here:
Can not draw oval on a JPanel
(2 answers)
Closed 2 years ago.
I'm trying to add a circle to my JPanel, but it won't draw the cricle.
the code below creates a JFrame, creates a JPanle and calls a function to add a circle to the JPanel(pgame), but it doesn't actually add it.
Help appreciated
fgame = new JFrame("Backgammon");
fgame.setSize(1000, 1000);
pgame = new JPanel();
pgame.setPreferredSize(new Dimension(1000, 687));
pgame.setLayout(new GridLayout(3, 10));
pgame.setBorder(BorderFactory.createEmptyBorder(309,460,150,460));
Circle Circlepanel = new Circle();
pgame.add(Circlepanel);
Circlepanel.setVisible(true);
fgame.add(pgame,BorderLayout.CENTER);
fgame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fgame.setTitle("Backgammon");
fgame.pack();
fgame.setVisible(true);
public class Circle extends JPanel {
public void paint(Graphics g) {
g.drawOval(500, 500, 100, 100);
g.setColor(Color.RED);
g.fillOval(500, 500, 100, 100);
}
}

First of all variable names should NOT start with an upper case character. Most of you names are correct, but not all. Learn Java conventions and be consistent!
Your create a GridLayout
pgame.setLayout(new GridLayout(3, 10));
Which will attempt to allocate space for 3 components vertically in the frame.
Then you create a Border:
pgame.setBorder(BorderFactory.createEmptyBorder(309,460,150,460));
which will give your component a height of 459 and a width of 920.
Finally you try to draw the oval at (500, 500) from the top left of the panel.
g.drawOval(500, 500, 100, 100);
Well, the problem is that you have weird random numbers and the size of your component isn't large enough to paint the oval in the space of the component.
To demonstrate this add and retest:
Circlepanel.setBackground( Color.YELLOW );
You will see a yellow panel. Next change:
//pgame.setLayout(new GridLayout(3, 10));
pgame.setLayout(new GridLayout(1, 0));
and you will see a taller yellow panel in the middle of the frame because you are only allocating space for a single component.
Next change:
//pgame.setBorder(BorderFactory.createEmptyBorder(309,460,150,460));
pgame.setBorder(BorderFactory.createEmptyBorder(50,50,50,50));
and you will see part of the oval because you have reserved less space for the border.
Next change:
//g.fillOval(500, 500, 100, 100);
g.fillOval(0, 0, 100, 100);
and you will see the oval at the top of the panel.
The point is that specifying the:
grid size
border size
oval location
all affect the size of the component and how it is painted.
Other issues:
override the getPreferredSize() method of your Circle class to return the desired size of the panel
custom painting is done by overriding paintComponent(), not paint();
you need to invoke super.paintComponent(..) at the start of the method.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.

Related

Does JFrame not accurately display specified width and height values?

I'm building a simple 2D game in Java.
I'm using the JFrame class, but I don't think the width and height are what I specified, or perhaps the graphics are incorrect.
Here are some snippets of my code:
public final static int WIDTH = 600, HEIGHT = 900;
JFrame frame = new JFrame();
frame.setSize(WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT - 10);
The JFrame is displaying a black background. However, based on the arguments I gave to the fillRect function, there should still be a 10px tall sliver of white at the bottom of the frame. This is not the case. The white sliver only really starts to show after a 30px decrease from the height of the frame.
Thanks for your help.
The JFrame size includes the borders so you need to allow for them. To facilitate dealing with this don't specify the width and height of the JFrame. I recommend doing the following.
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(width,height));
frame.add(panel);
// add other components in the panel
frame.pack();
// center on screen.
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Now your panel will be the specified size.
Note, if your going to paint, make certain you override paintComponent(Graphics g) in JPanel and do your painting there.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// your code here
}

How to ignore JFrame opacity?

I need to achieve the effect of "lights off" while displaying animation. It's currently been done with transparent Jframe, black background with 50% opacity the size of the monitor. then, there is this canvas component which should draw RGBA buffered-image.
Problems pops up when the the JFrame opacity effects the Canvas as well, making it semi transparent. That's what i'm trying to avoid.
//** Window class extends Canvas
public Window(){
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int hostMonitorWidth = gd.getDisplayMode().getWidth();
int hostMonitorHeight = gd.getDisplayMode().getHeight();
Dimension dimension = new Dimension(hostMonitorWidth, hostMonitorHeight);
super.setPreferredSize(dimension);
window = new JFrame();
window.setUndecorated(true);
window.setOpacity(0.55f);
window.setLayout(new GridLayout());
window.setSize(hostMonitorWidth, hostMonitorHeight);
window.add(this);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setVisible(true);
window.requestFocus();
window.setFocusableWindowState(true);
super.createBufferStrategy(3);
}
public void draw(){
BufferStrategy buffer = super.getBufferStrategy();
java.awt.Graphics g = buffer.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0, super.getWidth(), super.getHeight());
g.drawImage(batch.getImage(), 0, 0, super.getWidth(), super.getHeight(), null);
g.dispose();
buffer.show();
}
I have tried couple combinations of the following code with Jpanel, Layered Panes, Jlabel and what not. It's always seems to keep the opacity / throwing unexplainable exceptions / not working for any reason.
Am i doing it the correct way? what am i missing here?
Don't use setOpacity, use setBackground on the JFrame and pass it a alpha based color. This will allow the frame to become transparent without affecting the other components.
You may, however, find that Canvas doesn't like alpha based colors (as it only has an opaque state)

Adding some pictures to a BuffredImage then Save it

My general idea is to make a Sprite-Sheet-Maker I mean the program will:
Collect more than one picture like "1.bmp" , "2.png" and "3.jpg"
Create new BuffredImage variable and draw on it the 3 pictures (and draw the BuffredImage on a JPanel on the same time)
Save the final picture "Final.png"
I'm thinking to make the First step and the Second one in one loop because i have a JList with the paths of all the pictures.
and to do that I used Java window Builder on eclipse, I made my form and I tried to test a simple code on the Panel.
Panel panel = new Panel(); //Work
panel.setBackground(Color.BLUE); //Work
BufferedImage img = new BufferedImage(5,5,5); //Work
Graphics g = null ; //Work
panel.paintComponents(g); //work
g.setColor(Color.BLACK); //ERROR---------------------ERROR
g.fillRect(0, 0, 50, 50);
The problem it's not only in that code but in all the idea so please any of your ideas could help me even a part of solution for a part of my project , so please comment with any idea you've got.
g.setColor(Color.BLACK);//error
Since
Graphics g = null ;//null value, you are not create any obeject
Upon null value we can't perform any operation.
You have to override paintComponent method in JPanel class then you will receive Graphics object.
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
};
frame.add(panel);//added to frame.
See this link
Create a JPanel using a GridLayout.
Create 3 JLabel each containing an Icon for each image. Then add each label to the panel.
To create an image of any Swing component you can use the Screen Image class.

Java Project changing behaviour

I have been working on a basic Java Swing application, that paints some objects into a opaque JPanel. I have been coding this app on a University MAC-PC. Yesterday I tested the program on my macbook air(after exporting the project), the behaviour of the application totally change.
The logic of the application is as follows, a Jframe that contains a JLayeredPaneL with Jpanel, in each Jpanel I paint some objects.The application is working correctly on the University laptop.
1)The JPanel is not longer transparent
//Creating Layered Panel
JLayeredPane lpane = new JLayeredPane();
lpane.setBounds(0, 0, screenSize.width, screenSize.height);
this.add(lpane, BorderLayout.CENTER);
lpane.setBounds(0, 0, screenSize.width, screenSize.height);
//creating Jpanel
myGlassPane = new JPanel()
myGlassPane.setBackground(new Color(0, 255, 0, 0));
myGlassPane.setBounds(0, 0, 400, 400);
myGlassPane.setOpaque(true);
myGlassPane.setVisible(true);
//adding item
lpane.add(myGlassPane);
this.setBackground(new Color(0, 255, 0, 0));//makes JFrame invisible
this.setVisible(true);
this.setResizable(false);
2) The JPanel does not remember what is previously drawn(it actually creates two Jpanel one what is being drawn at the moment and what was previously drawn)
I paint lines, whenever a new line is added to an array I call paintAgain(), here is the code of the paintComponent
public void paintLines(Point p)
{
arrayLines.add(p);
repaint();
//Only the point is displayed the other points are not visible,
//the other points are in another JPANEL?
}
public void delete()
{
delete = true;
arrayLines.clear();
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(delete)
{
g.clearRect(0,0,screenSize.width,screenSize.height);
delete =false;
}
else
{
g2d = (Graphics2D) g.create();
g2d.setStroke(new BasicStroke(10));
g2d.setColor(pickedColor);
//It just paints the new lines, it does not iterate through all the points
g2d.draw(new Line2D.Float(arrayLines.get(arraySize-1).getx1(), arrayLines.get(arraySize-1).gety1(),arrayLines.get(arraySize-1).getx2(),arrayLines.get(arraySize-1).gety2()));
}
}
I do not know why the behaviour of the program changes. Maybe the JRE version that i'm using?I have literally no idea since, it has never happened before
Thank you in advance
In your paintComponent method, your code as written just draws one line, and so one line is all that you see. Instead you need to use a for loop to iterate through your Point collection, arrayLines, drawing a line between points.
// note that i *must* start at 1, not at 0
for (int i = 1; i < arrayLines.size(); i++) {
int x1 = arrayLines.get(i - 1).x;
int y1 = arrayLines.get(i - 1).y;
int x2 = arrayLines.get(i).x;
int y2 = arrayLines.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
Also, where do you set delete to true ever?
Edit
Regarding your comments:
...The paint method is an example, I call paintLines() several times.
This won't matter if paintComponent draws one and only one line.
Do I have to repaint everything , everytime i make a modification in the array?
At this point, probably, yes. Later consider doing your static background drawing to a BufferedImage and then displaying that in the paintComponent almost first thing, right after the super.paintComponent(g) call, and then drawing your non-static, your moving sprites directly in paintComponent. If you know for a fact that you've only altered a portion of a component, you can call one of the repaint(...) overload methods that suggest repainting a rectangular area of the component.
The problem is this code is working in another computer and in mine it misbehaves.
The issue for me is that I have no idea why the code would have a prayer of working on another system since it is broken code.
One of the other issues you are having is the fact that you are using an alpha based color as the background to an opaque component...
myGlassPane = new JPanel()
myGlassPane.setBackground(new Color(0, 255, 0, 0));
myGlassPane.setBounds(0, 0, 400, 400);
myGlassPane.setOpaque(true);
myGlassPane.setVisible(true);
//adding item
lpane.add(myGlassPane);
Swing only knows how to paint opaque or transparent components and makes these decisions based on the opaque state of the components.
When transparent, the API knows that it must first prepare the graphics context properly and secondly, paint all components that might be beneath this one.
When using an alpha based background color, the component is unable to clear the Graphics context for painting (as filling with a transparent color doesn't do anything), this tends to mean that the Graphics context still contains what ever was painted to it previously (as the Graphics context is a shared resource).
Instead, remove...
myGlassPane.setBackground(new Color(0, 255, 0, 0));
and use
myGlassPane.setOpaque(false);
which will give you the same effect.
It will also mean you won't need
g.clearRect(0,0,screenSize.width,screenSize.height);
and can simply remove the all the elements from the arrayLines instead, which will give you the same effect...just longer lasting...

How to treat a shape painted with an algorithm like an object?

Ok dear folks, i've got this question and i don't really know a certain way to solve it.
I'm doing like a "Paint application" in java, i know everything is ready, but I need to paint the shapes with Computer Graphics Algorithms.
So, the thing is, once the shape is painted in the container how could I convert it like sort of an "Object" to be able to select the shape and move it around (I have to move it with another algorithm) I just want to know how could I know that some random point clicked in the screen belongs to an object, knowing that, I would be able to fill it(with algorithm).
I was thinking that having a Point class, and a shape class, if i click on the screen, get the coordinates and look within all the shapes and their points, but this may not be very efficient.
Any ideas guys ?
Thanks for the help.
Here is some of my code:
public class Windows extends JFrame{
private JPanel panel;
private JLabel etiqueta,etiqueta2;
public Windows() {
initcomp();
}
public void initcomp()
{
panel = new JPanel();
panel.setBounds(50, 50, 300, 300);
etiqueta = new JLabel("Circulo Trigonometrico");
etiqueta.setBounds(20, 40, 200, 30);
etiqueta2 = new JLabel("Circulo Bresenham");
etiqueta2.setBounds(150, 110, 200, 30);
panel.setLayout(null);
panel.add(etiqueta);
panel.add(etiqueta2);
panel.setBackground(Color.gray);
this.add(panel);
this.setLayout(null);
this.setVisible(true);
this.setSize(400,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
g2d.setStroke(new BasicStroke(2));
dibujarCirculo_bresenham(g2d, 50, 260, 260);
dibujarCirculo_trigonometrico(g2d, 50, 130, 200);
}
/*This functions paints a Circle*/
public void dibujarCirculo_trigonometrico(Graphics g,int R,int xc,int yc)
{
int x,y;
for (int i = 0; i < 180; i++) {
double angulo = Math.toRadians(i);
x = (int) (Math.cos(angulo)*R);
y = (int) (Math.sin(angulo)*R);
g.drawLine(x+xc, y+yc, x+xc, y+yc);
g.drawLine((-x+xc), (-y+yc), (-x+xc), (-y+yc));
}
}
I assume that any image is a valid (isn't constrained to a particular set of shapes). To get an contiguous area with similar properties, try using a flood fill.
To colour in or move a particular shape around, you can use flood fill to determine the set of pixels and manipulate the set accordingly. You can set a tolerance for similar hue, etc so that it's not as rigid as in Paint, and becomes more like the magic selection tool in Photoshop.
There are a couple of approaches to take here depending on what precisely you want.
1) is to have objects, one for each drawn thing on screen, with classes like Circle and Rectangle and Polygon so on. They would define methods like paint (how to draw them on screen), isCLickInsideOf (is a click at this point on screen contained by this shape, given size/position/etc?) and so on. Then, to redraw the screen draw each object, and to test if an object is being clicked on ask each object what it thinks.
2) is, if objects have the property of being uniform in colour, you can grab all pixels that make up a shape when the user clicks on one of the pixels by using a floodfill algorithm. Then you can load these into some kind of data structure, move them around as the user moves the mouse around, etc. Also, if every object is guaranteed to have a unique colour, you can test which object is being clicked on by just looking at colour. (Libraries like OpenGL use a trick like this sometimes to determine what object you have clicked on - drawing each object as a flat colour on a hidden frame and testing what pixel colour under the mouse pointer is)

Categories

Resources