Java Paint Problem - java

Ok I'm wondering why the code below will not display the JLabel.
MyPanel is getting added correctly to a JFrame and everything because it all displays but will not draw the JLabel. Any help is appreciated.
public class MyPanel extends JPanel {
private Root root;
...
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
root.paint(g2);
}
}
class Root {
private Node1 node1;
...
public void paint(Graphics g) {
node1.paint(g);
}
}
class Node1 {
...
public void paint(Graphics g) {
JLabel jtp = new JLabel();
jtp.setLocation((int) x, (int) y);
jtp.setSize((int) width, (int) height);
jtp.setLocation(40, 40);
jtp.setSize(40, 40);
jtp.setText("Hello world");
//jtp.setVisible(true);
jtp.paint(g);
}
}

I suggest that you don't add Components to a Container in a paint method as 1) you do not have absolute control when or even if a paint method will be called and 2) paint and paintComponent have to be as blazing fast as possible, and this is not the time or place to update a GUI. 3) Since paint is often called many times, you will be adding components many times to your container, and all out of your direct control.
Also, while you're adding a component into Root (whatever Root is since it doesn't extend JComponent, JPanel, or similar) in the paint method, the Root object is never added to anything else that I can tell, and so it makes sense that nothing "added" to a component that is not added eventually to a top-level window will be visible.
Bottom line: I think you need a gui re-design as your solution. If you tell us more about it we can help you with it. Next we'll need to talk about use of layout managers and why setting absolute position and sizes of components is usually frowned on.
If anything I say is confusing, please ask for clarification, or if anything is wrong, please help me correct it!

You should not create your JLabel inside the paint method - instead, create it once when initializing your MyPanel. Your label is kind of a renderer component for your nodes, which in principle is a good thing. You may look how the renderers for JTable, JList, JTree work.
In your case, don't set the location of your label (it does not change anything, since it's paint-method expects its graphics object to be oriented by its own upper left corner), instead translate the Graphics-context:
Graphics copy = g.create((int)x, (int)y, (int)width, (int)height);
jtp.paint(copy);
(Graphics2D has some more fancy methods for shifting, rotating, scaling the context, too.)
Other than this, I don't see any problems. Make sure your Node1.paint() method gets actually called by putting some System.out.println() in there.

Related

Transparent JPanels in JLayeredPanes

I would like to have a JPanel transparent or fully invisible (not like panel.setVisible(false) but more something like opacity = 0.0f) which will then be put into a JLayeredPane, to make the bottom layer visible.
You know ask why. I need this to use the build in Layouts like BorderLayout and so on because I dont want to make my own layout and so on.
What I then tried was first of all the Implementation of a transparent JPanel which was more or less easy by doing just this:
public class ClearPanel extends JPanel {
private static final long serialVersionUID = 706731555521208974L;
private float opacity = 0.0f;
private Shape shape = null;
public ClearPanel() {
setBackground(new Color(0,0,0,0));
setOpaque(false);
}
public ClearPanel(float opacity) {
setOpaque(false);
setOpacity(opacity);
}
public ClearPanel(float opacity, Shape shape) {
setOpaque(false);
setOpacity(opacity);
setShape(shape);
}
// Here usually are some random getters and setters
#Override
public void paintComponent(Graphics go) {
Graphics2D g = (Graphics2D) go;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(shape == null) shape = g.getClipBounds();
g.setColor(new Color(getBackground().getRed(), getBackground().getGreen(), getBackground().getBlue(), 255*opacity));
g.fill(shape);
}
}
So what this does is usually creating a more or less transparent Version of the JPanel. And it also works if don't use a layout but fixed Positions and Sizes but when you program something bigger it would be way easier to use available solutions.
The problem comes now:
When I try to use this in a JLayeredPane with the possibility to see the bottom layer, nothing happens, although it definetly should I need this because I want a bottom panel with a background Image and then I want some stuff ABOVE that panel. And I thought, ok I know Layers from Gimp, maybe Java offers this, so thats why I think that JLayeredPane could help.
Do you know a possibility to make the bottomlayers shine trough an other layer although you use a fixed layout or do you think, I will need to make my own layout or use public void paint(Graphics g) of JFrame to paint them step by step ?
Thanks in advance
PS: Sry for my English but after one day of try and error I can't write anything "perfect" any more...

Drawn graphics flicker and then disappear when resizing window

The goal here is that I can click a color and shape, then two points on the figuresPanel. That colored shape is filled in on the figuresPanel, and I can add shapes on top of each other etc. I also need the current date to be displayed in the corner of the figuresPanel, on top of all the painted shapes. I am able to create shapes (though they always cover the date) no problem, but whenever I resize or minimize the window, all the painted shapes disappear. I've tried implementing quite a few different methods from Graphics (update, paint, redraw, etc.) and haven't found one that corrects this issue. I thought paintComponent() would take care of all that, but apparently not. Feel free to point out anything that could be implemented in a better way, always happy to learn something new.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawFigures();
figuresPanel.add(dateLabel, c);
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(800, 600));
}
private void addFigure(Figure figure) {
figureList.add(figure);
listArea.append(figure.toString() + "\n");
figure.fill(getGraphics());
}
private void drawFigures() {
for (Figure f : figureList) {
f.fill(getGraphics());
}
}
I would suggest a few things that might help you.
In your method drawFigures() instead of using getGraphics(), why don't you pass the instance of Graphics in paintComponentMethod as a parameter to the method and use it to draw the object. This will make sure that you are drawing on the same instance of the Graphics that you are using to paint.
In your method addFigure(Figure figure) I would suggest you remove the line figure.fill(getGraphics());, to draw the object completely. Instead in your mouseClicked(MouseEvent event) method after your switch statement insert:
revalidate();
repaint();
This should actually take care of the drawing of the objects are done exactly on the same Graphics object that is being used to display the components.
I hope that this shall be helpful.

Why is paintComponent() run even though no one calls it?

I was wondering if someone could explain how/why paintComponent() is called right after all the statements in main() are run. The reason I am confused is that there is no explicit call to painComponent() but it is run regardless.
// JComponent is a base class for custom components
public class SimpleDraw extends JPanel {
public static void main(String[] args) {
SimpleDraw canvas = new SimpleDraw();
JFrame f = new JFrame("SimpleDraw"); // jframe is the app window
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400); // window size
f.setContentPane(canvas); // add canvas to jframe
f.setVisible(true); // show the window
}
// custom graphics drawing
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g; // cast to get 2D drawing methods
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // antialiasing look nicer
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(32)); // 32 pixel thick stroke
g2.setColor(Color.BLUE); // make it blue
g2.drawLine(0, 0, getWidth(), getHeight()); // draw line
g2.setColor(Color.RED);
g2.drawLine(getWidth(), 0, 0, getHeight());
}
}
Here is a decent little write-up on how paintComponent is handled.
Excerpt:
Who calls paintComponent
... This method is called because the user did
something with the user interface that required redrawing, or your
code has explicitly requested that it be redrawn. Called automatically
when it becomes visible When a window becomes visible (uncovered or
deminimized) or is resized, the "system" automatically calls the
paintComponent() method for all areas of the screen that have to be
redrawn. Called indirectly from a user-defined listener via repaint() ...
There's more in the write-up as well as some reference links, which, unfortunatelly, are all broken.
I also found this blog post which discusses painting/drawing in Java from a very basic point of view. Check out the first paragraph:
Why do we put all our graphical drawing code into a paintComponent()
method? It seems odd, since it would seem we should be able to simply
stick some simple graphics commands into our main() method in a Java
application and just get the drawing done. Where does paintComponent
come from? If we never call it in our code, how does it get executed?
In the Java docs you actually have to read up on paint to start getting an idea of what going on. The paintComponent documentation is not very helpful.

Redrawing graphics in Java

I'm just getting into graphics in Java and I have a problem. I created a JFrame window (NetBeans Designer) with a JPanel panel and I drew some graphics on it. Then I added a JButton that changed a variable, which would change the X position of a square on JPanel.
On button press this code would execute:
drawObject.setX(150);
drawObject.repaint();
drawObject is an instance of this class:
public class sola extends JPanel {
private int x = 10;
#Override
public void paintComponent(Graphics g){
super.paintComponents(g);
super.setBackground(Color.WHITE);
g.setColor(Color.ORANGE);
g.fill3DRect(x, 160, 100, 50, true);
}
public void setX(int xX){
x = xX;
}
}
Now, when I press the JButton, the rectangle does move to the new position, however it is still visible in the old position. Only when i resize the window does it refresh and the old rectangle disappears. How can i solve this problem, so that when i press the button, the rectangle is only visible in the new position?
It's
super.paintComponent(g);
not
super.paintComponents(g); // note the s at the edn
Big difference between the two! The first one tells your JPanel to do all the housekeeping functions normally performed by the paintComponent method, including repainting the background (key for your project). The second, the one your calling doesn't do any of the above functionality. So my advice is to get rid of the trailing s in your super call.
You can use the following methods from JComponent: ( http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html )
void repaint(long tm, int x, int y, int width, int height)
Adds the specified region to the dirty region list if the component is showing.
void repaint(Rectangle r)
Adds the specified region to the dirty region list if the component is showing.
You can call those before redraw()
You could use repaint() method to do tis.
If you use the paintComponent() on the panel. You should IMHO take care of the painting in the whole panel. There is no code in your example which takes care about deleting the old painted rectangles.
What i recommend is creating an own Component for your rectangles. (You could extend from Component) then you can override the paintComponent method of these classes as you did in your panel. Because the Panel should act as a container component. Not as drawing the rectangles itsself.
Know add instances of these components to a normal JPanel. This should then update as expected.

Java Swing NullPointerException when drawing

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.

Categories