0

I'm with a problem and can not solve. I am creating a program that has multiple JFrames, and wanted the popups were shown as the Toast of Android. I found a class that helps me do that. This class has a method that takes the position of the JFrame to create the Toast. The problem is that when I run the JFrame individually, Toast works perfectly, but when I run the complete program, where the button a JFrame calls another JFrame, the method that takes location of the JFrame to create the Toast shows a NullPointerException, as the JFrame assigned as parameter was null. So can not get the location, but individually works. What is wrong? Could anyone help me? Thanks.

Toast code:

public class Toast extends JDialog {
private static final long serialVersionUID = -1602907470843951525L;

public enum Style {
    NORMAL, SUCCESS, ERROR
};

public static final int LENGTH_SHORT = 3000;
public static final int LENGTH_LONG = 6000;
public static final Color ERROR_RED = new Color(121, 0, 0);
public static final Color SUCCESS_GREEN = new Color(22, 127, 57);
public static final Color NORMAL_BLACK = new Color(0, 0, 0);

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 = 7;
private final int DISTANCE_FROM_PARENT_TOP = 100;

private JFrame mOwner;
private String mText;
private int mDuration;
private Color mBackgroundColor = Color.BLACK;
private Color mForegroundColor = Color.WHITE;

public Toast(JFrame owner) {
    super(owner);
    mOwner = owner;
}

private void createGUI() {
    setLayout(new GridBagLayout());
    addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            setShape(new RoundRectangle2D.Double(0, 0, getWidth(),
                    getHeight(), WINDOW_RADIUS, WINDOW_RADIUS));
        }
    });

    setAlwaysOnTop(true);
    setUndecorated(true);
    setFocusableWindowState(false);
    setModalityType(ModalityType.MODELESS);
    setSize(mText.length() * CHARACTER_LENGTH_MULTIPLIER, 25);
    getContentPane().setBackground(mBackgroundColor);

    JLabel label = new JLabel(mText);
    label.setForeground(mForegroundColor);
    add(label);
}

public void fadeIn() {
    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();
            }
        }
    });

    setOpacity(0);
    timer.start();

    setLocation(getToastLocation());
    setVisible(true);
}

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();
}

private Point getToastLocation() {
    System.out.println(mOwner);
    Point ownerLoc = mOwner.getLocation();
    int x = (int) (ownerLoc.getX() + ((mOwner.getWidth() - this.getWidth()) / 2));
    int y = (int) (ownerLoc.getY() + DISTANCE_FROM_PARENT_TOP);
    return new Point(x, y);
}

public void setText(String text) {
    mText = text;
}

public void setDuration(int duration) {
    mDuration = duration;
}

@Override
public void setBackground(Color backgroundColor) {
    mBackgroundColor = backgroundColor;
}

@Override
public void setForeground(Color foregroundColor) {
    mForegroundColor = foregroundColor;
}

public static Toast makeText(JFrame owner, String text) {
    return makeText(owner, text, LENGTH_SHORT);
}

public static Toast makeText(JFrame owner, String text, Style style) {
    return makeText(owner, text, LENGTH_SHORT, style);
}

public static Toast makeText(JFrame owner, String text, int duration) {
    return makeText(owner, text, duration, Style.NORMAL);
}

public static Toast makeText(JFrame owner, String text, int duration,
        Style style) {
    Toast toast = new Toast(owner);
    toast.mText = text;
    toast.mDuration = duration;

    if (style == Style.SUCCESS)
        toast.mBackgroundColor = SUCCESS_GREEN;
    if (style == Style.ERROR)
        toast.mBackgroundColor = ERROR_RED;
    if (style == Style.NORMAL)
        toast.mBackgroundColor = NORMAL_BLACK;

    return toast;
}

public void display() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                createGUI();
                fadeIn();
                Thread.sleep(mDuration);
                fadeOut();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }).start();
}

JFrame code:

public class MenuAtendente extends JFrame {

private JPanel contentPane;
private static JLabel lblInfo;
static MenuAtendente frame;

/**
 * Launch the application.
 */

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                frame = new MenuAtendente();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public MenuAtendente() {
    setTitle("SGTA - <Nome da Academia>");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JFrame teste = frame;
    setBounds(100, 100, 663, 449);
    setLocationRelativeTo(null);
    setResizable(false);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JLabel lblMenuAtendente = new JLabel("Menu Atendente");
    lblMenuAtendente.setFont(new Font("Tahoma", Font.PLAIN, 17));
    lblMenuAtendente.setBounds(22, 11, 165, 28);
    contentPane.add(lblMenuAtendente);

    JButton btnCadastrarAluno = new JButton("Cadastrar Novo Aluno");
    btnCadastrarAluno.setBounds(10, 75, 213, 84);
    contentPane.add(btnCadastrarAluno);
    btnCadastrarAluno.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            CadastroAlunosForm tela;
            try {
                tela = new CadastroAlunosForm();
                tela.setVisible(true);
                setVisible(false);
            } catch (ParseException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }
    });

    JButton btnPerfilDeAlunos = new JButton("Perfil de Alunos");
    btnPerfilDeAlunos.setBounds(10, 172, 170, 84);
    contentPane.add(btnPerfilDeAlunos);
    btnPerfilDeAlunos.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                PerfilUsuario tela = new PerfilUsuario();
                tela.setVisible(true);
                setVisible(false);
            } catch (ParseException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

        }
    });

    JButton btnRelatoriosDeAluno = new JButton("Relat\u00F3rios de Alunos");
    btnRelatoriosDeAluno.setBounds(10, 277, 225, 84);
    contentPane.add(btnRelatoriosDeAluno);
    btnRelatoriosDeAluno.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println(frame);
            Toast.makeText(frame, "Olá", Style.SUCCESS).display();

        }
    });

    JButton btnLogout = new JButton("Logout");
    btnLogout.setBounds(419, 17, 89, 23);
    contentPane.add(btnLogout);
    btnLogout.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            SessaoUsuario.getInstancia().setUsuarioLogado(null);
            Login tela = new Login();
            tela.setVisible(true);
            dispose();
        }
    });

    lblInfo = new JLabel("");
    lblInfo.setBounds(10, 386, 581, 14);
    contentPane.add(lblInfo);

    JButton button = new JButton("Alterar Cadastro Aluno");
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            AlterarCadastroAlunosForm tela;
            try {
                tela = new AlterarCadastroAlunosForm();
                tela.setVisible(true);
                dispose();
            } catch (ParseException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

        }
    });
    button.setBounds(267, 75, 177, 84);
    contentPane.add(button);
}

public static void getLblInfo(String mensagem) {
    lblInfo.setText(mensagem);
}

}
  • You will get answers more quickly if you create an [MCVE](http://stackoverflow.com/help/mcve). See what it means exactly in the link. Yes, it will take you an hour or so to write it, but (a) you might find what's wrong simply by tweaking your program, and (b) it will be easier for us to run it and help you. – RealSkeptic Jan 17 '15 at 16:52
  • See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/q/9554636/418556) – Andrew Thompson Jan 18 '15 at 01:07

1 Answers1

0

You can always get the parent top-level window of a displayed component using SwingUtilities.getWindowAncestor(component). For example

Window win = SwingUtilities.getWindowAncestor(someComponent);
Point ownerLoc = win.getLocation();

As an aside,

  • You probably don't want to have more than one JFrame in this program, and perhaps the 2nd window should be a JDialog or consider swapping JPanel views via a CardLayout. If you need to show an undecorated window, I wonder if JWindow would be better -- I'm not sure.
  • Your use of null layouts and setBounds(...) is dangerous code and can bite you in the end. You're far better off using layout managers to help you organize the position and size of your components.
  • Your display method is not Swing thread safe as you're making Swing calls, in the createGUI, fadeIn and fadeOut methods, on a background thread. Better to use a Swing Timer for this.

Edit This is my take so far on trying to make a minimal example program with your code:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.*;
import java.awt.geom.RoundRectangle2D;

import javax.swing.*;
import javax.swing.border.*;

public class FooGui {
   public static void main(String[] args) {
      MenuAtendente.main(args);
   }
}

@SuppressWarnings("serial")
class MenuAtendente extends JFrame {

   private JPanel contentPane;
   private static JLabel lblInfo;
   static MenuAtendente frame;

   /**
    * Launch the application.
    */

   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               frame = new MenuAtendente();
               frame.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }

   /**
    * Create the frame.
    */
   public MenuAtendente() {
      setTitle("SGTA - <Nome da Academia>");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setBounds(100, 100, 663, 449);
      setLocationRelativeTo(null);
      setResizable(false);
      contentPane = new JPanel();
      contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
      setContentPane(contentPane);
      contentPane.setLayout(null); // *** ugh, don't do this.

      JButton btnRelatoriosDeAluno = new JButton("Relat\u00F3rios de Alunos");
      btnRelatoriosDeAluno.setBounds(10, 277, 225, 84);
      contentPane.add(btnRelatoriosDeAluno);
      btnRelatoriosDeAluno.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            //!! 
            System.out.println(frame);
            Toast.makeText(frame, "Olá", Toast.Style.SUCCESS).display();
         }
      });

   }

   public static void getLblInfo(String mensagem) {
      lblInfo.setText(mensagem);
   }

}

class Toast extends JDialog {
   private static final long serialVersionUID = -1602907470843951525L;

   public enum Style {
      NORMAL, SUCCESS, ERROR
   };

   public static final int LENGTH_SHORT = 3000;
   public static final int LENGTH_LONG = 6000;
   public static final Color ERROR_RED = new Color(121, 0, 0);
   public static final Color SUCCESS_GREEN = new Color(22, 127, 57);
   public static final Color NORMAL_BLACK = new Color(0, 0, 0);

   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 = 7;
   private final int DISTANCE_FROM_PARENT_TOP = 100;

   private JFrame mOwner;
   private String mText;
   private int mDuration;
   private Color mBackgroundColor = Color.BLACK;
   private Color mForegroundColor = Color.WHITE;

   public Toast(JFrame owner) {
      super(owner);
      mOwner = owner;
   }

   private void createGUI() {
      setLayout(new GridBagLayout());
      addComponentListener(new ComponentAdapter() {
         @Override
         public void componentResized(ComponentEvent e) {
            setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(),
                  WINDOW_RADIUS, WINDOW_RADIUS));
         }
      });

      setAlwaysOnTop(true);
      setUndecorated(true);
      setFocusableWindowState(false);
      setModalityType(ModalityType.MODELESS);
      setSize(mText.length() * CHARACTER_LENGTH_MULTIPLIER, 25);
      getContentPane().setBackground(mBackgroundColor);

      JLabel label = new JLabel(mText);
      label.setForeground(mForegroundColor);
      add(label);
   }

   public void fadeIn() {
      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();
            }
         }
      });

      setOpacity(0);
      timer.start();

      setLocation(getToastLocation());
      setVisible(true);
   }

   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();
   }

   private Point getToastLocation() {
      System.out.println("Here!");
      System.out.println(mOwner);
      Point ownerLoc = mOwner.getLocation();
      // !! Window win = SwingUtilities.getWindowAncestor(someComponent);
      // Point ownerLoc = win.getLocation();
      int x = (int) (ownerLoc.getX() + ((mOwner.getWidth() - this.getWidth()) / 2));
      int y = (int) (ownerLoc.getY() + DISTANCE_FROM_PARENT_TOP);
      return new Point(x, y);
   }

   public void setText(String text) {
      mText = text;
   }

   public void setDuration(int duration) {
      mDuration = duration;
   }

   @Override
   public void setBackground(Color backgroundColor) {
      mBackgroundColor = backgroundColor;
   }

   @Override
   public void setForeground(Color foregroundColor) {
      mForegroundColor = foregroundColor;
   }

   public static Toast makeText(JFrame owner, String text) {
      return makeText(owner, text, LENGTH_SHORT);
   }

   public static Toast makeText(JFrame owner, String text, Style style) {
      return makeText(owner, text, LENGTH_SHORT, style);
   }

   public static Toast makeText(JFrame owner, String text, int duration) {
      return makeText(owner, text, duration, Style.NORMAL);
   }

   public static Toast makeText(JFrame owner, String text, int duration,
         Style style) {
      Toast toast = new Toast(owner);
      toast.mText = text;
      toast.mDuration = duration;

      if (style == Style.SUCCESS)
         toast.mBackgroundColor = SUCCESS_GREEN;
      if (style == Style.ERROR)
         toast.mBackgroundColor = ERROR_RED;
      if (style == Style.NORMAL)
         toast.mBackgroundColor = NORMAL_BLACK;

      return toast;
   }

   public void display() {
      new Thread(new Runnable() {
         @Override
         public void run() {
            try {
               createGUI();
               fadeIn();
               Thread.sleep(mDuration);
               fadeOut();
            } catch (Exception ex) {
               ex.printStackTrace();
            }
         }
      }).start();
   }
}

Edit A better, more thread-safe display() method:

public void display() {
   final Timer timer = new Timer(mDuration, new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
         fadeOut();
      }
   });
   timer.setRepeats(false);
   createGUI();
   fadeIn();
   timer.start();
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Thanks for answering. But I wanted to understand why when I open the JFrame individually, it works, but when I call the JFrame from another JFrame, JFrame frame attribute is null. – Edvan Junior Jan 17 '15 at 17:05
  • @EdvanJunior: I can't tell based on your code, since when I tried to make a compilable/runnable version out of your code, I could not reproduce your exception. For better help, consider condensing your code by creating and posting a minimal code example that demonstrates your problem, an [SSCCE](http://sscce.org). This will allow us to run your code and modify it and perhaps even correct it. Please read the link before replying as it supplies many important details on the SSCCE requirements. – Hovercraft Full Of Eels Jan 17 '15 at 17:07
  • @EdvanJunior: Please understand that in order for me to make sense out of a huge code base, I would have to put in considerable effort to try to distill the problem down to its core. Please remember that we are all volunteers here, myself included, and so if you need a solution to your problem, the effort to distilling the problem and the code down should be yours and yours alone. I again suggest that you create and post a minimal example program that we can run and that demonstrates for us your problem. This code should be posted here in its entirety and not in a link. – Hovercraft Full Of Eels Jan 17 '15 at 17:15
  • @EdvanJunior: as an aside, your display method is not Swing thread safe as you're making Swing calls, in the createGUI, fadeIn and fadeOut methods, on a background thread. Better to use a Swing Timer for this. – Hovercraft Full Of Eels Jan 17 '15 at 17:22
  • @EdvanJunior: I've posted what I've done so far to try to reduce your problem to its core. Please feel free to change the code that I've posted so that it reproduces your problem for us. – Hovercraft Full Of Eels Jan 17 '15 at 17:25
  • Thank you for your help. I got to solve the problem by placing the JFrame attribute as final. – Edvan Junior Jan 17 '15 at 17:27
  • @EdvanJunior: I'm glad that you've got things working. Please note my edit showing a better `display()` method, one that is thread safe. Please take my recommendations regarding posting a minimal example program to heart for your future questions. – Hovercraft Full Of Eels Jan 17 '15 at 17:33