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.
Related
I am using Visual Studio Code 2020, and it is giving me the error "The method setDefaultCloseOperation(int) is undefined for the type Frame"
The problem is line 52,
import java.awt.Frame;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import java.awt.Color;
public class Main {
public static void main(String[] args) {
boolean loop = false;
/* while (loop = true) {
try {
Thread.sleep(2000);
} catch (InterruptedException reallyIgnored) {}
System.out.println("Loop is working.");
} */
}
static class GraphicsEngine extends Component {
public void paint(Graphics g) {
// Creating Graphics Shortcut
Graphics2D g2d = (Graphics2D)g;
// Creating new framw window, declaring size
Frame frame = new Frame();
frame.add(new GraphicsEngine());
int frameWidth = 700;
int frameHeight = 500;
frame.setSize(frameWidth, frameHeight);
frame.setLayout(null);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
/* Next part will create dot that moves across screen.
It will have a loop that draws the dot, and also a loop
that erases the previous dot. */
g2d.SetColor(new Color(255, 255, 255));
g2d.fillRect(0, 0, getSize().height-1, getSize().height-1);
}
}
}
I have tried looking for answers, but none of the ones I found had worked.
I am a noob, and picked up java a few days ago. I don't really understand much, but I am trying to learn how graphics work right now
The error means that the setDefaultCloseOperation(int) is not found as a method of your object frame . This could be because there is no method with that name in the frame object, or if there is such a method, there isn't one that takes a single int argument.
Looking up the API here for Frame and JFrame:
https://docs.oracle.com/javase/7/docs/api/java/awt/Frame.html https://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html
setDeaultCloseOperation seems to be defined for the JFrame object, and not Frame. JFrame extends Frame, meaning it is a specific kind of frame. Specifically, it is a frame that has the setDefaultOperation() method.
Perhaps change your frame definition to Frame frame = new JFrame();
or JFrame frame = new JFrame();
Your tag says you are asking about a JFrame, which does have the setDefaultCloseOperation(...) method.
However, your code is using Frame which is an AWT component, not a Swing component. Use a JFrame for Swing.
Also, you class is extending Canvas. For a Swing application you should be extending JPanel and overriding paintComponent().
There is no need to use AWT components when you can use Swing.
I am trying to learn how graphics work right now
First of all you should NEVER create a component in a painting method. A painting method should only use the Graphics object to do painting.
Read the section from the Swing tutorial on Custom Painting for working examples to get you started.
Follow the examples from the tutorial for properly structured code. The code you posted here is mostly wrong.
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());
I am writing a small GUI in Java, using Swing components. My program uses several overlapping panels, the sizes of which are decided upon at the point that 'pack()' is called.
My problem is this. I need to know the dimensions of a particular JPanel prior to pack(), as I need to draw a line vertically down it. I cannot get this height dimension however until pack is called.
I have put in a System.out.println(myPanel.getSize()) call before the pack command & it returns (0, 0). When put in after, it returns the actual dimensions of the panel... as you would expect.
So, how does one draw a line on a panel down its entire length, either without knowing its length to begin with, or somehow doing so after pack has been called?
You can achieve this by adding a ComponentListener to the panel. Its componentResized() event is triggered whenever the panel is resized. And inside componentResized() method you will always get the actual size of the panel. Try below example and see it yourself.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class PanelResize
{
public static void main(String[] args)
{
CustomPanel panel = new CustomPanel();
panel.addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
System.out.println(panel.getSize());
panel.repaint();
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setBounds(300, 200, 400, 300);
f.setVisible(true);
}
}
class CustomPanel extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawLine(getWidth()/2, 0, getWidth()/2, getHeight());
}
}
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
Whatever I do, I can not display rectangle/line/oval on the screen. I checked other sources where they paint graphics, but when I even execute those codes, I don't get any graphics displayed on the windows. Below is the example from the text book.
import java.awt.*;
import javax.swing.*;
class PlotGraph
{
public static void main (String [] args) {
JFrame win;
Container contentPane;
Graphics g;
win = new JFrame("testing");
win.setSize(300,200);
win.setLocation(100,100);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setVisible(true);
contentPane = win.getContentPane();
g = contentPane.getGraphics();
g.drawRect(10, 30, 50, 50);
}
}
Ouch. You should change your text book then. First of all, all the accesses to Swing components must be done in the event dispatch thread.
Second, you should not get the graphics of a component and paint on it. Instead, you should extend a JComponent or JPanel, override its paintComponent(Graphics) method, and paint using the Graphics object passed as argument (and which is in fact a Graphics2D instance).
That's not how graphics work in Swing.
You need to add a component to your frame, not just draw on it. You never want to draw directly on the frame. The reason why it's not doing anything is because your drawing code is being overridden.
If you want your component to have custom drawing code, make a subclass of JComponent and override the paintComponent(Graphics) method. An example of how you should do this is as follows:
import java.awt.*;
import javax.swing.*;
class PlotGraph {
public static void main(String[] args) {
JFrame win;
win = new JFrame("testing");
win.setSize(300, 200);
win.setLocation(100, 100);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setVisible(true);
win.setContentPane(new MyComponent());
}
}
class MyComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
g.drawRect(10, 30, 50, 50);
}
}
I would highly encourage you to check out the Java GUI tutorial online.