How to make a clickable image? - java

I'm completely clueless and lost. I recently started programming on Java. I wanted to make a program that displayed an image that the user could click (a button with an image) and in return play a sound. I've watched many tutorials and they don't work when I follow them. Also I don't know whether I should use swing or javaFX or awt, or if I need to make a new file for the images and buttons only. Please help.

Here is a sample using JavaFX. Your question is tagged Swing, but the question text mentions you are considering JavaFX, so I thought I'd provide this solution so that you could see what a JavaFX style implementation would look like.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioClip;
import javafx.stage.Stage;
public class ImageAudioPlayer extends Application {
private static final String BUTTON_ICON_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/fantasy-mediaeval/128/Poison-red-icon.png";
private static final String AUDIO_FILE_LOC =
"http://soundbible.com/mp3/Power_Up_Ray-Mike_Koenig-800933783.mp3";
#Override
public void start(Stage stage) throws Exception {
final AudioClip audioClip = new AudioClip(AUDIO_FILE_LOC);
final ImageView graphic = new ImageView(new Image(BUTTON_ICON_LOC));
Button button = new Button(null, graphic);
button.setStyle("-fx-base: mistyrose;");
button.setOnAction(event -> audioClip.play());
StackPane layout = new StackPane(button);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I don't really know Swing, so I won't provide a solution for that. Library recommendations are off-topic for StackOverflow, so I won't provide a library recommendation here and encourage you to do your own research into potential technologies and decide on the best match that suits your application requirements and skill set.

Search more: it has an answer here:
Icon img = new ImageIcon("/class/path/to/image.png");
JButton btn = new JButton(img);
Make sure /class/path/to/image.png is in the classpath. If it's an image from your hard drive you'll have to load it first, as described in the answer I linked.
Edit: #jewelsea example in JavaFX into Swing:
public class ImageAudioPlayer extends JFrame {
private static final String BUTTON_ICON_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/fantasy-mediaeval/128/Poison-red-icon.png";
private static final String AUDIO_FILE_LOC =
"http://soundbible.com/grab.php?id=1019&type=wav";
public ImageAudioPlayer() throws MalformedURLException {
super("Audion button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
Icon icon = new ImageIcon(new URL(BUTTON_ICON_LOC));
JButton button = new JButton(icon);
cp.add(button, BorderLayout.CENTER);
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
playAudio();
}
});
}
private void playAudio() {
// Not nearly as easy as JavaFX, and cannot play MP3
try {
URL url = new URL(AUDIO_FILE_LOC);
final Clip clip = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
clip.open(ais);
clip.start();
clip.addLineListener(new LineListener() {
#Override public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP)
clip.close();
}
});
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws MalformedURLException {
ImageAudioPlayer iap = new ImageAudioPlayer();
iap.pack();
iap.setVisible(true);
}

Personally I've been experimenting with Swing lately and I think it's rather intuitive, at least at the base level.
What you want is something along the lines of an image object with an added listener for reactions for clicks/whatever it is you wish to react to.
Something like this:
Adding a mouse listener to image or image Icon in java
alternatively you could use the built in button objects in the swing libraries and set an image to it. You would still need to configure the listener to do whatever it you wish it to do.
Along these lines:
How do I add an image to a JButton
Setting up an action listener.

I think if you are a beginner you can start with swing and netbeans: here are a simple tutorial how to handle images in swing :
Other good tutorials:
text : here
video: here

You should either use Swing or JavaFX...
AWT is very old and should not be used unless there is no other way (I heard that sometimes on OSX there are some issues with Swing...).
Swing is the most common GUI-Toolkit in java, but Oracle announced, that JavaFX will completely replace Swing.
In my opinion Swing is easier to start, because there are tools like the eclipse window builder, which enables you to create your application in a graphical interface, but JavaFX is more likely to be used in the future, because it has some great improvements over Swing (like CSS skins etc.).
So you'll basically have to decide what you like more:
JavaFX will be the Toolkit in the Future - Swing is - still - the mostly used one, with more support etc.
And if you are using Swing, I think a JLabel can contain an image - if you add an mouseClicked listener that's probably the way to go...

You can wrap an image object inside of an anchor tag:
<img src="pic_mountain.jpg" alt="Mountain View" style="width:304px;height:228px;">

Related

Java Virtual Keyboard for Mac

I'm working on an on-screen keyboard for Windows and macOS and I've made a little test app. It has a single button and types the letter “M” to the active application. It works for Windows 10, but not Mac (I'm running macOS 10.12). In macOS, as soon as I press the button, whichever app I'm trying to send the "M" to loses focus (the cursor for text entry disappears), even though my single button "keyboard" has setFocusable(false) all over the place. I tried my own MouseListener on the button too.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class main {
private static Robot robot;
private static Rectangle rectangle;
public static void main(String[] args){
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
Button button = new Button("M");
button.setFocusable(false);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(100, 100);
frame.add(button);
frame.setAlwaysOnTop(true);
//set everything I can think of to unfocusable!!!
frame.setFocusable(false);
frame.setAutoRequestFocus(false);
frame.setFocusableWindowState(false);
frame.getRootPane().setFocusable(false);
frame.setVisible(true);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sendKeystroke();
}
});
//Instead of adding a listener to the button, I've also tried my own MouseListener.
/* button.addMouseListener(new MouseTrap());
rectangle = button.getBounds();*/
}
private static void sendKeystroke(){
robot.keyPress(KeyEvent.VK_M);
robot.keyRelease(KeyEvent.VK_M);
}
private static class MouseTrap extends MouseAdapter{
#Override
public void mouseClicked(MouseEvent e) {
if (rectangle.contains(e.getPoint())){
sendKeystroke();
}
}
}
}
It seems like macOS does let some apps have focus without taking the cursor from another. e.g. VMware or spotlight search from the system tray.
Cursor for VMware and IntelliJ at the same time
I've seen other answer which are non-Java:
Virtual Keyboard Cocoa & Objective C
But do I really have to go all native when Java works on Windows? Apart from the learning curve (not done anything native on a Mac), I want to keep Win and Mac versions versions as close as possible.
Anyone know how I could get this working using straight Java?
(Note: As was the case with the questioner for the above link, I can't just use a keyboardview, as I want send modified/additional data from the keyboard e.g. text predictions. I believe that would require additional native code again.)
I have tried to find the way very much. But it seems that it is not possible by pure Java without any native code.

Java GUI App - Overlay Images on a Map (background image)

I want to create a simple GUI application that displays a map of a city.
I then want to programatically add items (assets) such as hotels, restaurants to this map as images.
Pseudo-Code would be as follows
[set up background object with map image covering entire form]
[create hotel1 object (image, label with icon or whatever]
hotel1.image = "hotel.png";
hotel1.size-x = 30;
hotel1.size-y = 30;
hotel1.location-x = 450; (pixels)
hotel1.location-y = 300;
background-object.add(hotel1);
[create restaurant1 object (image, label with icon or whatever]
restaurant1 .image = "hotel.png";
restaurant1 .size-x = 30;
restaurant1 .size-y = 30;
restaurant1 .location-x = 600; (pixels)
restaurant1 .location-y = 400;
background-object.add(restaurant1);
[repeat for hotel2, hotel3, restaurant2 etc...]
This way I could add any number of Assets to the map. The other functions I would require are
change the image of an asset (e.g. to show different image for an asset)
hotel1.image = "hotel_closed.png";
overlap assets (if they are close together)
register a click event handler for each asset
change visibility of asset
hotel1.visible = false;
I am an experienced .Net programmer. This task would be a simple one in .Net, however I am not clear on the best way to accomplish the above in Java. Please could someone suggest the best approach to achieving the above. I am happy to Google if a concept is suggested (I don't need a full coded solution!!)
Many thanks, Ian
There's a lot of places you could start, without knowing the entire requirements (ie if you need to download the maps, tile the maps etc), I can only give you a few overview suggestions
I'd start by having a read through (in no particular order)
Creating a GUI With JFC/Swing
Concurrency in Swing
Custom Painting in Swing
2D Graphics
Basic I/O
I'd also make my self familiar with The Java Tutorials
While most of the above are GUI specific, I'd be reading through things like
Essential classes
Learning the Java Language
Simply because it doesn't matter where you code in Java, these will always be useful.
Happy readings :)
UPDATE
Oh, and of course, the all important API docs (AKA JavaDocs)
UPDATE
When you're reasonable comfortable with all that, you might like to check out SwingX WS, it has a great example of pulling Google & OpenStreet Maps
I am assuming that you want your application to be desktop rather than web based. In which case I have done something similar (though rather more complicated) before using a third party mapping solution. Unfortunately that solution required a licence and is no longer available anyway.
If you just want a simple non-scrollable map in a desktop application I suggest you start with a Swing solution. Look at extending the JComponent object and override the method
public void paintComponent(Graphics g){
// use g to draw things
}
Use the graphics object to paint your map image and your icons. Add this Component to your Swing JFrame and set up the correct sizes and layouts.
If you want this in a webpage then someone else would be better placed to help you.
Edit:
From the feedback given here and in the other post I think you may benefit from a slice of code so here goes:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SwingPaintDemo extends JPanel {
private BufferedImage map = null;
private BufferedImage pointer = null;
public SwingPaintDemo() {
this.setPreferredSize(new Dimension(200, 200));
loadImagesFromFile();
}
private void loadImagesFromFile() {
// load your images form file - these are fakes:
map = new BufferedImage(200, 200, BufferedImage.TYPE_3BYTE_BGR);
pointer = new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = map.getGraphics();
g.setColor(Color.GREEN);
g.fillRect(0, 0, 200, 200);
g = pointer.getGraphics();
g.setColor(Color.BLUE);
g.fillOval(0, 0, 10, 10);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// paint map
g.drawImage(map, 0, 0, this);
// paint pointers
g.drawImage(pointer, 50, 75, this);
}
// this main is for testing the class but can be used as a reference
public static void main(String... args) {
JFrame jf = new JFrame();
SwingPaintDemo mapper = new SwingPaintDemo();
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(mapper, BorderLayout.CENTER);
jf.setVisible(true);
jf.pack();
}
}
You will need to edit this to load in your images from your file - I wanted to make this self contained and easily runnable so I have just created the images inline.
An answer has not been accepted, yet. So, using your pseudo code as an example, I coded up a quick overlay example using JavaFX 2. The WebView can easily be replaced with an ImageView using the JPG file you mentioned.
Here is the code:
package simple.map.overlay;
import java.io.InputStream;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class SimpleMapOverlay extends Application
{
#Override
public void start(Stage primaryStage)
{
WebView mapView = new WebView();
WebEngine webEngine = mapView.getEngine();
String url = "http://maps.google.com/maps?q=Baramerica,+South+Alamo+Street,+San+Antonio,+TX&hl=en&ll=29.416647,-98.488655&spn=0.025196,0.035233&sll=29.416423,-98.489814&sspn=0.006299,0.008808&hq=Baramerica,&hnear=S+Alamo+St,+San+Antonio,+Texas&t=m&z=15";
url += "&output=embed";
webEngine.load(url);
VBox vBox = new VBox(5);
vBox.getChildren().add(mapView);
InputStream instream = SimpleMapOverlay.class.getResourceAsStream("beer.png");
Image beerImage = new Image(instream);
instream = SimpleMapOverlay.class.getResourceAsStream("food.jpg");
Image foodImage = new Image(instream);
Marker laTunaMarker = new Marker(beerImage, "La Tuna");
laTunaMarker.setLayoutX(210);
laTunaMarker.setLayoutY(480);
Marker rosariosMarker = new Marker(foodImage, "Rosarios");
rosariosMarker.setLayoutX(360);
rosariosMarker.setLayoutY(300);
Group root = new Group();
root.getChildren().add(vBox);
root.getChildren().add(laTunaMarker);
root.getChildren().add(rosariosMarker);
Scene scene = new Scene(root);
primaryStage.setTitle("Hello Map World with Markers!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
class Marker extends Group
{
public Marker(Image image, String text)
{
ImageView imageView = new ImageView(image);
Label label = new Label(text);
VBox vbox = new VBox(5);
vbox.getChildren().add(imageView);
vbox.getChildren().add(label);
getChildren().add(vbox);
}
}
}

How do I Highlight buttons when mouse pointer is hovered upon them in Java(Like Start button highlights in XP)?

If mouse pointer is hovered on start button in Windows XP, it highlights. I want to do the same in Java. Can anyone help me?
A possible solution is to create an Icon for your button to be displayed on rollover and then add it to the button via its setRolloverIcon. The mouse's model will do all that is needed to display this Icon.
And even another solution is to add a ChangeListener to the button's model. In the listener if isRollover() returns true, change the display.
E.G. of 1st technique.
import javax.swing.*;
import java.net.URL;
import java.awt.Image;
import javax.imageio.ImageIO;
class ButtonRollover {
public static void main(String[] args) throws Exception {
URL imageUrl2 = new URL("http://pscode.org/media/stromlo2.jpg");
URL imageUrl1 = new URL("http://pscode.org/media/stromlo1.jpg");
final Image image2 = ImageIO.read(imageUrl2);
final Image image1 = ImageIO.read(imageUrl1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JButton button = new JButton("Hover Me!");
button.setIcon(new ImageIcon(image2));
button.setRolloverIcon(new ImageIcon(image1));
JOptionPane.showMessageDialog(null, button);
}
});
}
}
Is this for a web page? If so, you can easily do this sort of thing with CSS.
Further information is required, really.

Flashing JFrame

I would like to create a JFrame with two specifal features:
JFrame should not grab focus while maximized from minimized state.
When a JFrame created or became maximized from minimized state, it should flash in the Windows bar until a user will grant a focus to it. (like as in ICQ clients ).
Does anybody know how the second requirement can be implemented?
Little self-explained example:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class JFrameTest {
private static JFrame childFrame;
public static Container getParentContentPane() {
JPanel panel = new JPanel();
JButton button = new JButton("Create\\Restore child frame");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
createOrRestoreChildFrame();
}
});
panel.add(button);
return panel;
}
private static void createOrRestoreChildFrame() {
if (childFrame == null) {
childFrame = new JFrame("Child Frame");
childFrame.setLocation(200, 200);
childFrame.add(new JLabel("Child Frame"));
childFrame.pack();
setChildFrameVisible();
} else {
setChildFrameVisible();
}
}
private static void setChildFrameVisible() {
childFrame.setFocusableWindowState(false);
childFrame.setVisible(true);
flashInWindowsBar(childFrame);
childFrame.toFront();
childFrame.setFocusableWindowState(true);
}
/**
* Should Make child frame flash in Windows bar.
* Currently, it does not work for me.
* Could anybody help me to fix this please? )
*/
private static void flashInWindowsBar(JFrame childFrame) {
childFrame.setState(JFrame.ICONIFIED);
childFrame.toFront();
}
private static void createAndShowGUI() {
JFrame parentFrame = new JFrame("JFrame Demo");
parentFrame.setLocation(100, 100);
parentFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
parentFrame.setContentPane(getParentContentPane());
parentFrame.pack();
parentFrame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Thanks!
The following code worked for me exactly as you described:
f.setState(JFrame.ICONIFIED);
f.toFront();
f is a JFrame.
Unfortunately, this isn't something that you can do natively under any Java platform. Anyone who manages to get it working by using the kind of 'trickery' that you've shown, will be disappointed to find that it is unlikely to work on another version of Windows, or even another computer with the same version of Windows. The only times I've ever seen a Java window flash is due to some glitch in Swing when minimizing all windows to the taskbar.
As this article on making Java applications feel native shows, it's the same on Mac OS.
Your best bet is to use the techniques described in the above article to make a JNI which does the Windows API call, or get a license for JNIWrapper (search for it) which does it all for you (best option if you are making a commercial app, or making it for a client who is willing to pay for such a feature). It looks like you can get a 30-day trial for that.
The only other thing I could suggest is create a poor-man's equivalent of a pop-up notification system. When you want to alert the user, create a Frame without a border, put it in the bottom-right corner of the screen, make it non-focusable and show it for a brief period of time.
The JPanel does not flash. Try it instead of JFrame.

Java swing JComponent "size"

I'm doing a project where i need some custom swing components. So far I have made a new button with a series of images (the Java Metal look doesn't fit with my UI at all). Ive implemented MouseListener on this new component and this is where my problem arises. My widget changes image on hover, click etc except my MouseListener picks up mouse entry into a the entire GridLayout container instead of into the image. So I have an image of about 200*100 and the surrounding container is about 400*200 and the mouseEntered method is fired when it enters that GridLayout section (even blank space parts of it) instead of over the image. How can I make it so that it is only fired when I hover over the image? Ive tried setting size and bounds and other attributes to no avail.
EDIT: Here's a demonstration of my issue. As you can see (sort of, colors are very similar) the bottom right button is highlighted just by entering its section of the GridlLayout. I only want it highlighted when I'm over the image actual, not the GridLayout section.
I Won't add the MouseListener methods because they just involve switching the displayed image.
public customWidget()
{
this.setLayout(new FlowLayout());
try {
imageDef=ImageIO.read(new File("/home/x101/Desktop/buttonDef.png"));
imageClick=ImageIO.read(new File("/home/x101/Desktop/buttonClick.png"));
imageHover=ImageIO.read(new File("/home/x101/Desktop/buttonHover.png"));
current=imageDef;
} catch (IOException e)
{
e.printStackTrace();
}
this.addMouseListener(this);
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
g.drawImage(current, 0, 0, current.getWidth(), current.getHeight(), null);
}
EDIT: added code section
As an alternative, consider the The Button API, which includes the method setRolloverIcon() "to make the button display the specified icon when the cursor passes over it."
Addendum: For example,
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ButtonIconTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
String base = "http://download.oracle.com/"
+ "javase/tutorial/uiswing/examples/components/"
+ "RadioButtonDemoProject/src/components/images/";
ImageIcon dog = null;
ImageIcon pig = null;
try {
dog = new ImageIcon(new URL(base + "Dog.gif"));
pig = new ImageIcon(new URL(base + "Pig.gif"));
} catch (MalformedURLException ex) {
ex.printStackTrace(System.err);
return;
}
JFrame frame = new JFrame("Rollover Test");
JPanel panel = new JPanel();
panel.add(new JLabel(dog));
panel.add(new JLabel(pig));
JButton button = new JButton(dog);
button.setRolloverIcon(pig);
panel.add(button);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I assume your image contains ONLY 4 'customWidget' objects (in a 2x2 grid).
Your code is working as I would expect. Your MouseListener methods are responding to MouseEvents for 'customWidget' (not the image drawn in 'customWidget'), which is sized to take up 1/4 of the image, so they will respond when it enters the enlarged area. The error is actually in your Test program, because you are allowing the custom button widget to be larger than the image.
If you want a Test program that provides an image similar to yours, you should create a larger grid (say 4x4), and then only place your buttons in every other grid node. Place an empty component into the gaps.
Although I won't answer to your particular question, I hope this helps:
If the components just look wrong maybe you should reuse Swing components and just write a custom Look&Feel or theme.
It would certainly help ensuring the look of the application is consistent and at least you are using the right tool for the task you want to accomplish.
As a sidenote, be aware that Java comes with multiple Look&feels, including Look&Feels made to mimic the native OS theme.
See: http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html

Categories

Resources