I am trying to make a small paint program. I am drawing objects over a JPanel which is on top of JFrame (I am using Netbeans 6.9). I have some basic functionality like font, line and fillRectangle. I am using the standard method to draw which is to override paintComponent().
class .... extends JPanel
{
#Override
void paintComponents(Graphics g)
{
.......
}
}
The problem is that when I draw a text,line over a region then it is drawn behind it rather than on top of it. Basically I want to draw objects on top of all other objects that have previously been drawn on the JPanel. I really do not want to switch to other types of layered pane. One very naive method will be to undo every object and paint them in reverse order (last one first).
You will need to override paintComponent(Graphics g) and do not forget to call super.paintComponent(Graphics g);
class .... extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);//honor paintComponent an call super to draw other components that were added to the JPanel
.......
}
}
You may also need to override getPreferredSize(..) of JPanel and return an appropriate size so the JPanel will be visible:
class .... extends JPanel
{
#Override
public Dimension getPreferredSize()
{
return new Dimension(300,300);
}
}
EDIT:
Depending on what you are doing you may also want to have a look at the GlassPane which will allow you to set a transparent pane over the entire JFrame window and can be painted too, which will cause the graphics to be drawn above all others like so:
This is an old question, but I had the same problem and solved it by overriding paintChildren(Graphics g) instead of paintComponent.
As the Oracle documentation states, the order of execution for the three paint methods is:
protected void paintComponent(Graphics g)
protected void paintBorder(Graphics g)
protected void paintChildren(Graphics g)
So, paintChildren(g) is run last, which means whatever we draw inside it is drawn on top of all previously drawn components.
Related
I have a JApplet (MainClass extends JApplet), a JPanel (ChartWindow extends JPanel) and a Grafico class.
The problem is that the Grafico class instance has 2 JPanel that should show 2 images (1 for each panel) but the images are shown and after a little while they disappears: instead of them i get a gray background (like an empty JPanel). This happens for every repaint() call (that are made in the ChartWindow class)
the MainClass init() contains
chartwindow=new ChartWindow();
add(chartwindow)
chartwindow has a Grafico instance.
it's the ChartWindow's paintComponent (override)
paintComponent(Graphics g)
{
super.paintComponent(g);
Image immagineGrafico=createImage(grafico.pannelloGrafico.getWidth()
,grafico.pannelloGrafico.getHeight());
Image immagineVolumi=createImage(grafico.pannelloVolumi.getWidth()
,grafico.pannelloVolumi.getHeight());
Graphics2D imgGrafico=(Graphics2D)immagineGrafico.getGraphics();
Graphics2D imgVolumi=(Graphics2D)immagineVolumi.getGraphics();
grafico.draw(imgGrafico,imgVolumi,mouseX,mouseY);
((Graphics2D)grafico.pannelloGrafico.getGraphics()).drawImage(immagineGrafico,0,0,this);
((Graphics2D)grafico.pannelloVolumi.getGraphics()).drawImage(immagineVolumi,0,0,this);
}
grafico's JPanels are added this way in the ChartWindow's constructor
grafico=new Grafico()
................
add(grafico.pannelloGrafico);
add(grafico.pannelloVolumi);
Tell me if you need more information, thank you very much :-)
You need to override the JPanel's paintComponent rather than the chart window's if you want to paint on them. What happens is that everytime the JPanel paints itself the default paint would overwrite your images.
class PanelloVolumi extends JPanel{
//some code
public void paintComponent(Graphics g){
//paint one image here
}
}
And do the same for the other JPanel.
Then add instances of these JPanels to your Applet.
I have an assignment to create a paint program in Java. I have managed to create something but not exactly what I wanted.
My problem is that I cannot create a JFrame in my IDE(NetBeans 7.0.1) from the options that the IDE gives me, and call the paint classes correctly.
To be more specific I want to press a button from one panel(ex. Panel1) and paint in Panel2,in the same frame.
That's the calling of the class:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
PaintFlower102 f = new PaintFlower102();
}
Part of Class:
super("Drag to Paint");
getContentPane().add(new Label ("Click and Drag"),BorderLayout.SOUTH);
// add(new JButton("Brush 20"),BorderLayout.NORTH);
addMouseMotionListener( new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent event) {
xval=event.getX();
yval=event.getY();
repaint();
}
});
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(PaintFlower102.DISPOSE_ON_CLOSE);
}
public void paint(Graphics g) {
g.fillOval(xval, yval, 10, 10);
}
The problem is that if I do not put the extend JFrame in the class this doesn't work. And if I do, it creates a new frame in which I can draw.
Suggestions:
Don't ever paint directly in a JFrame except under rare circumstances of absolute need (this isn't one of them).
Instead paint in a JPanel or JComponent or other derivative of JComponent.
Paint in the class's paintComponent(Graphics g) method, not in paint(Graphics g).
Read the Java tutorials on this as it's all explained well there. Check out Trail: 2D Graphics and Performing Custom Painting.
I might be wrong, but I think that you need to include super.paintComponent(g), and override the paintComponent method like Hovercraft Full Of Eels said.
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw Oval
g.fillOval(xval, yval, 10, 10);
}
I'm just playing with Swing and I'm working on a really simple Swing component. I have a component inherited from JComponent class and its UI inherited from ComponentUI. The paint() method looks like this:
public void paint(Graphics g, JComponent c) {
int x = c.getX();
int y = c.getY();
c.setBounds(x, y, 100, 25);
int width = c.getWidth();
int height = c.getHeight();
Rectangle r = g.getClipBounds();
g.fillRect(0, 0, 10, 10);
g.drawString("Baf!", 3, 3);
}
But it is totally impossible to get another value of r.height than 1. The component is width as given, but height allways one point only. Has anybody else experiences with suchlike components? Unfortunately there is no any easy tutorial. All tutorials are incomprehensible complicated (or obsolete).
It seems, that the layout manager resizes this component allways to 1 height (regardless to minimal value).
Never invoke setBound() in a painting method. That is a job for the layout manager, not your painting code.
I would guess the main problem (other than Heisenbug's points) are that you don't give you component a size. This is done by overriding the getPreferredSize() to return a size appropriate to your component.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
There are several problems with your code:
For what concern the class extending JComponent:
public void paint(Graphics g, JComponent c) {}
isn't a valid signature so you are not overriding the method paint, but create a new paint method.
you should override paintComponent(Graphics g) method instead of paint.
Because of you are extending a JComponent you need first call super.paintComponent(g) inside your overridden paintComponent method:
public class JPanelExtended{
public void paintComponent(Graphics g){
super.paintComponent(g);
...
}
}
For what concern the class extending ComponentUI, you should even there call explicitly the method paint on the super class:
public void paint(Graphics g, JComponent c) {
super.paint(g,c);
}
EDIT:
a little suggestion: when you want to override a method, it's quite useful to put the #override notation before the signature:
#Override
public void superMethodToBeOverridden(){}
This way you will be notified by the compiler with an error message, in the case you are defining a new method and not overriding an existing one.
I have a JFrame on which I am using overriding the paint method to display some graphics. I also want to add a JPanel to it that will show up on top of the graphics. Right now, all I see is the graphics created from JFrame paint method.
Here's my JPanel:
public class NoteDraw extends JPanel {
public NoteDraw() {
setSize(200, 100);
setBackground(Color.BLACK);
}
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, 100, 100);
}
}
Here's my JFrame:
public class ui extends JFrame {
public void paint(Graphics g) {
//do some drawing here...
}
}
Here's my main:
public class Main {
static ui main_gui = new ui();
public static void main(String[] args) {
NoteDraw note = new NoteDraw();
main_gui.getContentPane().add(note);
main_gui.setVisible(true);
}
}
You should NEVER override the paint() method of a JFrame (unless you really know what you are doing). This method is responsible for all the optimized painting behaviour of Swing.
Custom painting should always be done by overriding the paintComponent() method of a Swing component like you have done on your NoteDraw panel.
The reason the code in the paint method doesn't show is because the NoteDraw panel is opaque and therefore the panel paints over top of the Graphics code in your paint method.
So the solution is to move the Graphics painting code to the NoteDraw panel.
Or if you are trying to create some kind of background image for your frame then you can try using the Background Panel.
Or if you truly do need custom painting then you create a background panel and override the paintComponent() method. Then you set the layout to a BorderLayout and add this panel to the frame. Then you make your NoteDraw panel non-opaque and add it to the custom background panel. Now the background will show through on the NoteDraw panel.
Remember to call super.paint() when you override your paint() method.
This way, you still use the behavior defined in the parent class, and you can add your modifications safely.
Resources :
sun.com - Using the Keyword super
I'm using a custom JLayeredPane.
I have several Shapes which needed to be drawn on different layers in the JLayeredPane.
To test this I create a JPanel and ask its graphics. Then I draw a test rectangle on that JPanel (preparing the graphics) and in my paintComponent method from the JLayeredPane I finally draw everything. But this fails (NullPointerException).
public class MyCustomPanel extends JLayeredPane {
// test
JPanel testpane;
Graphics g2;
// test
// constructor
public MyCustomPanel() {
testpane = new JPanel();
this.add(testpane, new Integer(14));
g2 = testpane.getGraphics();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g2.drawRect(10, 10, 300, 300);
}
}
// run:
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
// at view.MyCustomPanel.paintComponent(MyCustomPanel.java:65)
Why can't I draw on such a JPanel from within my JLayeredPane? I can draw directly on my JLayeredPane from within my paintComponent method but that's on the default Panel from the JLayeredPane. I need to create and draw on several layers which are added in my JLayeredPane.
What am I doing wrong? :s
You should use g2 casting the Graphics that is passed to you:
Graphics2D g2 = (Graphics2D)g;
Why don't you try decoupling things?
class InnerPanel extends JPanel
{
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.drawRect(....);
}
}
class MyLayered extends JLayeredPane()
{
MyLayered()
{
this.add(new InnerPanel(), 14);
}
}
this makes more sense..
Also because you are trying to do something that doesn't agree with Swing behaviour.
Swing will care by itself to call the appropriate paint methods over things that must be displayed, and to go with this protocol you should tell Graphics objects what to draw when Swing asks it to your objects (calling the paint) method, not when you want to do it.
In this way whenever Swing wants to draw your JLayeredPane you just draw things on a Graphic object of other things without considering that Swing will call their appropriate methods when it's the right time to do so.
In conclusion: you can't draw something on a Graphic object when you want it. You can do it just inside methods invoked by Swing, because otherwise Graphics of these objects doesn't mean anything
The variable g2 is probably null because you set it in the constructor, not when drawing. Instead, use the "g" that was passed in.
You can only get a legitimate Graphics from a component that is currently being painted. Otherwise, it's not valid. At the point you're requesting it, the MyCustomPanel() isn't being displayed, and neither is testpane.