How to Update Image in an Applet - java

How do i get an java applet to search an image from the specified path. I want to make a simple imageviewer applet which has 2 buttons NEXT,PREV . By clicking Next it should show next image and by clicking prev it should show the previous image.
i have written the following code .Please help me in writing the code for the updatenext() and updateprev() function.
public class pic extends Applet implements ActionListener
{
Button prev,next;
private static final String PREV="Previous";
private static final String NEXT="Next";
Image img;
public void init()
{
img=getImage(getCodeBase(),"image1.jpg");
prev = new Button();
prev.setLabel(PREV);
prev.setActionCommand(PREV);
prev.addActionListener(this);
add(prev);
next = new Button();
next.setLabel(NEXT);
next.setActionCommand(NEXT);
next.addActionListener(this);
add(next);
}
public void paint(Graphics g)
{
g.drawImage(img,0,0,600,700,this);
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals(NEXT))
updatenext();
else if(e.getActionCommand().equals(PREV))
updateprev();
}
void updatenext()
{
//updateImagehere
}
void updateprev()
{
//updateimage here
repaint();
}
}

A very simple example is this.
import java.applet.*;
import java.awt.*;
public class AppletImage extends Applet{
Image img;
MediaTracker tr;
public void paint(Graphics g) {
tr = new MediaTracker(this);
img = getImage(getCodeBase(), "demoimg.gif");
tr.addImage(img,0);
g.drawImage(img, 0, 0, this);
}
public static void main(String args[]){
AppletImage appletImage = new AppletImage();
appletImage.setVisible(true);
}
}
try this and ya u can take image according to your self.

If you want to get a list of the files in the location of your applet you can create a File object of the current directory with:
File currentDir = new File(getCodeBase().getPath());
Then to iterate over the files call:
for (File file : currentDir.listFiles()) {
// do something with the file
}
You will need to filter out directories and non image files, I would suggest you use a FileNameFilter as an argument when calling listFiles().
EDIT:
Here's an example of the solution you could use with this method:
public class pic extends Applet implements ActionListener
{
Button prev, next;
private static final String PREV = "Previous";
private static final String NEXT = "Next";
Image img;
private File[] imageFiles;
private int currentIndex = 0;
public void init()
{
File baseDir = new File(getCodeBase().getPath());
imageFiles = baseDir.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
String image = ".*\\.(png|jpg|jpeg|gif)";
Pattern pattern = Pattern.compile(image);
Matcher matcher = pattern.matcher(name.toLowerCase());
return matcher.matches();
}
});
setImage();
prev = new Button();
prev.setLabel(PREV);
prev.setActionCommand(PREV);
prev.addActionListener(this);
add(prev);
next = new Button();
next.setLabel(NEXT);
next.setActionCommand(NEXT);
next.addActionListener(this);
add(next);
}
public void paint(Graphics g)
{
g.drawImage(img, 0, 0, 600, 700, this);
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals(NEXT))
updatenext();
else if (e.getActionCommand().equals(PREV))
updateprev();
}
private void setImage() {
img = getImage(getCodeBase(), imageFiles[currentIndex].getName());
}
void updatenext()
{
// needs circular increment
if (currentIndex == imageFiles.length - 1) {
currentIndex = 0;
} else {
currentIndex++;
}
setImage();
repaint();
}
void updateprev()
{
// needs circular decrement
if (currentIndex == 0) {
currentIndex = imageFiles.length-1;
} else {
currentIndex--;
}
setImage();
repaint();
}
}

Related

How to make two thread communicate through handler?

I have form that button can auto re-size their size when mouse hover on button and default their size when mouse is exited. It work normally first time but after i try it more than one time their size is enlarged that i can not control normally.
ImageIcon ima=new ImageIcon("C:\\Users\\chen rina\\Pictures\\win.png");
ImageIcon icon;
Thread thr;
Runnable r=new Runnable() {
#Override
public void run() {
int i=40;
while(i!=80){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_FAST);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i+5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
thr=new Thread(r);
thr.start();
}
Runnable res=new Runnable() {
int i;
#Override
public void run() {
int i=80;
while(i!=40){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_AREA_AVERAGING);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i-5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseExited(java.awt.event.MouseEvent evt) {
thr=new Thread(res);
thr.start();
}
Your code violates Swing thread integrity rules by making Swing calls, here setIcon(...) from within a background state. Having said that, why not simplify all of this by:
Reading in and creating and storing your ImageIcons once and only once
Never ignore exceptions as you're doing. That's unsafe coding.
Most important, use a Swing Timer to simply swap icons every 20 msec, and have no fear about violating Swing threading rules.
Your grow Timer's ActionListener could be as simple as this:
// a private inner class
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
// assuming the button is called button and the list iconList
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
The iconList would look something like:
private List<Icon> iconList = new ArrayList<>();
And you could fill it with code looking something like:
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
And a more complete and runnable example:
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeIconTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int START_LENGTH = 40;
private static final int END_LENGTH = 120;
private static final int STEP = 5;
private static final int TIMER_DELAY = 20;
private static final String URL_SPEC = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/2/2b/Oryx_gazella_-_Etosha_2014_square_crop.jpg/"
+ "600px-Oryx_gazella_-_Etosha_2014_square_crop.jpg";
private JButton button = new JButton();
private ResizeIcon resizeIcon;
public ResizeIconTest() throws IOException {
add(button);
URL imageUrl = new URL(URL_SPEC);
BufferedImage originalImg = ImageIO.read(imageUrl);
resizeIcon = new ResizeIcon(button, originalImg, START_LENGTH,
END_LENGTH, STEP, TIMER_DELAY);
button.setIcon(resizeIcon.getSmallestIcon());
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
resizeIcon.grow();
}
#Override
public void mouseExited(MouseEvent e) {
resizeIcon.shrink();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ResizeIconTest mainPanel = null;
try {
mainPanel = new ResizeIconTest();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("ResizeIconTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ResizeIcon {
private List<Icon> iconList = new ArrayList<>();
private AbstractButton button;
private int delayTime;
private Timer growTimer;
private Timer shrinkTimer;
public ResizeIcon(AbstractButton button, BufferedImage originalImg,
int startLength, int endLength, int step, int delayTime) {
this.button = button;
this.delayTime = delayTime;
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
}
public Icon getSmallestIcon() {
return iconList.get(0);
}
public void grow() {
if (growTimer != null && growTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(iconList.size() - 1)) {
return; // don't run if already at largest size
}
growTimer = new Timer(delayTime, new GrowListener());
growTimer.start();
}
public void shrink() {
if (shrinkTimer != null && shrinkTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(0)) {
return; // don't run if already at smallest size
}
shrinkTimer = new Timer(delayTime, new ShrinkListener());
shrinkTimer.start();
}
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
private class ShrinkListener implements ActionListener {
private int index = iconList.size() - 1;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index--;
if (index < 0) {
((Timer) e.getSource()).stop();
}
}
}
}

I can't save my Image (mid blend) to file?

I've tried looking at the Oracle advice on Writing/Saving an image but nothing I do works. I have a start button that starts the blend of 2 images from one to another. Then a stop button to stop the blend midway (or wherever you want) then I have a saveImage button and would like it capture the image in it's current state and save it to file. But how ? here's the code from the Frame.java
import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
class Frame extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private Image MeSmaller1;
private Image MeSmaller2;
protected Timer timer;
private float alpha;
JPanel pnlButton = new JPanel();
static JButton btnStartBlend = new JButton("Start Blend");
static JButton btnStopBlend = new JButton("Stop Blend");
static JButton saveImage = new JButton("Save Image To File");
public Frame() {
loadImages();
initTimer();
pnlButton.add(btnStartBlend);
this.add(pnlButton);
pnlButton.add(btnStopBlend);
this.add(pnlButton);
pnlButton.add(saveImage);
this.add(pnlButton);
addListeners();
}
// start button actionlistener
public void addListeners() {
btnStartBlend.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
initTimer();
timer.start();
System.out.println("Timer started");
}
});
// stop button actionlistener
btnStopBlend.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// initTimer();
timer.stop();
System.out.println("Timer stopped");
}
});
// Save button actionlistener
saveImage.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Save image clicked");
}
});
}
private void loadImages() {
MeSmaller1 = new ImageIcon("MeSmaller1.jpg").getImage();
MeSmaller2 = new ImageIcon("MeSmaller2.jpg").getImage();
}
public void initTimer() {
timer = new Timer(1000, this);
timer.start();
timer.stop();
alpha = 1f;
}
private void doDrawing(Graphics g) {
Graphics2D g2Dim = (Graphics2D) g;
// below sets the size of picture
BufferedImage buffImage = new BufferedImage(400, 600,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gBuffI = buffImage.createGraphics();
AlphaComposite aComp = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
// decides where images are drawn in JFrame
gBuffI.drawImage(MeSmaller1, 28, 55, null);
gBuffI.setComposite(aComp);
gBuffI.drawImage(MeSmaller2, 30, 48, null);
g2Dim.drawImage(buffImage, 10, 10, null);
}
public static void saveToFile(BufferedImage img) {
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
#Override
public void actionPerformed(ActionEvent e) {
alpha -= 0.1;
if (alpha <= 0) {
alpha = 0;
timer.stop();
System.out.println("Morph Finished please restart.");
}
repaint();
}
}
Can anyone help here it's just not working. There is also another class PictureMorph.java
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PictureMorph extends JFrame {
private static final long serialVersionUID = 1L;
public PictureMorph() {
initUI();
}
private void initUI() {
JFrame frame = new JFrame ("Image Morph");
setTitle("Facial Image Manipulation");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Frame());
// below set Frame Size around image
setSize(380, 470);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PictureMorph picMorph = new PictureMorph();
picMorph.setVisible(true);
}
});
}
}
And 3 classes (that I think could be redundant now actually?) called BtnStartBlendListener, BtnStopBlendListener, SaveImageListener that don't contain much code at all. Can anyone help ?
To use a JFileChooser and end up with a user friendly file selector, you may do this:
private static Frame workFrame;
public static Frame getWorkFrame() {
return workFrame;
}
public static void setWorkFrame(Frame frame) {
workFrame = frame;
}
Then modify the save method the following way (the signature changes and also I have commented the code that uses the Scanner and replace it by the JFileChooser)
public static void save(BufferedImage img, Frame frame) {
// Scanner scan = new Scanner(System.in);
// System.out.println("Enter the file name: ");
// String fileFullPath = scan.next();
String fileFullPath = getFileToSaveTo(frame);
file = new File(fileFullPath);
saveToFile(img, file);
}
Add the following method:
public static String getFileToSaveTo(Frame frame) {
JFileChooser fc=new JFileChooser();
int returnVal=fc.showOpenDialog(frame);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile().getAbsolutePath();
}
else {
return null;
}
}
In your main method have a call like Frame.setWorkFrame(fr);where fr is defined as Frame fr = new Frame();
This should make it work with the JFileChooser. For example here is how I call the program in my main method
public static void main(String[] args) {
JFrame theFrame = new JFrame("Testing catess...");
theFrame.setSize(400, 400);
Frame fr = new Frame();
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.add(fr, BorderLayout.CENTER);
theFrame.setVisible(true);
Frame.setWorkFrame(fr);
}
It is working fine in my tests. Test and let me know if it works
Since you have left the saveToFile method empty, I assume that it is the major issue that you have.
For the saveToFile method you can use javax.imageio.ImageIO. I would suggest that you pass a File object parameter to your method so it knows where to save the image.
public static void saveToFile(BufferedImage img, File file) {
String filename = file.getName();
String suffix = filename.substring(filename.lastIndexOf('.') + 1);
suffix = suffix.toLowerCase();
if (suffix.equals("jpg") || suffix.equals("png")) {
try { ImageIO.write(img, suffix, file); }
catch (IOException e) { e.printStackTrace(); }
}
else {
System.out.println("Error: filename must end in .jpg or .png");
}
}
Hope this helps
[EDIT]
The File constructor allows you to instanciate the File object with a string representing the path to the file.
Example: assuming I want to save it in, let's say C:\Tests\image1.jpg, I would do this
File myFile = new File("C:\\Tests\\image1.jpg")
,where Tests represents an existing folder and image1.jpg is of course the name of the new file in which you will save your image.
So assume that img is a variable containing the reference to your BufferedImage object you would call the above method with
Frame.saveToFile(img, myFile);
where myFile is the above File object.
You can also add a static method such as the following one to get the user to specify the path to the file. I used Scanner to get it quick, but for a more user - friendly dialog, use a JFileChooser (examples are here)
public static void save(BufferedImage img) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the file name: ");
String fileFullPath = scan.next();
File file = new File(fileFullPath);
saveToFile(img, file);
}
The issues you experienced are mostly related to the fact that you declared final some of the variables, notably the BufferedImage and the File object (which were null and since you make them final their values can't be changed)
I corrected these issues. Here is the whole code, except the imports statements which are the same as those you had in the link to your source code.
After you click on the save button, enter a full path to the file to save: example C:\test1.jpg in the console.
class Frame extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
static BufferedImage bufferedImage = null; // Don't need to make this final
static File file = null; // Don't need to make this final
private Image MeSmaller1;
private Image MeSmaller2;
protected Timer timer;
private float alpha;
JPanel pnlButton = new JPanel();
static JButton btnStartBlend = new JButton("Start Blend");
static JButton btnStopBlend = new JButton("Stop Blend");
static JButton saveImage = new JButton("Save Image To File");
public Frame() {
loadImages();
initTimer();
pnlButton.add(btnStartBlend);
this.add(pnlButton);
pnlButton.add(btnStopBlend);
this.add(pnlButton);
pnlButton.add(saveImage);
this.add(pnlButton);
addListeners();
}
// start button action listener
public void addListeners() {
btnStartBlend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
initTimer();
timer.start();
System.out.println("Timer started");
}
});
// stop button actionlistener
btnStopBlend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// initTimer();
timer.stop();
System.out.println("Timer stopped");
}
});
// Save button actionlistener
saveImage.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent saveImage) {
save(bufferedImage);
System.out.println("Save image clicked");
}
});
}
private void loadImages() {
// I did my local test using
//MeSmaller1 = new ImageIcon("C:\\Tests\\Alain_Lompo.jpg").getImage();
//MeSmaller2 = new ImageIcon("C:\\Tests\\Alain_Lompo.jpg").getImage();
MeSmaller1 = new ImageIcon("MeSmaller1.jpg").getImage();
MeSmaller2 = new ImageIcon("MeSmaller2.jpg").getImage();
}
public void initTimer() {
timer = new Timer(1000, this);
timer.start();
timer.stop();
alpha = 1f;
}
private void doDrawing(Graphics g) {
Graphics2D g2Dim = (Graphics2D) g;
// below sets the size of picture
bufferedImage = new BufferedImage(400, 600,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gBuffI = bufferedImage.createGraphics();
AlphaComposite aComp = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
// decides where images are drawn in JFrame
gBuffI.drawImage(MeSmaller1, 28, 55, null);
gBuffI.setComposite(aComp);
gBuffI.drawImage(MeSmaller2, 30, 48, null);
g2Dim.drawImage(bufferedImage, 10, 10, null);
}
public static void save(BufferedImage img) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the file name: ");
String fileFullPath = scan.next();
file = new File(fileFullPath);
saveToFile(img, file);
}
public static void saveToFile(BufferedImage img, File file) {
String filename = file.getName();
String suffix = filename.substring(filename.lastIndexOf('.') + 1);
suffix = suffix.toLowerCase();
if (suffix.equals("jpg") || suffix.equals("png")) {
try { ImageIO.write(img, suffix, file); }
catch (IOException e) { e.printStackTrace(); }
}
else {
System.out.println("Error: filename must end in .jpg or .png");
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
public void actionPerformed(ActionEvent e) {
alpha -= 0.1;
if (alpha <= 0) {
alpha = 0;
timer.stop();
System.out.println("Morph Finished please restart.");
}
repaint();
}
public static void main(String[] args) {
JFrame theFrame = new JFrame("Testing catess...");
theFrame.setSize(400, 400);
Frame fr = new Frame();
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.add(fr, BorderLayout.CENTER);
theFrame.setVisible(true);
}
}

How to display/update images after keystrokes in java in JFrame?

As a java non-expert, I would like to know how to change the code below to get it to work. Here is what I want to do
When the java code is called args contains several image filenames
I want to see the first image in this list
Then when I press a key, an index is changed, and the next image is displayed.
Using the suggestions made below, here is a compilable, running piece of code:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class LoadImageApp extends Component {
BufferedImage img;
private static int index = 0;
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
public LoadImageApp(String filename) {
try {
img = ImageIO.read(new File(filename));
} catch (IOException e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
public Dimension getPreferredSize() {
if (img == null) {
return new Dimension(100,100);
} else {
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
static public void changeImage(JFrame frame, String filename) {
System.out.println("Using file "+filename);
frame.add(new LoadImageApp(filename));
frame.pack();
frame.setVisible(true);
frame.repaint();
}
public static void main(final String[] args) {
char c=0;
String filename = args[0];
int numberImages = args.length;
final JFrame f = new JFrame("Load Image Sample");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
f.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent event) {
int key = event.getKeyCode();
if (key==81) {
System.exit(0);
} else if (key==89) {
System.out.println("yes");
} else if (key==78) {
System.out.println("no");
}
index += 1;
f.removeAll();
changeImage(f, args[index]);
}
});
// show first image here
changeImage(f, args[index]);
}
}
If I use use the code like
java LoadImageApp *.jpg
it only displays the first image. I can press keys, but the image shown does not change. I want to have the image changed.
I have found revalidate() and repaint() as possible solutions. Despite frame.revalidate() does not exist at all, frame.repaint() (inside changeImage) does still not change anything. I still see the first image displayed.
Is this the right approach anyway? Is there a more elegant way?
I wrote a program to demonstrate what you asked for, here is the code:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageShow {
/** Inner class: JPanel that displays images. **/
static class JImagePanel extends JPanel {
protected final LinkedList<BufferedImage> images;
protected BufferedImage currentImage;
protected int currentIndex;
public JImagePanel(final LinkedList<BufferedImage> images) {
super(true);
this.setFocusable(false);
this.images = images;
this.setIndex(0);
}
/** Has to be private to not cause issues when used in the constructor. **/
private void setIndex(final int index) {
if (index >= this.images.size()) {
this.currentIndex = 0;
} else if (index < 0) {
this.currentIndex = this.images.size() - 1;
} else {
this.currentIndex = index;
}
this.currentImage = this.images.get(this.currentIndex);
this.setPreferredSize(new Dimension(this.currentImage.getWidth(), this.currentImage.getHeight()));
this.repaint();
}
public void shiftIndex(final int amount) {
this.setIndex(this.currentIndex + amount);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(this.currentImage, 0, 0, null);
}
}
public static void main(final String[] args) {
final LinkedList<BufferedImage> images = loadImages(args);
if (images.size() > 0) {
final JFrame window = new JFrame("Image Show");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JImagePanel imagePanel = new JImagePanel(images);
window.add(imagePanel);
window.addKeyListener(new KeyAdapter() {
private void shiftIndex(final int amount) {
imagePanel.shiftIndex(amount);
window.pack();
window.setLocationRelativeTo(null);
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_ESCAPE:
window.dispose();
e.consume();
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_NUMPAD4:
shiftIndex(-1);
e.consume();
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_NUMPAD6:
shiftIndex(+1);
e.consume();
break;
}
}
});
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
} else {
System.err.println("No image could be loaded.\nPlease provide a list of image files as parameters.");
}
}
private static LinkedList<BufferedImage> loadImages(final String[] filenames) {
final LinkedList<BufferedImage> result = new LinkedList<>();
for (String filename : filenames) {
try {
final File file = new File(filename);
final BufferedImage image = ImageIO.read(file);
if (image == null) {
throw new IOException("Unknown image format");
}
result.add(image);
} catch (IOException e) {
System.err.println("Unable to load image \"" + filename + "\": " + e.getMessage());
}
}
return result;
}
}
Please note that this is not the most beautiful way of writing this tool, however it works.
What you should usually do:
Each class should be in its own .java file. The idea is to have a structure, that is easy to read even if you re-visit this code 3 years later.
You should not use variables from another scope like I did here with the window and imagePanel in the main function. Instead use constructors that store local variables with either the value given or a copy of the value (depending on your needs), like I did in the JImagePanel constructor.
Whether or not you need a copy of the value depends on what you do and how much risk you are willing to take. In this example changing the image list after JImagePanel is created would potentially mess things up.
You should never use numbers like you did in your version of the key listener. You never know which key-code corresponds to which key! Whenever available use the provided constants or functions to get such a 'magic' number.
Always expect the worst when it comes to error handling. For once try to catch and handle all possible errors. For second always try to avoid potential issues. A bug you cannot make, is a bug you won't have to bother about.
In your version the image file is loaded from disk every time a button is pressed. What happens if the image is no longer present at that moment? In my version everything is checked before-hand, and once that is done, the program cannot fail anymore (at least not when trying to switch images). ;)
In general: try to find a good book or online tutorial on Java for beginners. If you just hack away, you will miss all those nice things Java has already prepared for you, that will not only speed up developing a lot, it will as well prevent all bugs that you otherwise might code in.
The keyword final indicates that the variable will not change after it has been initialized. In order to use a variable within an anonymous inner class i.e. KeyAdapter it has to be declared final.
So you need:
public static void main(final String[] args) {
and
final JFrame f = new JFrame("Load Image Sample");
But this will not work for index as you are planning on changing it. So I recommed declaring it as a static variable on class level i.e. outside of the function.
private static int index = 0;
This is more or less what you want. I recommend you to study Java from scratch and fill the gap you have.
public class LoadImageApp extends JPanel {
//Current image the Canvas shows
private Image currentImage;
//change the current image and repaint
public void setCurrentImage(Image currentImage) {
this.currentImage = currentImage;
repaint();
}
#Override
public void paintComponent(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
if (currentImage != null)
g.drawImage(currentImage, 0, 0, null);
}
#Override
public Dimension getPreferredSize() {
if (currentImage == null) {
return new Dimension(100, 100);
} else {
return new Dimension(currentImage.getWidth(null), currentImage.getHeight(null));
}
}
public static void main(final String[] args) throws IOException {
if (args.length > 0){
final Image [] images = new Image[args.length];
for (int i = 0; i < images.length; i++){
images[i] = ImageIO.read(new File(args[i]));
}
//It is a goog practice to attach your code to AWT thread.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
LoadImageApp app = new LoadImageApp();
JFrame f = new JFrame("Load Image Sample");
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(app, BorderLayout.CENTER);
f.addKeyListener(new MyKeyAdapter(app, images));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
}
// We create another class for the KeyAdapter
class MyKeyAdapter extends KeyAdapter{
//The canvas so we can tell it that the current image has change
private LoadImageApp canvas;
//index of the current image
private int index;
//All the images
private Image [] images;
public MyKeyAdapter(LoadImageApp canvas, Image[] images) {
super();
this.canvas = canvas;
this.images = images;
rotateRight();
}
#Override
public void keyPressed(KeyEvent event) {
int key = event.getKeyCode();
if (key == 81) {
System.exit(0);
} else if (key == KeyEvent.VK_LEFT) {
rotateLeft();
} else if (key == KeyEvent.VK_RIGHT) {
rotateRight();
}
}
private void rotateRight() {
//change the image in the canvas
canvas.setCurrentImage(images[index]);
//increment index
index++;
//last element + 1, set it to 0
if (index >= images.length) index = 0;
}
private void rotateLeft() {
//change the image in the canvas
canvas.setCurrentImage(images[index]);
//decrement index
index--;
//< 0, set it to last image
if (index < 0) index = images.length - 1;
}
}

Frame refreshing issue

I am trying to create a panel with changing pictures.
This is my panel:
public class AdvertisementPanel extends JPanel {
private BufferedImage image;
private ArrayList<String> pictures;
private int index = 0;
public AdvertisementPanel(String... pics) {
pictures = new ArrayList<String>(Arrays.asList(pics));
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new Runnable() {
#Override
public void run() {
changeImage();
}
}, 0, 5, TimeUnit.SECONDS);
}
public void paint(Graphics g) {
g.drawImage(image, 0, 0, null);
}
private void changeImage() {
String name = pictures.get(index);
try {
File input = new File(name);
image = ImageIO.read(input);
index++;
index %= pictures.size();
} catch (IOException ie) {
Logger.getLogger().log(Level.SEVERE,
"No adds found in given path: " + name);
}
}
I have a frame that holds the panel, but no pictures are shown.
Tried to repaint periodically from the frame - caused some funny, yet unwanted results...
Any ideas why? What am I doing wrong? How should I refresh the frame's components?
you need to repaint each time you change the image.
Oh, and it should be done by the swing event handling thread:
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new Runnable() {
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
changeImage();
repaint();
}
};
}
}, 0, 5, TimeUnit.SECONDS);
UPDATE To correct a few other issues
public class AdvertisementPanel extends JPanel {
private BufferedImage image;
private ArrayList<String> pictures;
private int index = 0;
public AdvertisementPanel(String... pics) {
pictures = new ArrayList<String>(Arrays.asList(pics));
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new Runnable() {
#Override
public void run() {
changeImage();
}
}, 0, 5, TimeUnit.SECONDS);
}
private void changeImage() {
final BufferedImage img = nextImage();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
image = img;
repaint();
}
});
}
public void paint(Graphics g) {
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
private BufferedImage nextImage() {
String name = pictures.get(index);
try {
index++;
index %= pictures.size();
File input = new File(name);
return ImageIO.read(input);
} catch (IOException ie) {
Logger.getLogger("").log(Level.SEVERE,
"No adds found in given path: " + name);
return null;
}
}
}

Java JTextField with input hint

I would like to add a hint value to my javax.swing.JTextField. It should look like Firefox rendering of <input type="text" title="bla">. This creates an edit field with the text 'bla' in the background. If the textbox has focus the title-text disappears and just reappears if the user leaves the editbox without text.
Is there a (free) swing component that does something like this?
You could create your own:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
final JTextField textFieldA = new HintTextField("A hint here");
final JTextField textFieldB = new HintTextField("Another hint here");
frame.add(textFieldA, BorderLayout.NORTH);
frame.add(textFieldB, BorderLayout.CENTER);
JButton btnGetText = new JButton("Get text");
btnGetText.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String message = String.format("textFieldA='%s', textFieldB='%s'",
textFieldA.getText(), textFieldB.getText());
JOptionPane.showMessageDialog(frame, message);
}
});
frame.add(btnGetText, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
}
class HintTextField extends JTextField implements FocusListener {
private final String hint;
private boolean showingHint;
public HintTextField(final String hint) {
super(hint);
this.hint = hint;
this.showingHint = true;
super.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if(this.getText().isEmpty()) {
super.setText("");
showingHint = false;
}
}
#Override
public void focusLost(FocusEvent e) {
if(this.getText().isEmpty()) {
super.setText(hint);
showingHint = true;
}
}
#Override
public String getText() {
return showingHint ? "" : super.getText();
}
}
If you're still on Java 1.5, replace the this.getText().isEmpty() with this.getText().length() == 0.
Here is a simple way that looks good in any L&F:
public class HintTextField extends JTextField {
public HintTextField(String hint) {
_hint = hint;
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (getText().length() == 0) {
int h = getHeight();
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Insets ins = getInsets();
FontMetrics fm = g.getFontMetrics();
int c0 = getBackground().getRGB();
int c1 = getForeground().getRGB();
int m = 0xfefefefe;
int c2 = ((c0 & m) >>> 1) + ((c1 & m) >>> 1);
g.setColor(new Color(c2, true));
g.drawString(_hint, ins.left, h / 2 + fm.getAscent() / 2 - 2);
}
}
private final String _hint;
}
Here is a single class copy/paste solution:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.JTextComponent;
public class HintTextFieldUI extends BasicTextFieldUI implements FocusListener {
private String hint;
private boolean hideOnFocus;
private Color color;
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
repaint();
}
private void repaint() {
if(getComponent() != null) {
getComponent().repaint();
}
}
public boolean isHideOnFocus() {
return hideOnFocus;
}
public void setHideOnFocus(boolean hideOnFocus) {
this.hideOnFocus = hideOnFocus;
repaint();
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
repaint();
}
public HintTextFieldUI(String hint) {
this(hint,false);
}
public HintTextFieldUI(String hint, boolean hideOnFocus) {
this(hint,hideOnFocus, null);
}
public HintTextFieldUI(String hint, boolean hideOnFocus, Color color) {
this.hint = hint;
this.hideOnFocus = hideOnFocus;
this.color = color;
}
#Override
protected void paintSafely(Graphics g) {
super.paintSafely(g);
JTextComponent comp = getComponent();
if(hint!=null && comp.getText().length() == 0 && (!(hideOnFocus && comp.hasFocus()))){
if(color != null) {
g.setColor(color);
} else {
g.setColor(comp.getForeground().brighter().brighter().brighter());
}
int padding = (comp.getHeight() - comp.getFont().getSize())/2;
g.drawString(hint, 2, comp.getHeight()-padding-1);
}
}
#Override
public void focusGained(FocusEvent e) {
if(hideOnFocus) repaint();
}
#Override
public void focusLost(FocusEvent e) {
if(hideOnFocus) repaint();
}
#Override
protected void installListeners() {
super.installListeners();
getComponent().addFocusListener(this);
}
#Override
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener(this);
}
}
Use it like this:
TextField field = new JTextField();
field.setUI(new HintTextFieldUI("Search", true));
Note that it is happening in protected void paintSafely(Graphics g).
Take a look at this one: http://code.google.com/p/xswingx/
It is not very difficult to implement it by yourself, btw. A couple of listeners and custom renderer and voila.
For any Swing component (that is, anything that extends JComponent), you can call the setToolTipText(String) method.
For more information, reference the following links:
API Documentation for setToolTipText
"How to Use Tool Tips" tutorial
Have look at WebLookAndFeel at https://github.com/mgarin/weblaf/
WebTextField txtName = new com.alee.laf.text.WebTextField();
txtName.setHideInputPromptOnFocus(false);
txtName.setInputPrompt("Name");
txtName.setInputPromptFont(new java.awt.Font("Ubuntu", 0, 18));
txtName.setInputPromptForeground(new java.awt.Color(102, 102, 102));
txtName.setInputPromptPosition(0);
If you still look for a solution, here's one that combined other answers (Bart Kiers and culmat) for your reference:
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
public class HintTextField extends JTextField implements FocusListener
{
private String hint;
public HintTextField ()
{
this("");
}
public HintTextField(final String hint)
{
setHint(hint);
super.addFocusListener(this);
}
public void setHint(String hint)
{
this.hint = hint;
setUI(new HintTextFieldUI(hint, true));
//setText(this.hint);
}
public void focusGained(FocusEvent e)
{
if(this.getText().length() == 0)
{
super.setText("");
}
}
public void focusLost(FocusEvent e)
{
if(this.getText().length() == 0)
{
setHint(hint);
}
}
public String getText()
{
String typed = super.getText();
return typed.equals(hint)?"":typed;
}
}
class HintTextFieldUI extends javax.swing.plaf.basic.BasicTextFieldUI implements FocusListener
{
private String hint;
private boolean hideOnFocus;
private Color color;
public Color getColor()
{
return color;
}
public void setColor(Color color)
{
this.color = color;
repaint();
}
private void repaint()
{
if(getComponent() != null)
{
getComponent().repaint();
}
}
public boolean isHideOnFocus()
{
return hideOnFocus;
}
public void setHideOnFocus(boolean hideOnFocus)
{
this.hideOnFocus = hideOnFocus;
repaint();
}
public String getHint()
{
return hint;
}
public void setHint(String hint)
{
this.hint = hint;
repaint();
}
public HintTextFieldUI(String hint)
{
this(hint, false);
}
public HintTextFieldUI(String hint, boolean hideOnFocus)
{
this(hint, hideOnFocus, null);
}
public HintTextFieldUI(String hint, boolean hideOnFocus, Color color)
{
this.hint = hint;
this.hideOnFocus = hideOnFocus;
this.color = color;
}
protected void paintSafely(Graphics g)
{
super.paintSafely(g);
JTextComponent comp = getComponent();
if(hint != null && comp.getText().length() == 0 && (!(hideOnFocus && comp.hasFocus())))
{
if(color != null)
{
g.setColor(color);
}
else
{
g.setColor(Color.gray);
}
int padding = (comp.getHeight() - comp.getFont().getSize()) / 2;
g.drawString(hint, 5, comp.getHeight() - padding - 1);
}
}
public void focusGained(FocusEvent e)
{
if(hideOnFocus) repaint();
}
public void focusLost(FocusEvent e)
{
if(hideOnFocus) repaint();
}
protected void installListeners()
{
super.installListeners();
getComponent().addFocusListener(this);
}
protected void uninstallListeners()
{
super.uninstallListeners();
getComponent().removeFocusListener(this);
}
}
Usage:
HintTextField field = new HintTextField();
field.setHint("Here's a hint");
This can be achieved by using a focus listener to update the text field content.
Make the class implement the focus listener interface:
class YourClass implements FocusListener
Add a method to catch when focus is gained that blanks the field:
public void focusGained(FocusEvent e) {
if(JTextField1.getText().equals("Username")) {
JTextField1.setText("");
}
}
Add a method to catch when focus is lost to redisplay the default entry if the field was blank:
public void focusLost(FocusEvent e) {
if(JTextField1.getText().equals("")) {
JTextField1.setText("Username");
// you should prevent the form from being processed in this state
// as it will literally contain "Username" for the username
}
}
Register your class as the focus listener for text field:
textField.addFocusListener(this);
Learn more at How to Write a Focus Listener in the Java Tutorials.
Here is a fully working example based on Adam Gawne-Cain's earlier Posting. His solution is simple and actually works exceptionally well.
I've used the following text in a Grid of multiple Fields:
H__|__WWW__+__XXXX__+__WWW__|__H
this makes it possible to easily verify the x/y alignment of the hinted text.
A couple of observations:
- there are any number of solutions out there, but many only work superficially and/or are buggy
- sun.tools.jconsole.ThreadTab.PromptingTextField is a simple solution, but it only shows the prompting text when the Field doesn't have the focus & it's private, but nothing a little cut-and-paste won't fix.
The following works on JDK 8 and upwards:
import java.awt.*;
import java.util.stream.*;
import javax.swing.*;
/**
* #author DaveTheDane, based on a suggestion from Adam Gawne-Cain
*/
public final class JTextFieldPromptExample extends JFrame {
private static JTextField newPromptedJTextField (final String text, final String prompt) {
final String promptPossiblyNullButNeverWhitespace = prompt == null || prompt.trim().isEmpty() ? null : prompt;
return new JTextField(text) {
#Override
public void paintComponent(final Graphics USE_g2d_INSTEAD) {
final Graphics2D g2d = (Graphics2D) USE_g2d_INSTEAD;
super.paintComponent(g2d);
// System.out.println("Paint.: " + g2d);
if (getText().isEmpty()
&& promptPossiblyNullButNeverWhitespace != null) {
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
final Insets ins = getInsets();
final FontMetrics fm = g2d.getFontMetrics();
final int cB = getBackground().getRGB();
final int cF = getForeground().getRGB();
final int m = 0xfefefefe;
final int c2 = ((cB & m) >>> 1) + ((cF & m) >>> 1); // "for X in (A, R, G, B) {Xnew = (Xb + Xf) / 2}"
/*
* The hint text color should be halfway between the foreground and background colors so it is always gently visible.
* The variables c0,c1,m,c2 calculate the halfway color's ARGB fields simultaneously without overflowing 8 bits.
* Swing sets the Graphics' font to match the JTextField's font property before calling the "paint" method,
* so the hint font will match the JTextField's font.
* Don't think there are any side effects because Swing discards the Graphics after painting.
* Adam Gawne-Cain, Aug 6 2019 at 15:55
*/
g2d.setColor(new Color(c2, true));
g2d.drawString(promptPossiblyNullButNeverWhitespace, ins.left, getHeight() - fm.getDescent() - ins.bottom);
/*
* y Coordinate based on Descent & Bottom-inset seems to align Text spot-on.
* DaveTheDane, Apr 10 2020
*/
}
}
};
}
private static final GridBagConstraints GBC_LEFT = new GridBagConstraints();
private static final GridBagConstraints GBC_RIGHT = new GridBagConstraints();
/**/ static {
GBC_LEFT .anchor = GridBagConstraints.LINE_START;
GBC_LEFT .fill = GridBagConstraints.HORIZONTAL;
GBC_LEFT .insets = new Insets(8, 8, 0, 0);
GBC_RIGHT.gridwidth = GridBagConstraints.REMAINDER;
GBC_RIGHT.fill = GridBagConstraints.HORIZONTAL;
GBC_RIGHT.insets = new Insets(8, 8, 0, 8);
}
private <C extends Component> C addLeft (final C component) {
this .add (component);
this.gbl.setConstraints(component, GBC_LEFT);
return component;
}
private <C extends Component> C addRight(final C component) {
this .add (component);
this.gbl.setConstraints(component, GBC_RIGHT);
return component;
}
private static final String ALIGN = "H__|__WWW__+__XXXX__+__WWW__|__H";
private final GridBagLayout gbl = new GridBagLayout();
public JTextFieldPromptExample(final String title) {
super(title);
this.setLayout(gbl);
final java.util.List<JTextField> texts = Stream.of(
addLeft (newPromptedJTextField(ALIGN + ' ' + "Top-Left" , ALIGN)),
addRight(newPromptedJTextField(ALIGN + ' ' + "Top-Right" , ALIGN)),
addLeft (newPromptedJTextField(ALIGN + ' ' + "Middle-Left" , ALIGN)),
addRight(newPromptedJTextField( null , ALIGN)),
addLeft (new JTextField("x" )),
addRight(newPromptedJTextField("x", "" )),
addLeft (new JTextField(null )),
addRight(newPromptedJTextField(null, null)),
addLeft (newPromptedJTextField(ALIGN + ' ' + "Bottom-Left" , ALIGN)),
addRight(newPromptedJTextField(ALIGN + ' ' + "Bottom-Right", ALIGN)) ).collect(Collectors.toList());
final JButton button = addRight(new JButton("Get texts"));
/**/ addRight(Box.createVerticalStrut(0)); // 1 last time forces bottom inset
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(740, 260));
this.pack();
this.setResizable(false);
this.setVisible(true);
button.addActionListener(e -> {
texts.forEach(text -> System.out.println("Text..: " + text.getText()));
});
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new JTextFieldPromptExample("JTextField with Prompt"));
}
}

Categories