I am doing slideshow of images program in java using timer.
In timer event listner i have added code to chnage image but image is not changing.
Below is the code i have written
class ImagePanel extends JPanel {
private Image backgroundImage;
public ImagePanel(Image backgroundImage) {
super();
this.backgroundImage = backgroundImage;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(this.backgroundImage, 0, 0, null);
}
}
public class A extends JFrame{
static int counter;
List<String> imagePaths;
int nimgpaths=0;
static A frame = new A();
public static void main(String[] args) {
frame.setSize(1024, 768);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getPath();
/* Getting required image */
Image backgroundImage = null;
String pathToTheImage = "C:\\Documents and Settings\\Administrator\\My Documents\\My Pictures\\civ1.JPG";
try {
backgroundImage = ImageIO.read(new File(pathToTheImage));
} catch (IOException e) {
e.printStackTrace();
}
/* Initializing panel with the our image */
ImagePanel panel = new ImagePanel(backgroundImage);
frame.getContentPane().add(panel);
frame.setVisible(true);
frame.timerEvent();
//frame.show();
}
public void timerEvent(){
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Time event occured");
if(counter > nimgpaths)
counter=0;
String imgPath=imagePaths.get(counter);
Image backgroundImage = null;
try {
backgroundImage = ImageIO.read(new File(imgPath));
}catch (Exception e1) {
e1.printStackTrace();
}
/* Initializing panel with the our image */
frame.removeAll();
ImagePanel panel = new ImagePanel(backgroundImage);
panel.repaint();
//panel.setBackground(backgroundImage);
frame.getContentPane().add(panel);
}
});
timer.start();
}
// To get path of images
public void getPath(){
DbOps db=new DbOps();
imagePaths=db.getPath();
nimgpaths=imagePaths.size();
for(Iterator i=imagePaths.iterator();i.hasNext();){
System.out.println((String)i.next());
}
}
}
Why are you using a custom panel and painting?
Your code is simply painting the image at its preferred size. This functionality is available when you use a JLabel. Then when you use the label all you need to do is use:
label.setIcon(....);
when you want to change the image. Read the section from the Swing tutorial on How to Use Icons for more information.
The only reason to create a custom component is if you plan to scale the image or do something fancy like that. If this is the case then you can use something like the Background Panel which supports scaled images as well as a setImage() method so you can change the image dynamically.
A much better design for ImagePanel would let you just replace the image, rather than removing the component. If you do have to replace a visible component, though, you have to call validate() on its container, or the new one isn't going to show up (most of the time, anyway.) I think that's your problem here.
frame.removeAll() is not doing what you would expect - it is removing the components from the frame itself rather than removing the components from the content pane of the frame. Change the code at the end of the timer's action listener to something like this to fix it:
ImagePanel panel = new ImagePanel(backgroundImage);
frame.getContentPane().removeAll();
frame.getContentPane().add(panel);
frame.getContentPane().invalidate();
frame.getContentPane().validate();
Your concept itself is wrong.
You can refresh the panel like so:
public void refreshPanel(JPanel panel){
panel.removeAll();
panel.invalidate();
panel.validate();
}
Problem:
I see in your code that you are trying to create more than one object of the same panel, which you need to refresh.
It would be better to create one panel object and refresh that object.
ImagePanel panel = new ImagePanel(backgroundImage);
Hope you can understand what I wanted to explain to you.
If you are still confused then let me know.
Related
I have created a subclass of JPanel to display images. I instantiate this in the constructor of a JFrame and add it to that JFrame. This works perfectly. Then I have added a button with an ActionListener to change that Image. My problem is that the JFrame won´t update although I have tried repainting etc.
The subclass of JPanel:
public class ImagePanel extends JPanel {
BufferedImage bf;
public ImagePanel(String dateiname)
{
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
public void paint(Graphics g)
{
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
}
The JFrame is basically this
public class Hauptfenster extends JFrame {
private JButton changeImage;
private JPanel buttonPanel;
private ImagePanel ip;
public Hauptfenster {
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
ip = new ImagePanel("new_image.jpg");
ip.setVisible(true);
});
this.add(buttonPanel);
this.add(ip);
this.setVisible(true);
}
}
Why doesn´t the method in the ActionListener update the ip component in the JFrame Hauptfenster?
When you do ip = new ImagePanel("new_image.jpg"); you're creating a whole new ImagePanel that has nothing to do with your current layout. You could.
remove(ip);
ip = new ImagePanel("new_image.jpg");
add(ip);
repaint();
Another way you could do it is to just change the buffered image.
Add the following method to your image panel.
public void loadImage(String dateiname) {
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
Then in your action listener.
ip.loadNewImage("new_image.jpg");
ip.repaint();
You have a bunch of bad habits going on in your code though.
Such as, override paintComponent instead of paint and it should look like.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
That way transparency will be handled correctly.
You shouldn't extend JFrame, you should just create a JFrame.
When you add components, you there is a layout manager involved. It's good to be aware of that and handle things accordingly. I would change your constructor to.
public Hauptfenster() {
JFrame frame = new JFrame();
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
changeImage = new JButton("change image");
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
frame.remove(ip);
ip = new ImagePanel("new_image.jpg");
frame.add(ip, BorderLayout.CENTER);
frame.repaint();
});
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.add(ip, BorderLayout.CENTER);
frame.setVisible(true);
}
If you need more help, you'll need to actually make your example compilable. There are too many errors right now.
I have a JFrame. It uses a JPanel as its content pane, and that JPanel uses GridBagLayout as its LayoutManager. That JPanel contains two more items: a button, and another JPanel. On program start, an image is loaded from file into the lowest-level JPanel as a BufferedImage using ImageIO.read(...). Here is where everything goes to pieces.
The image loads correctly, I can see a small corner of it on screen (14px square as specified in debugger). There is nothing I can figure out that will cause the layout to grow and fit the entire image in the lowest level JPanel on screen. The image in debuggers shows correct size of 500px. The preferred size of the CardImagePanel shows up correctly as the same size as the image. But the layout will not respect the preferred size unless I manually set the CardImagePanel size using setSize(...) which I'm pretty sure is not supposed to be necessary with GBL.
I have tried putting revalidate() and repaint() calls on every single JFrame, JPanel, layout, grid bag, image, etc throughout the entire program and just can't find the correct place or time to call them to make this thing work. Currently I've been trying to just let the image load incorrectly and use the button to force revalidation and repaint, but even this explicit call is not doing anything.
I'm losing my mind, I'll do anything to get this thing working.
Here is all my code for the whole stupid thing (minus imports and package specification.
P1s1.java:
public class P1s1 {
public static void main(String[] args) {
// TODO code application logic here
build();
}
public static void build()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(640, 480));
frame.setContentPane(new GuiPanel(frame));
frame.setVisible(true);
}
}
GuiPanel.java:
public class GuiPanel extends JPanel {
JFrame parentFrame;
JButton imageLoaderButton;
CardImagePanel cardImagePanel;
LayoutManager layout;
GridBagLayout gridBagLayout;
GridBagConstraints constraints;
public GuiPanel(JFrame frame)
{
parentFrame = frame;
constraints = new GridBagConstraints();
gridBagLayout = new GridBagLayout();
layout = gridBagLayout;
this.setLayout(layout);
this.setBorder(BorderFactory.createLineBorder(Color.black));
setupImageLoaderButton(imageLoaderButton);
cardImagePanel = new CardImagePanel();
this.add(cardImagePanel);
}
private void setupImageLoaderButton(JButton button)
{
button = new JButton("Click to load image!");
ActionListener imageLoaderListener;
imageLoaderListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Button clicked.");
cardImagePanel.revalidate();
cardImagePanel.repaint();
GuiPanel.this.revalidate();
GuiPanel.this.repaint();
parentFrame.revalidate();
parentFrame.repaint();
}
};
button.addActionListener(imageLoaderListener);
this.add(button);
}
}
CardImagePanel.java:
public class CardImagePanel extends JPanel {
BufferedImage cardImage;
public CardImagePanel()
{
this.setBorder(BorderFactory.createLineBorder(Color.black));
try {
cardImage = ImageIO.read(new File("c:\\dev\\cards\\2_of_clubs.png"));
this.setPreferredSize(new Dimension(cardImage.getWidth(), cardImage.getHeight()));
} catch (IOException ex) {
System.out.println("Exception trying to load image file.");
}
}
// The getPreferredSize() override was suggested by MadProgrammer.
// It did not solve the issue, but see MadProgrammer's updated,
// accepted answer below for the correct solution. The rest of the
// code reflects my original attempt to solve the issue.
#Override
public Dimension getPreferredSize()
{
return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredImage();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(cardImage, 0, 0, this);
}
}
GridBagLayout relies on a component telling it what size it would like to be (along with it's minimum and maximum size when it's relievent). You need to override the getPreferredSize method of the CardImagePanel, returning the size you would like the component to be
public class CardImagePanel extends JPanel {
BufferedImage cardImage;
public CardImagePanel() {
this.setBorder(BorderFactory.createLineBorder(Color.black));
try {
cardImage = ImageIO.read(new File("c:\\dev\\cards\\2_of_clubs.png"));
} catch (IOException ex) {
System.out.println("Exception trying to load image file.");
}
}
#Override
public Dimension getPreferredSize() {
return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredSize();
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(cardImage, 0, 0, this);
}
}
Have a look at How to Use GridBagLayout for more details
You CardImagePanel has no preferred size, so the layout manager doesn't know how to handle the size properly.
A couple of solutions:
There is no need to create a custom class to display the image. Just use a JLabel to display the image. The JLabel will return the preferred size of the image.
If you do use the CardImagePane, then you need to override the getPreferredsize() method of the CardImagePanel to return the size of the image.
I'm new to programming world, and I need some help. I will try to be as clear as possible.
This is my current situation:
I'm programming a simple game.
On a Jframe, I've added a Jlabel on which I attached an image. I've also added a Jbutton on the Jframe.
I would like that when I click on the Jbutton, the image appears and on the next click the image hides.
How could I do it?
Thanks in advance and excuse me for the possible english mistakes.
EDIT
Following some instructions given by people, I've reached this point:
button.addActionListener(new Actionbox());
final class Actionbox implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
if (label.getIcon() == null)
label.setIcon(new ImageIcon(myimage));
else
label.setIcon(null);
}
}
Eclipse is giving me an error message on the left side of the code editor, near the number lines. It says "Actionbox cannot be resolved to a type".
How could I solve it?
I would like that when I click on the Jbutton, the image appears and on the next click the image hides
add/remove an Icon from the label:
public void actionPerformed(ActionEvent e)
{
if (label.getIcon() == null)
label.setIcon(...);
else
label.setIcon( null );
}
Or instead of setting the Icon null, you may want to have a blank Icon so that the size of the label doesn't keep changing every time you show an image.
Don't fiddle with your button's visibility, and don't make it a final local variable. For something like this, the label should be a field. Place it in your GUI and leave it visible, since if it doesn't hold an icon or have text, nothing will show on it. Instead in your button's ActionListener, simply change the JLabel's ImageIcon via its setIcon(...) method. Pass in an Icon if you want to show an image and pass in null if you want to show nothing. Make your JLabel a field of the class, not a final local variable.
Regarding your code, one way to create your JButton's ActionListener is to use an anonymous inner class rather than a static private class. I'd also recommend reading in the image just once perhaps in your class's constructor and not each time the button is pressed. For example,
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial") // have GUI extend JPanel
public class ButtonSwapImageGui extends JPanel {
private static final String IMAGE_PATH = "https://duke.kenai.com/iconSized/duke.gif";
private Icon imageIcon; // hold our image
private Icon nullImageIcon; // hold a blank image as a placeholder
private JLabel label = new JLabel("", SwingConstants.CENTER);
// throw an exception if image can't be read
public ButtonSwapImageGui() throws IOException {
// read in an image from the internet
URL imageUrl = new URL(IMAGE_PATH);
BufferedImage image = ImageIO.read(imageUrl);
// create a blank placeholder image the same size as
// the image read in from internet
int width = image.getWidth();
int height = image.getHeight();
BufferedImage nullImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// create ImageIcon objects with images read in above
imageIcon = new ImageIcon(image);
nullImageIcon = new ImageIcon(nullImage);
// set JLabel with the placeholder nullImageIcon
label.setIcon(nullImageIcon);
// create our button
JButton button = new JButton("Swap Image");
// add an anonymous inner class ActionListener to button
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// get the JLabel's Icon
Icon currentIcon = label.getIcon();
// if the Icon matches the null icon
if (currentIcon == nullImageIcon) {
// set label with image
label.setIcon(imageIcon);
} else {
// otherwise the label is displaying the image
// so now set label with the null (blank) icon
label.setIcon(nullImageIcon);
}
}
});
// JPanel to hold our button
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
// set our GUI's layout to BorderLayout
setLayout(new BorderLayout());
// add the JLabel to the BorderLayout.CENTER position
add(label, BorderLayout.CENTER);
// add button JPanel to the bottom
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
// declare our GUI JPanel
ButtonSwapImageGui mainPanel = null;
try {
mainPanel = new ButtonSwapImageGui();
} catch (IOException e) {
// if we're here, the image could not be read in
e.printStackTrace();
System.exit(-1); // can't get image -- exit program
}
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel); // add GUI to JFrame
frame.pack(); // tell layout managers to layout components
frame.setLocationRelativeTo(null); // center GUI
frame.setVisible(true); // display GUI
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can do something like this:
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
jLabel.setVisible(!jLabel.isVisible()); //Note! jLabel has to be a final variable.
}
}
You should note that any variables used inside coming from outside the ActionListener have to be final ones. This largely restricts you into working with objects
I usually use set bounds (0,0,0,0); whenever I want to hide swing components
button.addActionListener(new Actionbox());
final class Actionbox implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
if (label.getIcon() == null) {
label.setIcon(new ImageIcon(myimage));
else{
label.setIcon(null);
}
}
I am having some difficulty figuring out why there is a difference between the results I see on the Title Screen and the Setup Screen. I copy/pasted the majority of the code before tweaking each... it clearly has to do with something in my outer frame, but I don't know what. The problem I am seeing is that although the Title Screen comes up at the correct size of 1024x768 with the background correctly displayed, the Setup Screen comes up as a very small window as though I had not just set it's size. The background image is also only shown in that sliver of space, even if the box is resized.
I have removed all of the elements inside of Title Screen but it still maintains its size. Can someone help? Thanks
OuterFrame
public class OuterFrame extends JFrame {
public OuterFrame(String windowHeading) {
int WIDTH = 1024;
int HEIGHT = 768;
final Dimension screenSize = new Dimension(WIDTH,HEIGHT);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JPanel title = new TitleScreen();
title.setLayout(new BoxLayout(title, BoxLayout.PAGE_AXIS));
JButton matchButton = new JButton("New Match");
//Add action listener to button
matchButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Execute when button is pressed
removeAll();
JPanel setupScreen = new SetupScreen();
add(setupScreen);
pack();
}
});
JButton exitButton = new JButton("Exit to Windows");
//Add action listener to button
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Execute when button is pressed
System.exit(0);
}
});
matchButton.setAlignmentX(title.CENTER_ALIGNMENT);
exitButton.setAlignmentX(title.CENTER_ALIGNMENT);
title.setPreferredSize(screenSize);
title.add(matchButton);
title.add(Box.createRigidArea(new Dimension(0,25)));
title.add(exitButton);
add(title);
pack();
}
}
Title Screen
public class TitleScreen extends JPanel {
public BufferedImage background;
public TitleScreen() {
try {
InputStream is = new BufferedInputStream(new FileInputStream("images/datascreen.png"));
Image image = ImageIO.read(is);
background = (BufferedImage)image;
} catch (Exception a) {
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(background,0,0,1024,768,null);
}
}
SetupScreen
public class SetupScreen extends JPanel {
public BufferedImage background;
public SetupScreen() {
try {
InputStream is = new BufferedInputStream(new FileInputStream("images/datascreen.png"));
Image image = ImageIO.read(is);
background = (BufferedImage)image;
} catch (Exception a) {
}
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(background,0,0,1024,768,null);
}
}
Sorry about the formatting.. I can't for the life of me make it keep the indention I use in my code.
Edit:
#Override
public Dimension getPreferredSize() {
return new Dimension(1024, 768);
}
I added the above to both the title and the setup classes, as well as removing the hard coded resize. The issue still occurs - the window is sized correctly for the title but not the setup. Any help would be appreciated..
Read the Swing tutorial on Custom Painting for the basics. In this case the problem is that you don't override the getPreferredSize() method of your custom component, so the layout manager basically uses 0.
The reason your first screen displays is because you hardcoded:
title.setPreferredSize(screenSize);
This is a no-no (for too many reasons to go into detail here). The component should return its preferred size as mentioned above and then the pack() statement will work properly.
Figured out that the problem was the removeAll() statement. I added getContentPane. to it and it worked fine.
I have to build a small Java applet for a project. I have previously never used applets. Hence I don't know much about the various inbuilt functions available. The layout of this applet is as below:
The screen is divided into 3 parts
Top most part will have a set of buttons and text boxes
Middle part and bottom part will be displaying different images
These Images can vary in size when the program is run each time (Hence it requires scroll bars in case the image goes out of the screen)
Till now I have succeeded in partitioning the screen and creating separate panels for the each part and adding the corresponding components in them.
Problem:
The bottom image is not completely visible. And also scroll bars are not appearing for each Image when it does not fit into the panel.
I tried using setSize(), setMinimumSize() methods but it does not produce any changes in the output. Can you please help me with the above problem?
This is what I have done till now:
/*<applet code=DOSlayout.java width=400 height=400>
</applet>*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DOSlayout extends JApplet implements ActionListener {
Button ViewButton;
Panel1 Top;
Panel2 LeftSide;
Panel3 RightSide;
Label l1,l2,l3;
Image img;
public void init() {
setSize(400,400);
setLayout(new BorderLayout());
Top = new Panel1();
LeftSide = new Panel2();
RightSide = new Panel3();
Top.setSize(getSize().width, getSize().height/3);
LeftSide.setSize(getSize().width,getSize().height/3);
RightSide.setSize(getSize().width,getSize().height/3);
//RightSide.setMinimumSize (new Dimension(400, 10000));
add(Top, BorderLayout.NORTH);
add(LeftSide, BorderLayout.CENTER);
add(RightSide, BorderLayout.SOUTH);
ViewButton = new Button("View");
l1 = new Label("North");
l2 = new Label("East");
l3 = new Label("West");
Top.add(ViewButton);
Top.add(l1);
//LeftSide.add(l2);
//RightSide.add(l3);
ViewButton.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
class Panel1 extends JPanel {
Panel1() {
super();
}
public void paint(Graphics g) {
}
}
class Panel2 extends JPanel {
Panel2() {
super();
}
private Image img;
public void init()
{
img = null;
}
public void loadImage()
{
try
{
img = getImage(getCodeBase(), "input1.png");
}
catch(Exception e) { }
}
public void paint(Graphics g)
{
if (img == null)
loadImage();
g.drawImage(img, 0, 0, this);
//g.drawImage(img,0,0,(int)getBounds().getWidth(), (int)getBounds().getHeight(),this);
}
}
class Panel3 extends JPanel {
Panel3() {
super();
}
private Image img;
public void init()
{
img = null;
//setSize(400,400);
}
public void loadImage()
{
try
{
img = getImage(getCodeBase(), "input2.png");
}
catch(Exception e) { }
}
public void paint(Graphics g)
{
if (img == null)
loadImage();
g.drawImage(img, 0, 0, this);
//g.drawImage(img,0,0,(int)getBounds().getWidth(), (int)getBounds().getHeight(),this);
}
}}
Start with the container used in ImageViewer. It centers the image inside a scroll-pane whose scroll-bars appear reliably.
Further tips
"I have previously never used applets." That is ominous, given applets are tougher to develop & deploy than frames. I suggest develop this first in a JFrame (then launch the frame from a link using Java Web Start). Only after seeing the frame launched using JWS should you consider using an applet. By that stage, any 'conversion' needed will be much simpler.
Don't ever call setSize(..) in an applet. The size is in the HTML.
Don't mix Swing and AWT components unless necessary, use all Swing.
It is typically a bad idea to set the sizes (preferred, max or min) of any components.
Please learn common Java naming conventions (specifically the case used for the names) for class, method & attribute names & use it consistently.