I have a piece of code that scales a JPanel in the paintComponent() method as follows:
g2d.translate(this.getWidth()/2, this.getHeight()/2);
g2d.scale(scale, scale);
g2d.translate(-this.getWidth()/2, -this.getHeight()/2);
I expected this to scale the cursor of the JPanel as well, however it does not. I tried creating a custom cursor with a larger image, but it automatically re-sizes it to 32x32. Is there a system-independent way of resizing a cursor to match the scale of my JPanel?
As far as I know, you may 'suggest' differently sized cursor images, but the operating system always has the final say. See http://docs.oracle.com/javase/7/docs/api/java/awt/Toolkit.html#getBestCursorSize(int, int)
Related
I have customized a cursor on a label component called ageLabel using the following code
ageLabel.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(new javax.swing.ImageIcon(getClass().getResource("/images/image1.jpg")).getImage(),new Point(5,5),"custom cursor"));
It works fine anyway but what I want to do is increase the size of the customized cursor. I have tried changing the point to (10,10) but the cursor size wouldn't change. I also tried changing the dimensions of the image that I used ,it still wouldn't change. I have searched through the internet but to no avail. Is It possible to resize the cursor in anyway? If it is how do I do that?
Thanks in advance for all helps.
Java's Image class has a built in function for scaling.
Documentation: https://docs.oracle.com/javase/7/docs/api/java/awt/Image.html#getScaledInstance(int,%20int,%20int)
My approach to the problem:
Split the line up into many to make it look a bit nicer (not necessary).
Add an extra method call to scale the image up.
Potential Solution:
URL imageResource = getClass().getResource("/images/image1.jpg");
ImageIcon imageIcon = new ImageIcon(imageResource);
Image image = imageIcon.getImage();
// This is the important line that scales the image up!
Image scaledImage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
Toolkit toolkit = Toolkit.getDefaultToolkit();
Cursor cursor = toolkit.createCustomCursor(scaledImage, new Point(5, 5), "Custom Cursor");
ageLabel.setCursor(cursor);
Afterthoughts:
Remember to replace newWidth and newHeight with the values you want.
After you get it working, I'd even go further and extract some of this code into methods.
You might need to tweak your imports a bit if it isn't compiling.
I haven't tried running this code so I don't know if it works.
I'm drawing to a Canvas using Graphics through a BufferStrategy with lines such as
g.drawImage(bufferedImage, x, y, null);
I currently have this running undecorated in a JFrame, 1920x1080p as per the resolution of my laptop. I'm curious as to whether there is any way to alter the resolution of the Graphics rendered, particularly lowering resolution so as to increase efficiency/speed, or fitting to another differently sized screen. There are many objects being rendered with a camera and the game runs fairly well, but any usable alterations to the resolution would be useful as optional in my settings.
I've researched this and found no good answers. Thank you for your time.
(Resolution changes such as for printing.)
Best to use a drawImage with a smaller image, and scaled width and height.
Now, you could even render all in your own BufferedImage using a Graphics2D with BufferedImage.createGraphics and scale afterwards. Not so nice for text or printing.
Or use Graphics2D scaling:
For complex rendering:
g.scale(2.0, 2.0);
... // Draw smaller image
g.scale(0.5, 0.5);
As you might imagine this probably does not help in memory consumption, apart from needing smaller images. At one point all pixels of the image must be given in the devices color size. 256 colors gif, or 10KB jpg will not help.
The other way around, supporting high resolutions with tight memory also exists. There one might use tiled images, see ImageIO.
Important is to prepare the image outside the paintComponent/paint.
You might also go for device compatible bit maps if you make your own BufferedImage, but this seems circumstantial (GraphicsEnvironment).
I've read that JPanel has a double buffering system, but I've also seen people manually create their own back buffer using BufferedImage, which allows the user to add to the image before actually rendering.
How does the JPanel double buffering work, and why would someone create their own back buffer if JPanel already has double buffering? What is an example of a time where BufferedImage as your buffer would be needed/recommended?
From what I've seen it's usually because:
They are already loading an image which serves as a background image and wish to draw on top of that (they probably could just draw the image, leaving it to be hardware accelerated for future renders while drawing everything else using the same Graphics object used to call drawImage)
Because they wish to have a simple way to scale their graphics as their panel resizes with drawImage(Image, 0, 0, panelWidth, panelHeight, ImageObserver) and don't wish to do the extra work on calculating dynamic drawing coordinates for the graphics based on the panel's current dimensions (although this leads to not so good looking graphics, and if the scaled image is not cached per resize there could be performance issues as well).
Because it's old code in the days before Swing was double buffered, or people following code from old books.
The graphics of what you draw in the double buffered painting methods (like paintComponent(Graphics)) will be visible all at once when all of the relevant painting methods are complete. That being the case there's no reason to use a BufferedImage as a way to manually ensure all the Graphics get shown at once.
I am making a grid-based game that resizes its grid as the window size changes. I also may apply color filters for lighting effects in the future. I am concerned about the performance of this code, which draws to the screen an image in one of the grid squares.
public void drawSquares(Graphics g){
ListIterator<Viewport> iterator = vp.listIterator();
while(iterator.hasNext()){
Viewport v = (Viewport)iterator.next();
BufferedImage img = v.getSqView().getImage();
Rectangle b = v.getPixRect();
g.drawImage(img, b.x, b.y, b.width, b.height, v.getSqView().getBackground(), null);
}
return;
}
What this code does is get the image (stored in img) and get the pixel rectangle it needs to fit in (stored in b), then draw it in the space alloted via drawImage.
drawImage says that it scales images on the fly - which means that all images are being rescaled every frame. But the window is only resized rarely, so this must waste lots of processor time doing the same thing over and over again.
Now I saw this and decided that I would just update all the images upon resizing once, then store the result and be able to draw normally.
Like this:
public void resizeImage(int width, int height){
BufferedImage resized = new BufferedImage(width, height, img.getType());
Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(img, 0, 0, width, height, 0, 0, img.getWidth(), img.getHeight(), null);
g.dispose();
img = resized;
}
This doesn't work - I think it has something to do with img = resized. I just lose all the images with this code.
I have a few questions then.
What is the performance cost of repeatedly scaling with drawImage? Is it any different even if the window has not been resized in between frames?
How should I get the second code snippet to work? What is going wrong?
If I apply a lighting filter to a tile, will that eat up tons of processor time as well if I run it each frame? (Think 225 or so small images on a 800x800 or so display)
What is best practice for applying lighting filters? I am planning on overlaying on the whole map a pitch black filter, then exposing the areas around light sources.
Thanks for any help with this!
Resize the frame of this Grid to get a subjective feel for the latency. Use the approach shown here to measure the latency. Verify your findings in a profiler.
There's no reason you shouldn't be able to resize the elements of a List<Image> as you propose, but add() the resized instances to a new list as they are created.
What is the performance cost of repeatedly scaling with drawImage? Is
it any different even if the window has not been resized in between
frames?
You should always measure, but there is definitely a performance cost here, even if the window is not resized, because as the Javadoc says, there is no caching behind this drawImage method. The cost also depends on the frame rate.
How should I get the second code snippet to work? What is going wrong?
The second code snippet should be OK, I think the problem is somewhere else. Try reproducing the problem in a "small but complete" program, and post another question if you still see the problem.
If I apply a lighting filter to a tile, will that eat up tons of processor time as well if I run it each frame? (Think 225 or so small images on a 800x800 or so display)
You should always measure :)
What is best practice for applying lighting filters? I am planning on overlaying on the whole map a pitch black filter, then exposing the areas around light sources.
You can use an AlphaComposite for this.
I have image inside the JPanel. I would like to rotate the image. Is it possible to rotate the JPanel using Graphics, Image is rotatable, Just out of curiosity is it possible to rotate JPanel ?
Yes! This is possible and fairly straightforward too. I haven't done rotations but I have done other affine transformations (scaling the entire GUI up and down) very successfully on a project. I cannot see why rotations should be any different.
Instead of trying to scale each component use the fact that you can set a transformation on the Graphics object. Since this is shared between all components being rendered you get all things transformed at once "for free". It is important to realize that the transformation is only a rendering-process-step ... i.e. all components still believe they have the bounds (locations+sizes) which you gave them in the untransformed world. This leaves us with the challenge to deal with mouse-events correctly. To do this you simply add a glass-pane in front of your main-panel. This pane collects all mouse-events and apply a reverse of the transform on the event and then sends the event onward towards all other components.
Conceptually very simple! Still, I remember it took some tweaking to get it all crisp though. Especially the fact that rendered texts (fonts) in java are not correctly linearly scaled (it scales in discrete steps corresponding to font-sizes) imposed a final challenge in my scale-affine-transformation-case. Maybe you don't have to worry about that if you only rotate.
I got my inspiration from JXTransformer: http://www.java.net/blog/alexfromsun/archive/2006/07/jxtransformer_t.html
As far as I know you can't rotate a JPanel itself but you might be able to rotate the image inside the JPanel using Java2D. Here's an article that might help.
Edit:
There might actually be a way to rotate JComponents (such as JPanel) if you override their paintXxx methods and use AffineTransform.
It's not possible to rotate JPanel itself, but it's certainly possible to rotate any image inside. There are quite a few ways to do that, you can - for example - override JPanel's public void paint(Graphics g) and then cast Graphics to Graphics2D. It's very useful class, does rotation and much more ;) Check api docs for more info about this one.
Yes, it is possible. But you won't rotate the panel, but the image:
public void paintComponent(Graphics gg)
{
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTI_ALIAS, RenderingHints.VALUE_ANTI_ALIAS_ON);
AfflineTransform matrix = g.getTransform(); // Backup
float angle = Math.PI / 4.0f; // 45°
g.rotate(angle);
/* Begin */
g.drawImage(yourImage, [your coordinates], null);
/* End */
g.setTranform(matrix); // Restore
}
Everything between /* Begin */ and /* End */ will be drawn rotated.
(I didn't test the code, so, they may be some syntax errors...)