I am trying to develop a Toast (Android) like feature in my Swing application. As a standalone, its working perfectly. But when integrated into the application, its posing problems.
The Class file is:
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.RoundRectangle2D;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
import net.mindcrew.utils.LayoutHelper.Packer;
public class Toast extends JDialog {
String text;
public Toast(String text) {
this.text = text;
initComponents();
}
private void initComponents(){
setLayout(new GridBagLayout());
addComponentListener(new ComponentAdapter() {
// Give the window an rounded rect shape. LOOKS GOOD
// If the window is resized, the shape is recalculated here.
@Override
public void componentResized(ComponentEvent e) {
setShape(new RoundRectangle2D.Double(0,0,getWidth(),getHeight(),50,50));
}
});
setUndecorated(true);
setSize(300,100);
setLocationRelativeTo(null);
getContentPane().setBackground(Color.BLACK);
// Determine what the GraphicsDevice can support.
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
final boolean isTranslucencySupported =
gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT);
//If shaped windows aren't supported, exit.
if (!gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) {
System.err.println("Shaped windows are not supported");
}
//If translucent windows aren't supported,
//create an opaque window.
if (!isTranslucencySupported) {
System.out.println(
"Translucency is not supported, creating an opaque window");
}
// Set the window to 70% translucency, if supported.
if (isTranslucencySupported) {
setOpacity(0.9f);
}
ImageIcon loading = new ImageIcon(Toast.class.getResource("/net/mindcrew/utils/userinterface/resources/loading-photo.gif"));
JLabel label = new JLabel(text);
label.setForeground(Color.WHITE);
label.setIcon(loading);
Packer packer = new Packer(this);
packer.pack(label).fillboth().west().inset(0, 50, 0, 20);
}
public static Toast showDailog(String textToDisplay){
final Toast toast = new Toast(textToDisplay);
// Display the window.
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
toast.setVisible(true);
}
});
thread.start();
return toast;
}
@Override
public void hide(){
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setVisible(false);
dispose();
}
});
}
public static void main(String... args){
Toast toast = Toast.showDailog("Display");
try{
Thread.sleep(5000);
}
catch (Exception e){}
toast.hide();
}
}
There may be some implementation faults, but this is the basic thing.
This works well. But when I try to put it up in the way of a resource intensive operation, its tripping. As in the GIF animation is not showing up, which I think implies that its sort of stalled.
The use is:
Toast toast = Toast.showDailog("Generating PDF");
//resource intensive operation. Takes about 3-5seconds to execute
toast.hide();
To add to my misery, even after the "Toast" has been disposed, the application is becoming dreadfully slow. I am pretty sure that the slowing down is not because of the operation in question, since its working perfectly if I do away with the "Toast".
Can somebody please point out what is wrong here???
I went through this question. But the things there are far too complicated than what I am looking for. What I am looking for is a simple dialog. Not a full blown frame which needs to accommodate several components.
Instantiate a Toast objectUse the makeText() method, which takes the following parameters: The application Context . The text that should appear to the user. The duration that the toast should remain on the screen.
A Toast in Android is a message that appears on the screen for a specific time whenever invoked. This message appears at the bottom of the application leaving some margin at the bottom. In general, a Toast can be displayed for either 2 seconds (Toast. LENGTH_SHORT) or 3.5 seconds (Toast.
A toast is a short, informational message that an app displays briefly near the bottom of the screen. Only one toast can be displayed at a time. The toast tells a user about an action the app has taken or will take. It does not require any user action or response. After 8 seconds, the toast disappears automatically.
You can use a rounded self-disposing JFrame as overlay which is positioned relative to your application window. By fading it in an out it looks like an Android Toast. Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
class Toast extends JFrame {
private final float MAX_OPACITY = 0.8f;
private final float OPACITY_INCREMENT = 0.05f;
private final int FADE_REFRESH_RATE = 20;
private final int WINDOW_RADIUS = 15;
private final int CHARACTER_LENGTH_MULTIPLIER = 9;
private final int DISTANCE_FROM_PARENT_BOTTOM = 100;
public Toast(JFrame owner, String toastText) {
setTitle("Transparent JFrame Demo");
setLayout(new GridBagLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUndecorated(true);
setFocusableWindowState(false);
setOpacity(0.4f);
// setup the toast lable
JLabel b1 = new JLabel(toastText);
b1.setForeground(Color.WHITE);
b1.setOpaque(false);
add(b1);
setSize(toastText.length() * CHARACTER_LENGTH_MULTIPLIER, 50);
int x = (int) (owner.getLocation().getX() + (owner.getWidth() / 2));
int y = (int) (owner.getLocation().getY() + owner.getHeight() - DISTANCE_FROM_PARENT_BOTTOM);
setLocation(new Point(x, y));
// configure frame
setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), WINDOW_RADIUS, WINDOW_RADIUS));
getContentPane().setBackground(new Color(0, 0, 0, 170));
}
public void fadeIn() {
setOpacity(0);
setVisible(true);
final Timer timer = new Timer(FADE_REFRESH_RATE, null);
timer.setRepeats(true);
timer.addActionListener(new ActionListener() {
private float opacity = 0;
@Override
public void actionPerformed(ActionEvent e) {
opacity += OPACITY_INCREMENT;
setOpacity(Math.min(opacity, MAX_OPACITY));
if (opacity >= MAX_OPACITY) {
timer.stop();
}
}
});
timer.start();
}
public void fadeOut() {
final Timer timer = new Timer(FADE_REFRESH_RATE, null);
timer.setRepeats(true);
timer.addActionListener(new ActionListener() {
private float opacity = MAX_OPACITY;
@Override
public void actionPerformed(ActionEvent e) {
opacity -= OPACITY_INCREMENT;
setOpacity(Math.max(opacity, 0));
if (opacity <= 0) {
timer.stop();
setVisible(false);
dispose();
}
}
});
setOpacity(MAX_OPACITY);
timer.start();
}
public static void makeToast(final JFrame owner, final String toastText, final int durationSec) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Toast toastFrame = new Toast(owner, toastText);
toastFrame.fadeIn();
Thread.sleep(durationSec * 1000);
toastFrame.fadeOut();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}).start();
}
public static void main(String args[]) {
final JFrame frame = new JFrame("Cloud Tester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jPanel = new JPanel();
jPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
JButton toastButton = new JButton("show toast");
jPanel.add(toastButton);
toastButton.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
Toast.makeToast(frame, "a toast!", 3);
}
});
frame.add(jPanel);
frame.setSize(800, 600);
frame.setVisible(true);
}
}
Class below is ToastMessage.java, should provide an Android-ish toast message. Call it from your project using new ToastMessage(this, "Short message here!");
Note this
can be any component or panel from your calling JFrame, used to determine the location on screen.
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.Window;
import java.awt.geom.RoundRectangle2D;
import javax.swing.*;
public class ToastMessage extends JDialog {
private static final long serialVersionUID = 1L;
private static Boolean spamProtect = false;
private final int milliseconds = 1500;
public ToastMessage(JComponent caller, String toastString) {
if(spamProtect) {
return;
}
setUndecorated(true);
setAlwaysOnTop(true);
setFocusableWindowState(false);
setLayout(new GridBagLayout());
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
panel.setBackground(new Color(160, 160, 160));
JLabel toastLabel = new JLabel(toastString);
toastLabel.setForeground(Color.WHITE);
panel.add(toastLabel);
add(panel);
pack();
Window window = SwingUtilities.getWindowAncestor(caller);
int xcoord = window.getLocationOnScreen().x + window.getWidth() / 2 - getWidth() / 2;
int ycoord = window.getLocationOnScreen().y + (int)((double)window.getHeight() * 0.75) - getHeight() / 2;
setLocation(xcoord, ycoord);
setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 30, 30));
setVisible(true);
new Thread(){
public void run() {
try {
spamProtect = true;
Thread.sleep(milliseconds);
dispose();
spamProtect = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With