I am working on some NetBeans platform app, and i am currently stuck on some detail in Visual Library. Ok, here is problem. I have Visual Editor for my app, with pallet, scene and everything works great, just there is a problem when i am dragging icons from pallet to scene. They are not displayed during drag event, i would like to create that effect, can someone help on this?
I do this in two phases:
1) Create a screenshot (an image) of a palette element. I create the screenshot lazily and then cache it within the view. To create the screenshot, you can use this snippet:
screenshot = new BufferedImage(getWidth(), getHeight(), java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE);// buffered image
// creating the graphics for buffered image
Graphics2D graphics = screenshot.createGraphics();
// We make the screenshot slightly transparent
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f));
view.print(graphics); // takes the screenshot
graphics.dispose();
2) Paint the screenshot on the receiving view. When the drag gesture is recognized, find a way to make the screenshot available to the receiving view or one of its ancestor (you could make it available on the frame or its content pane, depending on where you want to make the screenshot drag available) and paint the image within the paint method. Something like this:
a. Make the screenshot available:
capturedDraggedNodeImage = view.getScreenshot(); // Transfer the screenshot
dragOrigin = SwingUtilities.convertPoint(e.getComponent(), e.getDragOrigin(), view); // locate the point where the click was made
b. As the mouse is dragged, update the location of the screenshot
// Assuming 'e' is a DropTargetDragEvent and 'this' is where you want to paint
// Convert the event point to this component coordinates
capturedNodeLocation = SwingUtilities.convertPoint(((DropTarget) e.getSource()).getComponent(), e.getLocation(), this);
// offset the location by the original point of drag on the palette element view
capturedNodeLocation.x -= dragOrigin.x;
capturedNodeLocation.y -= dragOrigin.y;
// Invoke repaint
repaint(capturedNodeLocation.x, capturedNodeLocation.y,
capturedDraggedNodeImage.getWidth(), capturedDraggedNodeImage.getHeight());
c. paint the screenshot in paint method:
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.drawImage(capturedDraggedNodeImage, capturedNodeLocation.x,
capturedNodeLocation.y, capturedDraggedNodeImage.getWidth(),
capturedDraggedNodeImage.getHeight(), this);
}
Instead of calling repaint() and perform the painting in the paint() method, you could invoke paintImmediately() as the mouse moves but the rendering will be a lot poorer and you could observe some flickering, so I would not recommend that option. Using paint() and repaint() provides a better user experience and a smooth rendering.
If I hear you well, you are creating a graphical editor of some sort, with drag and drop of elements, and you want to create an effect during that drag and drop?
If so, you basically need to create a ghost of the object you're dragging and attach it to the move of the mouse. Easier said than done, of course, but you get the gist.
So what you need is to take the image of what you're dragging (it shouldn't be too much trouble) and move it according to the position of the mouse (think of substracting the relative position of the mouse cursor in the object you're dragging).
But I think that kind of code is available somewhere. I'd advise you to look that up :
http://free-the-pixel.blogspot.fr/2010/04/ghost-drag-and-drop-over-multiple.html
http://codeidol.com/java/swing/Drag-and-Drop/Translucent-Drag-and-Drop/
Hope that helps you!
Related
I am creating a Java game, and in this, I have a plane that can be moved around by the user, however if the plane hits any of the sides, it should explode - meaning there should be an explosion at that location. I used links such as: Why gif animation doesn't animate when using it in paintComponent()? and other ones to find out how to animate a gif, however, my code doesn't work.
Here is the relevant code:
ImageIcon ii = new ImageIcon(this.getClass().getResource("explosion.gif"));
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(ii.getImage(), planeX, planeY, this);
System.out.println("drawn");
Although "drawn" is being printed out on the console, the explosion gif doesn't load. I checked the file name and it was correct. However, I did use the same gif somewhere else in my code and it worked there, so is there something that prevents having a gif being used twice in Java?
Here is my entire paintComponent() method:
super.paintComponent(g);
setFocusable(true);
requestFocus();
background = new ImageIcon("bg.png").getImage();
g.drawImage(background, -6, 0, 700, 700, null); //background of JPanel
if (!hit) g.drawImage(plane, planeX, planeY, planeLen, planeHei, null); //only draw plane if not exploded
else if (count == 0)
{
ImageIcon ii = new ImageIcon(this.getClass().getResource("explosion.gif"));
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(ii.getImage(), planeX, planeY, this); //doesn't work
System.out.println("drawn"); //printed
}
title = new ImageIcon("title.png").getImage(); //transparent, is drawn
g.drawImage(title, -9, 20, 700, 218, null);
title2 = new ImageIcon("title2.png").getImage(); //transparent, is drawn
g.drawImage(title2, 10, 245, 670, 20, null);
I have checked title and title2 and they are transparent, meaning that the explosion should be seen. I even tried it below those two images, and the explosion still is not visible. I am using JButtons and KeyListeners on this panel as well.
Please let me know if I should add anything else, and thank you in advance!
You should always pass this as the final argument to drawImage in a painting method. If an image has multiple frames, or the image is loaded in the background, this tells the component to paint itself again as more of the image becomes available.
Painting of components happens frequently. It is controlled by the system, not just by code calling the component’s repaint methods. In fact, it’s common for painting to happen many times per second. Many system events beyond a programmer’s control can trigger painting, such as a user moving a window, or another window moving, or even the user moving the mouse.
For this reason, painting should not perform slow operations like loading files. Move the loading of your images out of your painting method, and into the class’s constructor. Store the Image objects in private fields, where paintComponent can use them again and again without reloading them for every painting run.
Since the timing of painting is beyond your control, it is important that you never change the state of a component in a painting method. Move setFocusable and requestFocus out of your paintComponent method. Those calls should be in the code that builds your component and adds it to a window.
Finally, be aware that loading images from files will not work if you ever package your application in a .jar file. A .jar file is a single compressed archive; the entries in it are not files anymore, they’re just sequences of bytes inside the archive. Loading all files using getResource will address this, since getResource looks in every .jar file in the classpath.
Never mind, I had to make a duplicate of "explosion.gif". It works fine now!
However, please let me know if there is another way of doing this, much faster AND efficiently. Thanks!
I need to draw strings on a painted image. The project I am working on also requires the string to move around the screen at least 22 times in a second. Hence, its position can be anywhere on the image. So, redrawing the image with the string on it won't be possible as I feel there are better ways of doing this and that would unnecessarily consume resources redrawing the whole image. I have also tried using panel.getGraphics and then painting on the image but then all the drawn text is all over the screen(the code is below). I was wondering if someone could guide me in the right direction on how I can draw text over a paintedImage but it also needs to reset its position when required. The code I have tried that doesn't reset its previous position is below.
Original Panel with the Image:
public class PanelForImages extends JPanel{
private BufferedImage image;
public PanelForImages(File image) throws IOException{
//this.image = image;
//URL resource = getClass().getResource("so2.jpg");
this.image = ImageIO.read(image);
}
#Override
public void paintComponent(Graphics g){
//super.paint(g);
//super.paintComponents(g);
super.paintComponent(g);
//g.drawImage(image, 3, 4, this);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
g.drawString("HELLOOOOOOOOOOOOOOOOOOOOOOOO", 400, 400);
//repaint();
}
}
Method with which I am trying to draw the string over the image.
public void drawFixationsOnFrame(GazeData gazeData){
Graphics g = this.panelForImages.getGraphics();
g.drawString("TEsting 123", (int)gazeData.smoothedCoordinates.x, (int)gazeData.smoothedCoordinates.y);
g.dispose();
jF.revalidate();
}
I have also tried making a new panel and then adding it to the current one but it doesn't seem to work. I am not sure how I can make it so it comes on top of the panelForImages without it hiding panelForImages.
The project I am working on also requires the string to move around the screen at least 22 times in a second. Hence, its position can be anywhere on the image. So, redrawing the image with the string on it won't be possible as I feel there are better ways of doing this and that would unnecessarily consume resources redrawing the whole image.
Then don't redraw the whole image. The JComponent repaint(...) method has an override, one that allows you to repaint only a select rectangle (check out the JComponent API for more on this). You will want to move the image in a Swing Timer, then repaint its old location (to get rid of the old String image) and repaint its new location. If you need the dimensions of the String, then use FontMetrics to help you get its bounding rectangle.
I note that your code has two other issues that are worrisome, some of it commented out:
Calling getGraphics() on a component to get its graphics component and draw with it -- you don't want to do this as this will result in a Graphics object that is short-lived risking broken images or a NPE
Calling repaint() from within the paintComponent. This is a bad and completely uncontrolled way of doing animation. Instead use a Swing Timer so you can have complete control of the animation and so you don't use paintComponent for something it was not intended to be used for.
Making a paint-like application that works by saving mouse points in an arraylist. My idea is to have a "points" arraylist with all the previously drawn stuff, and a "temp" arraylist to get and modify the current brush stroke the user just entered. This is necessary as the user can change the color and size, so my idea is to modify the current brush stroke based off what buttons have been pressed, then add that brush stroke to the rest of the picture. I searched around StackOverflow and found some code but cant get it to work how I want to (assuming I found the right code).
#Override
public void paintComponent(Graphics g1) {
super.paintComponent(g1);
final Graphics2D g = (Graphics2D)g1.create();
try {
g.setColor(brushColor);
for (Point point : tempArrayList){
g.fillOval(point.x, point.y, brushSize, brushSize);
}
} finally {
g.dispose();
}
The problem is that I need to clear the tempArrayList for the next brush stroke, which I can do when they change the color/size, but then it erases what was previously there. I am starting to think that I don't even need the "points" arraylist as descibed above because I was hoping that the g1 graphic would just save what the g graphic created.
I guess I just need to figure out how to add the g graphic to g1
Painting is controlled by the Swing API, there is a expectation that whenever paintComponent is called, you will repaint the entire state of the component (as part of your component might have been damaged due to some system event), so the short answer is, no, you can't...however....
You Could...
Paint to a BufferedImage instead and paint the BufferedImage when paintComponent is called
You Could...
Establish a series of "paintable" objects which contain information about what is to be painted and how it is to the painted, including the brush stroke, stroke color and fill color.
These would then be added to some kind of List and "painted" when the paintComponent method is called
Check out Custom Painting Approaches for exampled of painting from:
A List of objects
A BufferedImage.
The examples show how to draw Rectangles of different colours.
I'm attempting to make a Java Applet that will allow me to draw a graph data structure in a canvas. I will do this by clicking where I want to create nodes, and clicking the nodes to connect them. The problem is I cannot get the paint() method to behave correctly. I add new nodes to the graph (and squares on the canvas) inside the mousePressed(MouseEvent e) method using,
Graphics g = this.getGraphics();
g.setColor(Color.blue);
g.fillRect(e.getX(), e.gety(), 40, 40);
Everything works fine, until I resize the window, and then all the filled rectangles vanish. I overrided the paint method to just an empty method, but the same thing still happens. I can't add the fillRect commands inside paint() because I don't know what rectangles exist until the user interacts with it using the mouse.
How can I use g.fillRect() inside the mouse listener methods and make them stick?
The problem is the place you're drawing to isn't persistant. At any moment, you can lose everything you've drawn to it. The paint(Graphics) method is called when this happens. You'll either need to repaint the entire picture every time this happens, or you'll need to set aside a canvas to draw to and copy the contents to your applet's Graphics as needed.
Here's how to create and draw to an image:
http://java.sun.com/docs/books/tutorial/2d/images/drawonimage.html
Then, in your paint method, use your Graphics' drawImage(...) method to display the image you've created.
I don't know if I'm reading this correctly, but why not just store the location of the last click in a variable to be painted later, when the paint() method is called?
You've got to override the window resize action listener and call repaint inside of it.
The Graphics is temporary. When a region gets dirty, it will be repainted.
The best way is to create a BufferedImage, paint to it on mousePressed and call repaint.
When paint is called, draw the Image onto the passed Graphics Object. This way you don't need to store the Rectangles and you got a buffer which will improve performance.
How can I draw something in JPanel that will stay the same and not be repainted, I am doing a traffic simulation program and I want the road to be drawn once because It will not change.
Thanks
I'm not sure you actually want your road to never be repainted - repaint events fire (for example) when your window is resized, or when it becomes visible following another window obstructing it. If your panel never repaints then it'll look peculiar.
As far as I remember, Swing will only fire appropriate paint events for these circumstances, so you should be OK following the usual method of subclassing JPanel with a suitable override:
public class RoadPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// your drawing code here
}
}
If you cache your road into an image or another graphics format (to save calculating the display data multiple times) once drawn once, this might save you some time on subsequent paints.
To my knowledge, no, unless there is a trick with transparent overlays.
Most graphical applications I saw (and did) just re-draw the whole panel on each repaint. Now, you can do that once, in a graphic buffer, and then just paint the whole background at once, quickly, by copying the graphic buffer to the JPanel. It should be faster than calling all graphical primitives to draw the road.
Or, the way some 2D games do, perhaps paint it once and update the moving parts, like sprites: it needs to erase the old place used by the sprites (restore the background there) and re-draw the sprites at the new place. So you still have a copy of the road in a graphic buffer but instead of re-drawing it whole each time, you update only some small parts. Can be slightly faster.
The component will need to be repainted every time that the panel is obscured (ie frame minimized/another window put on top). Therefore drawing something only once will not work as you want it to. To make parts that do not change be drawn more efficiently you can draw them once to a 'buffer' image, and then just draw this buffer each time that the panel or component needs to be redrawn.
// Field that stores the image so it is always accessible
private Image roadImage = null;
// ...
// ...
// Override paintComponent Method
public void paintComponent(Graphics g){
if (roadImage == null) {
// Create the road image if it doesn't exist
roadImage = createImage(width, height);
// draw the roads to the image
Graphics roadG = roadImage.getGraphics();
// Use roadG like you would any other graphics
// object to draw the roads to an image
} else {
// If the buffer image exists, you just need to draw it.
// Draw the road buffer image
g.drawImage(roadImage, 0, 0, null);
}
// Draw everything else ...
// g.draw...
}
What I do is set a boolean value to whether or not a certain part needs to be redrawn. Then, in the paintComponent() method I can check the value and redraw the certain thing, or not.
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (drawRoad) {
drawRoadMethod(g);
}
drawTheRest(g);
}
Kinda like that.