Multiple components in JPanel not displayed - java

I have tried many solutions but I do not know what is wrong with my code.
Basicaly I want to display the shapes in the window, FlowLayout does not display anything and BorderLayout displays the last one which is not what I want. Ignore the shape.draw() method, it just prints coordinates of the shape. Shape extends JComponent.
package Shapes;
import javax.swing.*;
import java.awt.*;
/**
* Created by Matej on 10/12/2016.
*/
public class TestShapes extends JFrame
{
//static Shape[] shapes = new Shape[3];
public static void main(String[] args)
{
Shape[] shapes = new Shape[3];
shapes[0] = new Circle(300,100,20);
shapes[1] = new Rectangle(100,100,40,60);
shapes[2] = new RedRectangle(200,200,20,30);
TestShapes window = new TestShapes();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(500,500);
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
for(Shape shape:shapes)
{
shape.printName();
shape.draw();
panel.add(shape);
}
window.add(panel);
window.setVisible(true);
}
public void paint (Graphics g)
{
super.paint(g);
}
}

You've not shown us your code for your Shape class and subclass, but regardless you're doing it wrong, and the fix is to not have them extend JComponent. Rather make them logical not component classes, and pass them into a JPanel that holds them in an ArrayList<...> and that draws them in its paintComponent method override. Then add this JPanel to your JFrame's contentPane, BorderLayout.CENTER, so that it may display its contained shapes.
Note that JComponents default to a preferred size of 0,0 unless they have been given other reason not to -- such as if they hold components that have preferred size or if they have an overridden getPreferredSize() method.
But again this is moot, because you're not wanting to display each figure in its own component as this will unnecessarily limit what you can do with the images and where you can display them.

Related

Drawing to JPanel on Layered Pane

What I'm looking to do is custom draw to a JPanel that is attached to one of the layers in a layered pane.
For simple drawing I get that you can effectively do the following:-
JFrame frame = new JFrame();
frame.add(new CustomPaintComponent());
I have this and the CustomPaintComponent is called, drawing to a test frame created - all works fine. However...if I try the same approach (below) but using pane instead of frame the CustomPaintComponent isn't even called let alone producing the same drawing I get when adding simply to the frame.
pane.add(new CustomPaintComponent(),JLayeredPane.POPUP_LAYER);
I'd be grateful for any support/advice on this. Why isn't the method being called - should I be doing something (maybe a lot :P) differently?
Simple Example Below
Example Class which creates the JFrame and JLayeredPane and JPanel (the latter accesses second class below)
package example;
import javax.swing.*;
public class Example {
public static void main(String[] args) {
JLayeredPane forLayers = new JLayeredPane();
forLayers.setSize(300, 300);
JFrame showsDrawnImage = new JFrame ("JFrame");
showsDrawnImage.setSize(300, 300);
JPanel panelDrawnOn = new DrawImage();
//CODE BELOW WORKS - and returns string line in output//
showsDrawnImage.add(panelDrawnOn); //blank these out to show the layeredpane example
showsDrawnImage.setVisible(true); //blank these out to show the layeredpane example
//CODE BELOW DOESN'T WORK - only shows the JFrame and DOES NOT return string line in output//
forLayers.add(panelDrawnOn, JLayeredPane.PALETTE_LAYER);
showsDrawnImage.add(forLayers);
forLayers.setVisible(true);
showsDrawnImage.setVisible(true);
}
}
DrawImage class to do the actual drawing
package example;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.JPanel;
public class DrawImage extends JPanel{
public void paintComponent( Graphics g ) {
System.out.println("This is what I try to access/draw");
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Line2D line = new Line2D.Double(10, 10, 40, 40);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(10));
g2.draw(line);
}
}
I would guess the main issue is that your custom component doesn't have a "size" so there is nothing to paint.
When you add a component to a JFrame, the layout manager will give the components a size. A JLayeredPane doesn't use layout managers, so it is now your responsibility to give the component a size and location.
Read the section from the Swing tutorial on How to Use Layered Panes for a working example.
Also, don't use the POPUP_LAYER. That is meant to be used for temporary display of a component only.

Cant draw two items to Jframe

I cant Draw two items( there will be more) to a Jframe, im trying to make a landscape, but the item painted last overwrites anything before it.
Main:
import javax.swing.*;
import java.awt.*;
public class TheComponets extends JComponent {
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(600, 600);
frame.setTitle("A house on the water!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
House home = new House();
Sun sun = new Sun();
frame.setLayout(new GridLayout(2,3));
frame.add(home);
frame.add(sun);
}
}
House class:
import javax.swing.*;
import java.awt.*;
import java.applet.*;
// Program to draw a house
public class House extends JComponent
{
public void paintComponent(Graphics g)
{
// Draw the roof
g.setColor(Color.red);
int xs[] = {100,160,220};
int ys[] = {100,50,100};
Polygon poly=new Polygon(xs,ys,3);
g.fillPolygon(poly);
// Draw the body of house
g.setColor(Color.blue);
g.fillRect(100,100,120,120);
// draw the door
g.setColor(Color.orange);
g.fillRect(145,160,30,60);
}
}
Sun class:
import javax.swing.*;
import java.awt.*;
public class Sun extends JComponent {
public void paintComponent(Graphics g)
{
// draw sun
g.setColor(Color.yellow);
g.fillOval(500, 0, 50, 50);
}
}
I want the house and the sun to show up in the Jframe, but as of now it will only show the last frame.add() object. I have only been programming for two months and dont know much about Swing and awt. Please try to keep that in mind when answering.
The reason of this, is that a JFrame uses a BorderLayout by default. When you frame.add(component) without any constraints, the component will be added to BorderLayout.CENTER position. So, no matter how many components you will add without constraints, borderlayout will override the older since all of them are being added to CENTER.
The solution would be either to choose where you want your components to be added:
frame.add(home,BorderLayout.CENTER);
frame.add(sun,BorderLayout.LINE_START);
either to change the layout of your container (the JFrame in your case):
frame.setLayout(new FlowLayout());
frame.add(home);
frame.add(sun);
Worth to read: A Visual Guide to Layout Managers
Finally, do not #Override paint() method. #Override paintComponent() method instead.
When you use individual panels for custom painting then your painting will be done in 2D since components are positioned in 2D space based on the layout manager used.
im trying to make a landscape,
Then keep all you custom painting in a single class.
First you paint the background. Then you paint the sun, then the house etc.
You will now have full control over the order in which items are painted.
To Add multiple components on JFrame, need to set layout from Layout manager. it can be FlowLayout or Gridlayout or BorderLayout....
In your case,it add Last component only because JFrame's default layout is BoderLayout and can add component
frame.add(home, BorderLayout.LINE_START);
you have PAGE_START, PAGE_END, LINE_START, LINE_END, CENTER position to add component. so add second component to other position or change layout of frame using
frame.setLayout(new FlowLayout());

paintComponent overriding to draw on a panel

This is a noob question.
We are being taught applets in class, and I was trying something on my own.
The following is the code
import java.awt.*;
import javax.swing.*;
class controls extends JPanel{
#Override public void paintComponent(Graphics g) {
g.drawOval(50, 50, 50, 50); // <-- draws an oval on the panel
}
}
public class test extends JApplet{
public void init(){
final JPanel stage = new JPanel();
final JPanel controlPanel = new controls();
final JPanel banner = new JPanel();
final JLabel name = new JLabel("Test", JLabel.CENTER);
this.setLayout(new BorderLayout());
banner.setBackground(Color.CYAN);
banner.add(name);
this.add(controlPanel, BorderLayout.WEST);
this.add(banner, BorderLayout.NORTH);
}
}
As far as I understand, paintComponent() need not be called explicitly.
The controls class works well when used alone.
I mean the following code works.
public class test extends JApplet{
public void init(){
JPanel controlPanel = new controls();
this.add(controlPanel);
}
}
I am not able to understand the difference. Why does the same code work in this case, and not in the previous?
Thank you.
Override public Dimension getPreferredSize() (and return a new Dimension) in the controls class. When putting components in WEST the width will be determined by the preferredSize. If you don't override getPreferredSize, the preferred size will be 0. The CENTER will take up the rest of the space, after the WEST, ect is calculated. The second case works because it is in the CENTER of the default BorderLayout

adding a drawn circles Objects to an Arraylist

I created an Arraylist of objects (Circles). I added a mouseclick event and so once I click in the panel, a circle will be drown and stored in the arraylist. I am stuck and can't think of a way around my code... I would appreciate some hints that could help me solving my problem.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class Circle extends JFrame
{
private JPanel panel;
private ArrayList <Circle> circle;
public static void main(String[]args)
{
setTitle("Drawing Circles");
// Set the size of the window.
setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
// Specify an action for the close button.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set the Frame's layout
setLayout(new BorderLayout());
// Add the panels to the frame's content pane.
add(panel, BorderLayout.CENTER);
// Display the window.
setVisible(true);
circle = new ArrayList<Circle>();
}
public Circle()
{
panel.addMouseListener(new ClickingLitener());
}
private class ClickingLitener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{
circle.add(new Circle());
// somehow I need to call panel.paintComponent ... right ?
}
}
}
Your Circle class extends JFrame. You can't add or paint a JFrame on a JPanel so your basic approach is flawed.
If you want to do custom painting to draw a Circle on a panel then you need to store information about the Circle that you want to draw. Then in the paintComponent() method of the panel you iterate through the ArrayList and paint all the circles. When you add a new Circle to the ArrayList you just invoke repaint() on the panel.
Check out Custom Painting Approaches for working examples of this approach. The code adds "Rectangles" to the panel, but you should be able to change the code easily enough to add circles.

Add GUI with Swing, but unsure of the sequence to take

I'm building a GUI for a data processing algorithm. I can instantiate the window, give it a background, title, etc., but when I try adding panels to it, I run into trouble. What I'm really looking for more than a proofreader is a suggestion for the sequence in which to build, configure, and add objects in Java Swing so that they behave correctly, in a generic sense. So, is this the best way to build a JFrame with a different-colored panel in it?
Declare JFrame
Set JFrame color (background color)
Declare JPanel (box to represent data graphically)
Set JPanel color (box color)
Add JPanel to JFrame
Set JFrame to visible = true
It makes sense intuitively but it doesn't seem to work, no matter what I do. I've found step-by-step instructions elsewhere but they tend to explain what to type more than why you're typing it, so you get a very narrow understanding of what's going on. Thanks for any help!
Below is the full code; I hesitated to post it because I'd begun experimenting with Graphics2D and it isn't well-commented, but if it helps:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
JFrame mainWindow = new JFrame();
JPanel backgroundPanel = new JPanel();
JPanel subPanel = new JPanel();
Color background = new Color(40,40,40);
Color subWindow = new Color(255, 255, 255);
TitledBorder title = BorderFactory.createTitledBorder("title");
Rectangle rect1 = new Rectangle(10, 10, 40, 40);
Graphics2D g;
public static void main (String[] args)
{
new GUI();
}
public GUI()
{
initializeGUI();
}
private void initializeGUI()
{
mainWindow.setSize(1340, 880);
backgroundPanel.setBackground(background);
subPanel.setBackground(subWindow);
subPanel.setBorder(title);
mainWindow.setTitle("Ed");
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainWindow.add(backgroundPanel);
backgroundPanel.add(subPanel);
updateGUI();
}
public void updateGUI()
{
mainWindow.setVisible(false);
mainWindow.setVisible(true);
}
public void paintComponent(Graphics g)
{
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
}
Let's break this down....
public class GUI extends JFrame {
JFrame mainWindow = new JFrame();
There is no need to extend from JFrame as you are neither using it nor are you adding any value to the class.
This...
public void paintComponent(Graphics g) {
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
is doing nothing and will never be called, as nothing you've extended from implements a paintComponent method (that is, JFrame does not have a paintComponent methd) (and you class is not attached to anything displayed on the screen anyway). Also, you should NEVER maintain a reference to ANY Graphics context you did not create yourself.
The reason that subPanel is appearing so "small" is because it has not definable size, aside from the border.
You could rectify this in one of three ways...
You could change the layout manager of backgroundPanel to something like BorderLayout
You could override the getPreferredSize method of the subPanel to return a more suitable size or
You could add other components to it and let the layout manager figure it out...
In any case, you should have a look at Laying Out Components Within a Container.
You should also have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting is done in Swing

Categories

Resources