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());
Related
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.
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.
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
I want to draw customized elements on a JFrame.
I've tried it by creating a class UI (extends JFrame) and a class Component (extends JPanel). The component draws something on itself and the UI just adds this component. So until now, I've written this code:
File UI.java
package UIComponent;
import javax.swing.JFrame;
public class UI extends JFrame {
public UI(){
this.setSize(1024,684);
this.setTitle("This is just a test program.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
}
}
File Component.java
package UIComponent;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.Graphics;
public class Component extends JPanel {
int x, y, w, h;
public Component(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
#Override
public void paintComponent(Graphics g){
g.setColor(Color.red);
g.fillRect(this.x, this.y, this.w, this.h);
}
}
But the result is not that what I accept. It draws just one Rectangle.
The x/y/w/h values have no bearing on the actual size of the compnent which is likely to be 0x0, meaning that you'd be painting out side of the visible area of the component.
Start by overriding the getPreferredSize method and return a area which would allow you painting to be visible, something like....
public Dimension getPreferredSize() {
return new Dimension(x + w, y + h);
}
For example.
JFrame uses a BorderLayout by default, which means that it will only allow one component to be visible within any of its 5 available positions.
This means that your example will only show the last component added.
Depending on what you intend to achieve, you might consider using an OverlayLayout or some other layout manager.
Personally, unless you had a particular need, I would not worry about the x/y position of the painting, and simply paint from the 0x0 position of component, allowing the containers layout manager to deal with the actually positing.
I'd as reconsider some of your naming, as Component already exists in the API and may cause confusion, and components already have a concept of position and size...
Remember, the position of the component within its container has no effect on where the components drawing starts. That is, 0x0 is always the top left corner of the component.
Don't extend JFrame. You are not adding any new behaviour to the frame.
Don't call your class Component. There is already an AWT class by that name so you will probably cause Swing to stop working.
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
The default layout manager for a JFrame is a BorderLayout. By default when you add components to the frame without specifying a constraint they go to the CENTER. The CENTER can only contain a single component, so that is why you only see the last one added.
Instead try adding one component to the BorderLayout.NORTH and one to the SOUTH.
Also, the components won't paint properly because you need to override the getPreferredSize() method of you custom component so the layout manager can do its job:
#Override
public Dimension getPreferredSize()
{
return new Dimension(w, h);
}
Also, the paintComponent() method should invoke super.paintComonent().
Check out the Swing tutorial. You should be reading the sections on Custom Painting and Layout Managers for more information.
Also, the painting of your rectangles should be done at an x/y location of (0, 0) so that the entire painting will fit in the width/height of your component. If you want the rectangle to appear at a specific location then you should be using a null layout in which case you are responsible for setting the location and size of the component.
If you are trying to just paint shapes on a panel then you should probably be playing with the Shape class instead of creating custom components. See Playing With Shapes for more ideas.
Just adding a LayoutManager should give your the two rectangles you're looking for
public class UI extends JFrame {
public UI(){
this.setSize(1024,684);
this.setTitle("This is just a test program.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new GridLayout(1, 2)); // I used a simple grid layout.
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
}
public static void main(String[] args){
SwingUtlities.invokeLater(new Runnable(){
public void run(){
new UI();
}
});
}
}
I'm currently designing a menu with several screens with multiple buttons on each screen. To use buttons on top of the background image, which is in a jLabel (by default, I can't put buttons on TOP of the jLabel), I used GridBagLayout with two panels/menu screen, one panel containing the buttons (opaque = false) and one panel with the background image, or jLabel. In order to switch the current panels being displayed, depending on where the user is in the menu, I made each menu screen (aka. every 2 panels) in separate methods, not classes.
Now, I've come to the point where I'm working on parts of the interface that are unnecessarily complicated, and I don't feel GridBag will serve my purposes, so I was wondering if there was a different way to draw my background image, still being able to use my buttons on top of the image.
The most popular way I looked up was overriding the paintComponent method, but I can't do that, since I've made my JPanels in separate methods, not classes. They're all contained in my original JFrame.
Help would be greatly appreciated, thank you!
Just added this code, but my background remains white for some reason? Trying the other suggestion right now, thanks guys!
private void mainPanel() {
icon = new ImageIcon(getClass().getResource("/phantasma/menuv1.png"));
mainContainer1 = new javax.swing.JPanel() {
#Override
protected void paintComponent(Graphics g) {
g.drawImage(icon.getImage(), 0,0, null);
super.paintComponent(g);
}
};
BG image with Swing without overriding paintComponent
I have no idea why all the postings suggest doing custom painting for this. You would only do custom painting if you need to automatically scale the background image.
If you want the image painted at its real size then use a JLabel.
I can't put buttons on TOP of the jLabel),
Sure you can. Just set a LayoutManager for the JLabel and then you can add any component to it the same way you add components to a panel.
In my comment above I state:
You can always create an anonymous inner JPanel-derived class and override the paintComponent method there if need be.
As an example of what I mean, you can override paintComponent in any JPanel that you create whether it's derived from a stand-alone class or created within a method. For e.g.,
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class AnonInnerPanel {
private static void createAndShowGui() {
JPanel mainPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
};
JFrame frame = new JFrame("AnonInnerPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}