I'm trying to display an animated gif on a transparent JDialog using a simple JLabel:
JDialog dialog = new JDialog();
AWTUtilities.setWindowOpaque(dialog,false);
JLabel label = new JLabel();
ImageIcon ii = new ImageIcon("animation.gif");
label.setIcon(ii);
JPanel panel = new JPanel();
panel.setBackground(new Color(0,0,0,0));
panel.add(label);
dialog.add(panel);
dialog.setVisible(true);
This almost works. It displays the animation smoothly and it does have transparency.
The problem is that all the animation frames are overlaid instead of getting a cleared canvas and the current frame every frame step.
I assume that the JLabel's canvas doesn't get cleared every repaint step.
Does anyone know how I can fix this?
Edit:
I figured out a solution.
I had to override the ImageIcon's paintIcon function and manually clear the canvas:
class ClearImageIcon extends ImageIcon{
public ClearImageIcon(String filename){super(filename);}
#Override
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setBackground(new Color(0,0,0,0));
g2.clearRect(0, 0, getIconWidth(), getIconHeight());
super.paintIcon(c, g2, x, y);
}
}
this draws every frame nicely on to the screen.
this http://download.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html contains GradientPaint, that's is similair as add Image or ImageIcon
Related
When multiple JFrames are queued for repaint, the Swing Repaint Event paints the contents of all frames onto all frames, as though it is sharing the JPanels with the other frames.
In the example below, 'Frame 1' should only paint the square, and 'Frame 2' should only paint the oval. Instead, their graphics are somehow overlapping. The JPanels are not shared in any way, shape or form, so this should be impossible.
What I want to see is this:
For some reason, this only happens when the frames are being drawn in a loop (e.g. at 60 FPS).
I'm running Java 1.8.0_25 on Windows 10 x64.
I've been at it for hours now, and I couldn't find anything online about this... Does anyone know of a way to avoid this issue? Or if there is a work-around?
Here's the code:
JFrame frame1 = new JFrame("Frame 1");
frame1.setSize(256, 256);
frame1.setLocation(0, 0);
JPanel panel1 = new JPanel() {
public void paintComponent(Graphics g) {
g.fillRect(32, 32, 32, 32);
}
};
frame1.add(panel1);
frame1.setVisible(true);
JFrame frame2 = new JFrame("Frame 2");
frame2.setSize(256, 256);
frame2.setLocation(300, 0);
JPanel panel2 = new JPanel() {
public void paintComponent(Graphics g) {
g.fillOval(66, 32, 32, 32);
}
};
frame2.add(panel2);
frame2.setVisible(true);
while(true) {
Thread.sleep(16);
panel1.repaint();
panel2.repaint();
}
Solution (thanks MadProgrammer):
I did not add super.paintComponent(g) right after overriding the paintComponent() method. This fixed the issue. Unfortunately this also erases the previous graphics contents of the JPanel.
Im making an application that should be able to read files in a given directory and then display all image files in a fullscreen borderless window, it should also display text files, but i havent started on that part yet, so never mind the system.out part. So far ive made the JFrame fullscreen and borderless, and ive made an Arraylist containing the files i want shown. I then add a jpanel with the file in the constructor, this jpanel adds the picture to a jlabel and displays it, afterward i remove the jpanel and start over with the next picture.
What i need is a way to make the images fade in from a given color, and then fade out to that same color.
this is where i add the panels and remove them again
for (File f : files) {
String fileName = f.getName();
if (fileName.endsWith(".txt")) {
System.out.println("Txt");
System.out.println(fileName);
System.out.println("--");
} else if (fileName.endsWith(".png") || fileName.endsWith(".jpg") || fileName.endsWith("bmp")) {
AlbumPanel albumpan = new AlbumPanel(connect, f, this);
add(albumpan, BorderLayout.CENTER);
pack();
try {
Thread.sleep(current.getFormat().getPicLength()*1000);
} catch (InterruptedException ex) {
}
remove(albumpan);
}
}
And this is the JPanel
public class AlbumPanel extends JPanel {
BufferedImage image;
ImageIcon icon;
IConnect connect;
File pic;
JFrame presWin;
public AlbumPanel(IConnect connect, File pic, JFrame presWin) {
this.connect = connect;
this.pic = pic;
this.presWin = presWin;
this.setLayout(new GridBagLayout());
try {
image = ImageIO.read(pic);
} catch (Exception e) {
System.out.println(e);
}
image = resize(image, presWin.getWidth(), presWin.getHeight());
icon = new ImageIcon(image);
JLabel picLabel = new JLabel();
picLabel.setIcon(icon);
add(picLabel);
setVisible(true);
}
private BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
}
Override the rendering method (probably paintComponent) on the control you are using. Call super.paintComponent and then draw a semi-transparent rectangle of your "fade out" color over it.
Inside paintComponent you are passed a Graphics object. Methods on that object can be used to do things, including drawing a rectangle on the screen. You probably want fillRect.
Pick the opacity to be 0 when the image is fully displayed then move towards 1 when it's fully faded out.
You will need something to trigger redraws at regular intervals (a Swing Timer may be good enough).
You can use Color's transparency (the constructor public Color(int r, int g, int b, int a) where the last variable is alpha.
Start a Timer and change the Color's transparency from 0 to 255 and back filling the image (or the panel) with the Color.
The situation here is the following: I have a JFrame, in which I store a list of images. When the right-key is pressed, I display the next image in this fullscreen JFrame. I want a Exit JButton in the upper right corner of the screen, which is the problem. To achieve that, I create a new JPanel everytime the image is changed, remove the old JPanel from the frame, and add the JButton to the new JPanel. The issue is the following: when I start the program, the JButton is in the middle of the JFrame. Once I load the next Image by pressing the right key the JButton is on the right position. However, workarounds like calling the method to display the next Image fail. Even if I set the JButton invisible until the right key was pressed and the second image loaded, it still will be in the center of the screen instead of the upper right. The following code is used:
BufferedImage image = ImageIO.read(images.get(number));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
if (currentPanel != null) {
this.remove(currentPanel);
}
panel.setSize(Gallery.this.getSize());
currentPanel = this.add(panel);
jButton1.setBounds(Gallery.this.getWidth() - jButton1.getWidth(), 0, jButton1.getWidth(), jButton1.getHeight());
panel.add(jButton1);
currentPanel.repaint();
This code is executed once at startup. The JButton then is in the middle.
It is executed again when loading the next Image, JButton now is in correct position.
I already tried many things, like adding the JButton to the JFrame instead, setting JPanels layout to null (makes button invisible), repaint, pack, invalidate, nothing I try seems to work. Is anyone able to instruct Swing to place that JButton in the upper right corner of my JFrame? Thank you a lot!
After cleaning up the mess I programmed there, an easy solution proved to work:
I added a custom JPanel to the JFrame at startup and set a fixed width to the JButton. Here the JPanel:
public class ImagePanel extends javax.swing.JPanel {
Image image;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public ImagePanel() {
initComponents();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
I set a fixed width to the JButton and added it to that JPanel:
jButton1 = new JButton();
jButton1.setText("Exit");
imagePanel = new ImagePanel();
imagePanel.setSize(Gallery.this.getSize());
add(imagePanel);
imagePanel.add(jButton1);
jButton1.setBounds(Gallery.this.getWidth() - 50, 0, 50, 30);
jButton1.addActionListener((ActionEvent e) -> exit());
displayImage(0);
The displayImage method consists of these lines:
BufferedImage image = ImageIO.read(images.get(number));
imagePanel.setImage(image);
imagePanel.repaint();
I have searched (I think) thoroughly for an answer to my problem. I'm a beginner so I may just not know what to look for. I am trying to make an overview of an office layout (tables, chairs), which I coded using Graphics2D and GeneralPath, and JLabels with names by each chair.
If this has already been answered I apologize but I did look.
(Note: the graphics are super simple for now: table is just a square and chairs are just lines.)
public class DemoReception extends JApplet{
#Override
public void paint(Graphics g){
//draws table
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(4.0f));
g2.setColor(Color.BLACK);
int[] xPoints={150,700,700,150};
int[] yPoints={250,250,550,550};
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,xPoints.length);
path.moveTo(xPoints[0], yPoints[0]);
for (int i = 0; i < xPoints.length; i++) {
path.lineTo(xPoints[i], yPoints[i]);
}
path.closePath();
g2.draw(path);
//draws chairs
g2.setColor(Color.RED);
path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
path.moveTo(260,240);//Person1
path.lineTo(310,240);
path.moveTo(510,240);//Person2
path.lineTo(560,240);
path.moveTo(260,560);//Person3
path.lineTo(310,560);
path.moveTo(510,560);//Person4
path.lineTo(560,560);
path.closePath();
g2.draw(path);
}
And here is the main method:
public static void main(String[] args) {
int labelwidth = 50;
int labelheight = 10;
JFrame testFrame = new JFrame("Test Layout");
testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet demo = new DemoReception();
testFrame.setBackground(Color.white);
testFrame.getContentPane().add(demo);
testFrame.pack();
testFrame.setMinimumSize(new Dimension(1000,710));
testFrame.setSize(new Dimension(1000,710));
JPanel testPanel = new JPanel();
testPanel.setAlignmentX(0);
testPanel.setAlignmentY(0);
label1 = new JLabel("Person1");
label2 = new JLabel("Person2");
label3 = new JLabel("Person3");
label4 = new JLabel("Person4");
label1.setAlignmentX(260);
label1.setAlignmentY(235);
label1.setSize(labelwidth, labelheight);
label1.setVisible(true);
testPanel.add(label1);
label2.setAlignmentX(510);
label2.setAlignmentY(235);
label2.setSize(labelwidth, labelwidth);
label2.setVisible(true);
testPanel.add(label2);
label3.setAlignmentX(260);
label3.setAlignmentY(565);
label3.setSize(labelwidth, labelwidth);
label3.setVisible(true);
testPanel.add(label3);
label4.setAlignmentX(510);
label4.setAlignmentY(565);
label4.setSize(labelwidth, labelwidth);
label4.setVisible(true);
testPanel.add(label4);
testFrame.getContentPane().add(testPanel);
testFrame.setVisible(true);
}
When I run it all I get is the JFrame with the graphics but the JLabels don't show up.
Any help would be appreciated.
The JLabel does not appear in the JApplet as JFrame#pack is called before all labels have been added. The result is that those components are not validated so dont appear
The solution is to invoke the method before calling setVisible
testFrame.pack();
testFrame.setVisible(true);
However further changes are necessary as the applet window itself will not appear when this is done. This is because the statement
testFrame.getContentPane().add(testPanel);
will cause the JPanel testPanel to be displaced as implemented in the earlier statement
testFrame.getContentPane().add(demo);
BorderLayout can only contain one component at the CENTER location.
To fix, remove the testPanel and add the JLabel components directly to the JApplet demo instead.
Also add
super.paint(g);
to the paint method to ensure that the JLabels are painted by Swing.
Of course paint should never be used for custom painting in Swing. Rather use paintComponent
As a future exercise, make sure to replace the paint functionality by using a JComponent based class instead and overriding paintComponent. Remember to invoke super.paintComponent(g). Follow the steps outlined in Performing Custom Painting
The idea of the program is that I have some buttons and an icon SOMEWHERE on the frame. I want the buttons to change the color. I'm only worried about making all the elements show up right now. If I comment out lines 11-13, I see "hello," printed out, with a red circle on top of it. Otherwise, I just have the button "red" without "hello" or my red circle. So here's my code:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class ButtonTester
{
public static void main (String[] args)
{
JFrame frame = new ButtonFrame();
frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
JButton redButton = new JButton("Red");
frame.add(redButton);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 200;
public ButtonFrame()
{
setTitle("Hello");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
ButtonPanel panel = new ButtonPanel();
add(panel);
}
}
class ButtonPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
Icon ico = new ColorIcon(32);
ico.paintIcon(null, g, 75, 75);
}
}
I'm 90% sure the problem is lines 11-13, but I'm not sure what to change to make everything visible.
Your problem is that your ButtonPanel's size is 0. Have it override getPreferredSize() and you will see what I mean:
class ButtonPanel extends JPanel {
private static final int PREF_W = 150;
private static final int PREF_H = PREF_W;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
// !! Icon ico = new ColorIcon(32);
// Icon ico = new ImageIcon();
// ico.paintIcon(null, g, 75, 75);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Also as an unrelated aside, why are you creating an Icon inside of the paintComponent method? This doesn't make sense to me and would only serve to needlessly slow your graphics down.
Edit
You state:
Ok, I see the difference after overriding getPreferredSize() But what would be the "better" or "correct" way to create the icon? I'm just trying to follow the directions for an exercise out of a Java textbook: Exercise 4.14. Write a program that shows a frame with three buttons labeled "Red", "Green", and "Blue", and a label containing an icon showing a circle that is initially red. As the user clicks the buttons, the fill color of the circle should change. When you change the color, you need to invoke the repaint method on the label. The call to repaint ensures that the paintIcon method is called so that the icon can be repainted with the new color.
You need to think on this a different way. Myself I'd create three ImageIcons one for a blue circle, one for red, and one for green. I'd then display the ImageIcon in a JLabel on my JFrame. I'd change the color by simply swapping the label's icons via its setIcon(...) method. I wouldn't worry about futzing with paintComponent(...) but rather would try to solve this in as simple a fashion as possible.