How can I tell the paint method to draw background on JPanel only and not on the entire JFrame.
My JFrame size is bigger than the JPanel. When I try to paint a grid background for the JPanel, the grid seems to be painted all over the JFrame instead of just the JPanel.
Here parts of the code:
public class Drawing extends JFrame {
JPanel drawingPanel;
...........
public Drawing (){
drawingPanel = new JPanel();
drawingPanel.setPreferredSize(new Dimension(600,600));
}
public void paint(Graphics g)
{
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
paintBackground(g2); //call a METHOD to paint the for JPANEL
}
private void paintBackground(Graphics2D g2)
{
g2.setPaint(Color.GRAY);
for (int i = 0; i < drawingPanel.getSize().width; i += 300)
{
Shape line = new Line2D.Float(i, 0, i, drawingPanel.getSize().height);
g2.draw(line);
}
for (int i = 0; i < drawingPanel.getSize().height; i += 300)
{
Shape line = new Line2D.Float(0, i, drawingPanel.getSize().width, i);
g2.draw(line);
}
} //END private void paintBackground(Graphics2D g2)
}
If you want to do painting on the JPanel then override the JPanel, not the JFrame.
You should be overriding the paintComponent() method of JPanel. Read the section from the Swing tutorial on Custom Painting for a working example.
camickr is correct. So:
public class Drawing extends JFrame {
JPanel drawingPanel;
...........
public Drawing (){
drawingPanel = new MyPanel();
drawingPanel.setPreferredSize(new Dimension(600,600));
add(drawingPanel);
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
myBackgroundRoutine(g2);
}
}
You need to strictly separate your drawing from different components. Swing is already
managing subcomponents, so there is absolutely no need to implement drawings in your
Panel in the Frame (calling paintComponents() is a severe error).
And you should never override paint(), because only paintComponent()
is used in Swing. Don't mix both until you absolutely know what you are doing.
super.paintComponents(g);
I would suggest as your first point of investigation.
The code you posted is not complete, it's missing how the panel is added to the JFrame and which LayoutManager is being used.
The code seams to be correct. Are you sure the JPanel is not occupying the whole JFrame? Add a System.out.println(drawingPanel.getSize()) to check this.
If you are using the BorderLayout, the default for JFrame, and has just added the panel without any constraint, the panel will use the whole area. The PreferredSize is ignored.
Try this, just for testing:
public Drawing (){
drawingPanel = new JPanel();
drawingPanel.setPreferredSize(new Dimension(600,600)); // ignored
drawingPanel.setBounds(0, 0, 600, 600); // location and size
setLayout(null);
add(drawingPanel);
}
but IMO this is not the best or correct way to do it. I would prefer to override the paintComponent() method from the JPanel, as suggested by Thorsten and camickr.
But it will still use the whole area of the JFrame until other Component is added to the JFrame or the LayoutManager changed.
You should override the JPanel, not the JFrame to do painting. You can override the paintComponent() method of the JPanel
Related
i am currently trying to make a canvas that i can draw stuff to and have it appear inside a JFrame.
To do this, i intend to have a BufferedImage inside a JPanel component that the paintComponent method can draw from.
Ideally from the given JFrame i want to be able to reference this buffered image, and then draw stuff to it using its Graphics2D that the paintComponent method can then show when it draws using the buffered image.
I'm doing this to avoid using the paintcomponent method directly, i want to be able to reference this canvas from anywhere in the program and have it be painted when the frames repaint() method is called.
class MyPanel extends JPanel {
BufferedImage img = new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB);
Graphics2D imgG2 = img.createGraphics();
public Graphics2D getGraphics() {
return imgG2;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int w = img.getWidth();
int h = img.getHeight();
g2.drawImage(img, 0, 0, w, h, null);
}
}
class Main {
private static JFrame createAndShowGui() {
JFrame frame = new JFrame("droneFrame");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new MyPanel());
frame.setSize(500, 500);
frame.setResizable(false);
frame.setVisible(true);
return frame;
}
public static void main(String args[]) {
JFrame frame = createAndShowGui();
//Something here to reference the inner Jpanels imgG2 field, and draw to it.
frame.repaint();
//Draw whatever is currently in the buffered image.
}
}
However, i'm at a loss at how to do this, since frame.getComponent(0) just returns a Component, rather than the specfic type of component it is.
Thanks in advance.
Just managed to figure this out, you need to set the content pane of your JFrame to the JPanel, then to reference the graphics of the buffered image, you need to get the content pane of the JFrame, and downcast it to the specific type MyPanel.
Now you have the content pane in the correct format, and can reference the graphics since it now has that field.
I'm working on a project and I just started on the GUI. Since this isn't my most favorite topic, I stumbled real quick on something not working quite right. Everything (PacmanGrid,PacmanScore) is shown correctly but the borders I wrote for the PacmanScore Panel! Anyway here is the code, hope someone can help.
public class PacmanFrame extends JFrame{
public PacmanFrame() {
this.setLayout(new BorderLayout());
this.setTitle("Pacman");
PacmanGrid p1=new PacmanGrid();
PacmanScore p2 = new PacmanScore();
this.add(p1,BorderLayout.CENTER);
this.add(p2,BorderLayout.EAST);
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.repaint();
pack();
super.setVisible(true);
}
public static void main(String[] args) {
PacmanFrame p1 = new PacmanFrame();
}
}
PacmanScore
public class PacmanScore extends JPanel{
private TitledBorder t3 = BorderFactory.createTitledBorder("Menu");
private Border etched = BorderFactory.createEtchedBorder(Color.WHITE, Color.white);
public PacmanScore() {
setLayout(new FlowLayout());
setPreferredSize(new Dimension(100,800));
setBackground(Color.DARK_GRAY);
t3.setBorder(etched);
setBorder(t3);
setVisible(true);
setOpaque(true);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(Color.white);
g2.drawString("Score: ", 20, 400);
}
}
PacmanGrid is also extended by a Panel and draws the classical PacmanGrid using predefined patterns. But I don't think it is relevant since the problem is clearly on the PacmanScore Panel. I will post the code if anyone needs tho.
Thanks in Advance!
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(Color.white);
g2.drawString("Score: ", 20, 400);
}
You didn't override paint() properly because you didn't invoke super.paint() and therefore the border is not painted.
Don't override paint(). Custom painting is done by overriding paintComponent().
Read the section from the Swing tutorial on A Closer Look at the Paint Mechanism for more information.
Why are you even doing custom painting? Just add a JLabel to the panel.
Also, Swing components (except for top level windows) are visible by default so there is no need to make the panel visible.
So, I have a JLayeredPane (technically a class subclassing JLayeredPane actually). On that is a JPanel. I want to add a BufferedImage to the Jpanel.
public class BigMap extends JLayeredPane implements MouseListener
JPanel mapPanel;
BufferedImage theMap;
public BigMap (BufferedImage m){
theMap = m;
mapPanel = new JPanel();
add(mapPanel, 0);
mapPanel.setBounds(0, 0, 640, 640);
//other unimportant stuff
}
#Overrride
public void paintComponent (Graphics g){
super.paintComponent(g);
Graphics2D gmap = (Graphics2D) mapPanel.getGraphics();
gmap.drawImage(theMap, null, 0, 0);
//some other stuff which is working just fine
}
The issue is that the BufferedImage isn't displaying. The JPanel is definately present as I can set its backgroundColour and see it if I wish. I realise that JLayeredPane doesn't have a layout manager and have had to set the bounds for the JPanel but that shouldn't be an issue for the JPanel itself, surely? And given that BufferedImage lacks methods to control its size directly I don't see how I'd overcome that if it were.
Any help appreciated.
The problem here is that you override the paintComponent() method of your layered pane, not the JPanel. The JPanel will paint itself later, as one of the children of your layered pane, and this will wipe out what you painted.
In general, a paintComponent() method should paint into the Graphics that was given to it, not into some other component's graphics.
Can JPanels background be set to transparent?
My frame is has two JPanels:
Image Panel and
Feature Panel.
Feature Panel is overlapping Image Panel.
The Image Panel is working as a background and it loads image from a remote URL.
On Feature Panel I want to draw shapes. Now Image Panel cannot be seen due to Feature Panel's background color.
I need to make Feature Panel background transparent while still drawing its shapes and I want Image Panel to be visible (since it is doing tiling and cache function of images).
I'm using two JPanel's, because I need to seperate the image and shape drawing .
Is there a way the overlapping Jpanel have a transparent background?
Calling setOpaque(false) on the upper JPanel should work.
From your comment, it sounds like Swing painting may be broken somewhere -
First - you probably wanted to override paintComponent() rather than paint() in whatever component you have paint() overridden in.
Second - when you do override paintComponent(), you'll first want to call super.paintComponent() first to do all the default Swing painting stuff (of which honoring setOpaque() is one).
Example -
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TwoPanels {
public static void main(String[] args) {
JPanel p = new JPanel();
// setting layout to null so we can make panels overlap
p.setLayout(null);
CirclePanel topPanel = new CirclePanel();
// drawing should be in blue
topPanel.setForeground(Color.blue);
// background should be black, except it's not opaque, so
// background will not be drawn
topPanel.setBackground(Color.black);
// set opaque to false - background not drawn
topPanel.setOpaque(false);
topPanel.setBounds(50, 50, 100, 100);
// add topPanel - components paint in order added,
// so add topPanel first
p.add(topPanel);
CirclePanel bottomPanel = new CirclePanel();
// drawing in green
bottomPanel.setForeground(Color.green);
// background in cyan
bottomPanel.setBackground(Color.cyan);
// and it will show this time, because opaque is true
bottomPanel.setOpaque(true);
bottomPanel.setBounds(30, 30, 100, 100);
// add bottomPanel last...
p.add(bottomPanel);
// frame handling code...
JFrame f = new JFrame("Two Panels");
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// Panel with a circle drawn on it.
private static class CirclePanel extends JPanel {
// This is Swing, so override paint*Component* - not paint
protected void paintComponent(Graphics g) {
// call super.paintComponent to get default Swing
// painting behavior (opaque honored, etc.)
super.paintComponent(g);
int x = 10;
int y = 10;
int width = getWidth() - 20;
int height = getHeight() - 20;
g.drawArc(x, y, width, height, 0, 360);
}
}
}
Alternatively, consider The Glass Pane, discussed in the article How to Use Root Panes. You could draw your "Feature" content in the glass pane's paintComponent() method.
Addendum: Working with the GlassPaneDemo, I added an image:
//Set up the content pane, where the "main GUI" lives.
frame.add(changeButton, BorderLayout.SOUTH);
frame.add(new JLabel(new ImageIcon("img.jpg")), BorderLayout.CENTER);
and altered the glass pane's paintComponent() method:
protected void paintComponent(Graphics g) {
if (point != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.3f));
g2d.setColor(Color.yellow);
g2d.fillOval(point.x, point.y, 120, 60);
}
}
As noted here, Swing components must honor the opaque property; in this variation, the ImageIcon completely fills the BorderLayout.CENTER of the frame's default layout.
In my particular case it was easier to do this:
panel.setOpaque(true);
panel.setBackground(new Color(0,0,0,0,)): // any color with alpha 0 (in this case the color is black
(Feature Panel).setOpaque(false);
Hope this helps.
To set transparent you can set opaque of panel to false like
JPanel panel = new JPanel();
panel.setOpaque(false);
But to make it transculent use alpha property of color attribute like
JPanel panel = new JPanel();
panel.setBackground(new Color(0,0,0,125));
where last parameter of Color is for alpha and alpha value ranges between 0 and 255 where 0 is full transparent and 255 is fully opaque
public void paintComponent (Graphics g)
{
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.0f)); // draw transparent background
super.paintComponent(g);
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f)); // turn on opacity
g.setColor(Color.RED);
g.fillRect(20, 20, 500, 300);
}
I have tried to do it this way, but it is very flickery
As Thrasgod correctly showed in his answer, the best way is to use the paintComponent, but also if the case is to have a semi transparent JPanel (or any other component, really) and have something not transparent inside. You have to also override the paintChildren method and set the alfa value to 1.
In my case I extended the JPanel like that:
public class TransparentJPanel extends JPanel {
private float panelAlfa;
private float childrenAlfa;
public TransparentJPanel(float panelAlfa, float childrenAlfa) {
this.panelAlfa = panelAlfa;
this.childrenAlfa = childrenAlfa;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, panelAlfa));
super.paintComponent(g2d);
}
#Override
protected void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_ATOP, childrenAlfa));
super.paintChildren(g);
}
//getter and setter
}
And in my project I only need to instantiate Jpanel jp = new TransparentJPanel(0.3f, 1.0f);, if I want only the Jpanel transparent.
You could, also, mess with the JPanel shape using g2d.fillRoundRect and g2d.drawRoundRect, but it's not in the scope of this question.
I cannot get this oval to draw on the JFrame.
static JFrame frame = new JFrame("New Frame");
public static void main(String[] args) {
makeframe();
paint(10,10,30,30);
}
//make frame
public static void makeframe(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(375, 300));
frame.getContentPane().add(emptyLabel , BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// draw oval
public static void paint(int x,int y,int XSIZE,int YSIZE) {
Graphics g = frame.getGraphics();
g.setColor(Color.red);
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
The frame displays but nothing is drawn in it. What am I doing wrong here?
You have created a static method that does not override the paint method. Now others have already pointed out that you need to override paintComponent etc. But for a quick fix you need to do this:
public class MyFrame extends JFrame {
public MyFrame() {
super("My Frame");
// You can set the content pane of the frame to your custom class.
setContentPane(new DrawPane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
}
// Create a component that you can actually draw on.
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
g.fillRect(20, 20, 100, 200); // Draw on g here e.g.
}
}
public static void main(String args[]){
new MyFrame();
}
}
However, as someone else pointed out...drawing on a JFrame is very tricky. Better to draw on a JPanel.
Several items come to mind:
Never override paint(), do paintComponent() instead
Why are you drawing on a JFrame directly? Why not extends JComponent (or JPanel) and draw on that instead? it provides more flexibility
What's the purpose of that JLabel? If it sits on top of the JFrame and covers the entire thing then your painting will be hidden behind the label.
The painting code shouldn't rely on the x,y values passed in paint() to determine the drawing routine's start point. paint() is used to paint a section of the component. Draw the oval on the canvas where you want it.
Also, you're not seeing the JLabel because the paint() method is responsible for drawing the component itself as well as child components. Overriding paint() is evil =)
You are overriding the wrong paint() method, you should override the method named paintComponent like this:
#Override
public void paintComponent(Graphics g)
You need to Override an exist paint method that actually up to dates your Frame. In your case you just created your custom new method that is not called by Frame default.
So change your method to this:
public void paint(Graphics g){
}