Drawing warning symbol during form validation in Swing - java

I have developed a swing form which validates entries as the focus is lost from JTextComponent
and if the entry is correct ,the background is painted green Otherwise it is painted red.
Here is the code :-
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
public class Form extends JFrame implements FocusListener{
JTextField fname,lname,phone,email,address;
BufferedImage img;
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable(){public void run(){new Form();}});
}
public Form()
{
super("Form with Validation Capability");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,300);
setLayout(new GridLayout(5,3));
try {
img=ImageIO.read(new File("src/warning.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
add(new JLabel("First Name :"));
add(fname=new JTextField(20));
add(new JLabel("Last Name :"));
add(lname=new JTextField(20));
add(new JLabel("Phone Number :"));
add(phone=new JTextField(10));
add(new JLabel("Email:"));
add(email=new JTextField(20));
add(new JLabel("Address :"));
add(address=new JTextField(20));
fname.addFocusListener(this);
lname.addFocusListener(this);
phone.addFocusListener(this);
email.addFocusListener(this);
address.addFocusListener(this);
setVisible(true);
}
public void focusGained(FocusEvent e)
{
((JTextComponent) e.getSource()).setBackground(Color.WHITE);
}
public void focusLost(FocusEvent e)
{
if(e.getSource().equals(fname))
{
validationForText(fname);
}
else if(e.getSource().equals(lname))
{
validationForText(lname);
}
else if(e.getSource().equals(email))
{
validationForEmail(email);
}
else if(e.getSource().equals(phone))
{
validationForNumber(phone);
}
else{
((JTextComponent) e.getSource()).setBackground(Color.GREEN);
}
}
public void validationForText(JTextComponent comp)
{
String temp=comp.getText();
if (temp.matches("^[A-Za-z]+$")) {
comp.setBackground(Color.GREEN);
}
else
comp.setBackground(Color.RED);
}
public void validationForNumber(JTextComponent comp)
{
String text=comp.getText();
if(text.matches("^[0-9]+$"))
comp.setBackground(Color.GREEN);
else
comp.setBackground(Color.RED);
}
public void validationForEmail(JTextComponent comp)
{
String text=comp.getText();
if(text.matches("[^#]+#([^.]+\\.)+[^.]+"))
comp.setBackground(Color.GREEN);
else
comp.setBackground(Color.RED);
}
}
Here is the output to my simple app :
Now I also want to draw a warning symbol (buffered image) at the lower left corner of incorrect field.Can anyone help me how to do this as i am not understanding where to paint the image.
(I would like to do it using JLayeredPane as I am learning its application,any code snippet will really help).

Why not simply add a JLabel (using an appropriate LayoutManager to position it) with the inbuilt Swing warning icon UIManager.getIcon("OptionPane.warningIcon")
like so:
JLabel label=new JLabel(UIManager.getIcon("OptionPane.warningIcon"));
see here for more.
UPDATE:
As per your comment I would rather use GlassPane (and add JLabel to glasspane) for this as opposed too JLayeredPane. See here for more on RootPanes
Some suggestions:
Dont extend JFrame unnecessarily
Dont call setSize on JFrame. Use a correct LayoutManager and/or override getPreferredSize() where necessary and replace setSize call with pack() just before setting JFrame visible.
Dont implement FocusListener on the class unless you want to share the functionality with other classes.
Also get into the habit of using FocusAdapter vs FocusListener this applies to a few with appended Listener i.e MouseListener can be replaced for MouseAdapter. This allows us to only override the methods we want. In this case listener is correct as we do something on both overridden methods, but as I said more about the habit
Also always call super.XXX implementation of overridden methods i.e focusGained(FocusEvent fe) unless you are ignoring it for a reason
Here is code with above fixes including glasspane to show warning icon when field is red:
And removes it when is corrected:
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;
/**
*
* #author David
*/
public class GlassValidationPane extends JComponent {
private static JTextField fname, lname, phone, email, address;
private static GlassValidationPane gvp = new GlassValidationPane();
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Form with Validation Capability");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//f.setResizable(false);
f.setLayout(new GridLayout(5, 3));
f.add(new JLabel("First Name :"));
f.add(fname = new JTextField(20));
f.add(new JLabel("Last Name :"));
f.add(lname = new JTextField(20));
f.add(new JLabel("Phone Number :"));
f.add(phone = new JTextField(10));
f.add(new JLabel("Email:"));
f.add(email = new JTextField(20));
f.add(new JLabel("Address :"));
f.add(address = new JTextField(20));
f.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent ce) {
super.componentResized(ce);
gvp.refreshLocations();
}
});
FocusAdapter fl = new FocusAdapter() {
#Override
public void focusGained(FocusEvent fe) {
super.focusGained(fe);
((JTextComponent) fe.getSource()).setBackground(Color.WHITE);
}
#Override
public void focusLost(FocusEvent fe) {
super.focusLost(fe);
if (fe.getSource().equals(fname)) {
validationForText(fname);
} else if (fe.getSource().equals(lname)) {
validationForText(lname);
} else if (fe.getSource().equals(email)) {
validationForEmail(email);
} else if (fe.getSource().equals(phone)) {
validationForNumber(phone);
} else {
gvp.removeWarningIcon(((Component) fe.getSource()));
((JTextComponent) fe.getSource()).setBackground(Color.GREEN);
}
}
};
fname.addFocusListener(fl);
lname.addFocusListener(fl);
phone.addFocusListener(fl);
email.addFocusListener(fl);
address.addFocusListener(fl);
f.setGlassPane(gvp);
f.pack();
f.setVisible(true);
gvp.setVisible(true);
}
public void validationForText(JTextComponent comp) {
String temp = comp.getText();
if (temp.matches("^[A-Za-z]+$")) {
setGreen(comp);
} else {
setRed(comp);
}
}
public void validationForNumber(JTextComponent comp) {
String text = comp.getText();
if (text.matches("^[0-9]+$")) {
setGreen(comp);
} else {
setRed(comp);
}
}
public void validationForEmail(JTextComponent comp) {
String text = comp.getText();
if (text.matches("[^#]+#([^.]+\\.)+[^.]+")) {
setGreen(comp);
} else {
setRed(comp);
}
}
private void setRed(JTextComponent comp) {
comp.setBackground(Color.RED);
gvp.showWarningIcon(comp);
}
private void setGreen(JTextComponent comp) {
comp.setBackground(Color.GREEN);
gvp.removeWarningIcon(comp);
}
});
}
private HashMap<Component, JLabel> warningLabels = new HashMap<>();
private ImageIcon warningIcon;
public GlassValidationPane() {
setLayout(null);//this is the exception to the rule case a layoutmanager might make setting Jlabel co-ords harder
setOpaque(false);
Icon icon = UIManager.getIcon("OptionPane.warningIcon");
int imgW = icon.getIconWidth();
int imgH = icon.getIconHeight();
BufferedImage img = ImageUtilities.getBufferedImageOfIcon(icon, imgW, imgH);
warningIcon = new ImageIcon(ImageUtilities.resize(img, 24, 24));
}
void showWarningIcon(Component c) {
if (warningLabels.containsKey(c)) {
return;
}
JLabel label = new JLabel();
label.setIcon(warningIcon);
//int x=c.getX();//this will make it insode the component
int x = c.getWidth() - label.getIcon().getIconWidth();//this makes it appear outside/next to component
int y = c.getY();
label.setBounds(x, y, label.getIcon().getIconWidth(), label.getIcon().getIconHeight());
add(label);
label.setVisible(true);
revalidate();
repaint();
warningLabels.put(c, label);
}
public void removeWarningIcon(Component c) {
for (Map.Entry<Component, JLabel> entry : warningLabels.entrySet()) {
Component component = entry.getKey();
JLabel jLabel = entry.getValue();
if (component == c) {
remove(jLabel);
revalidate();
repaint();
break;
}
}
warningLabels.remove(c);
}
public void refreshLocations() {
for (Map.Entry<Component, JLabel> entry : warningLabels.entrySet()) {
Component c = entry.getKey();
JLabel label = entry.getValue();
//int x=c.getX();//this will make it insode the component
int x = c.getWidth() - label.getIcon().getIconWidth();//this makes it appear outside/next to component
int y = c.getY();
label.setBounds(x, y, label.getIcon().getIconWidth(), label.getIcon().getIconHeight());
revalidate();
repaint();
}
}
}
class ImageUtilities {
public static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
}
public static BufferedImage getBufferedImageOfIcon(Icon icon, int imgW, int imgH) {
BufferedImage img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
icon.paintIcon(null, g2d, 0, 0);
g2d.dispose();
return img;
}
}

Related

Java drawstring working fine in earlier part of the code to count points but doesn't work when to show game over [duplicate]

After learning that dispose() should be called on Graphics/Graphics2D object after use, I went about changing my game to incorporate this.
When I added g2d.dispose() in overridden paintComponent(Graphics g) of JPanel, my components which I added (extensions of JLabel class) where not rendered I was able to still click on them etc but they would not be painted.
I tested with a normal JLabel and JButton with same effect (though JButton is rendered when mouse is over it).
So my question is why does this happen?
Here is an SSCCE to demonstrate:
after uncommenting call to dispose() in paintComponent of MainMenuPanel class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
try {
initComponents();
} catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
MainMenuPanel mmp = new MainMenuPanel();
frame.add(mmp);
frame.pack();
frame.setVisible(true);
}
}
class MainMenuPanel extends JPanel {
//create labels for Main Menu
private PopUpJLabel versusesModeLabel;
private PopUpJLabel singlePlayerModeLabel;
private PopUpJLabel optionsLabel;
private PopUpJLabel helpLabel;
private PopUpJLabel aboutLabel;
//create variable to hold background
private Image background;
private Dimension preferredDimensions;
public static String gameType;
public static final String SINGLE_PLAYER = "Single Player", VERSUS_MODE = "VS Mode";
/**
* Default constructor to initialize double buffered JPanel with
* GridBagLayout
*/
public MainMenuPanel() {
super(new GridBagLayout(), true);
try {
initComponents();
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Could not load main menu background!", "Main Menu Error: 0x004", JOptionPane.ERROR_MESSAGE);
System.exit(4);
}
}
/*
* Create JPanel and its components
*/
private void initComponents() throws Exception {
//set prefered size of JPanel
preferredDimensions = new Dimension(800, 600);
background = scaleImage(800, 600, ImageIO.read(new URL("http://photos.appleinsider.com/12.08.30-Java.jpg")));
//create label instances
singlePlayerModeLabel = new PopUpJLabel("Single Player Mode");
singlePlayerModeLabel.setEnabled(false);
versusesModeLabel = new PopUpJLabel("Versus Mode");
optionsLabel = new PopUpJLabel("Options");
helpLabel = new PopUpJLabel("Help");
aboutLabel = new PopUpJLabel("About");
//create new constraints for gridbag
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.HORIZONTAL;
gc.ipady = 50;//vertical spacing
//add newGameLabel to panel with constraints
gc.gridx = 0;
gc.gridy = 0;
add(singlePlayerModeLabel, gc);
gc.gridy = 1;
add(versusesModeLabel, gc);
//add optionsLabel to panel with constraints (x is the same)
gc.gridy = 2;
add(optionsLabel, gc);
//add helpLabel to panel with constraints (x is the same)
gc.gridy = 3;
add(helpLabel, gc);
//add aboutLabel to panel with constraints (x is the same)
gc.gridy = 4;
add(aboutLabel, gc);
}
public static BufferedImage scaleImage(int w, int h, BufferedImage img) throws Exception {
BufferedImage bi;
//bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
bi = new BufferedImage(w, h, img.getType());
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(img, 0, 0, w, h, null);
g2d.dispose();
return bi;
}
/*
* Will return the preffered size of JPanel
*/
#Override
public Dimension getPreferredSize() {
return preferredDimensions;
}
/*
* Will draw the background to JPanel with anti-aliasing on and quality rendering
*/
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
//convert graphics object to graphics2d object
Graphics2D g2d = (Graphics2D) grphcs;
//set anti-aliasing on and rendering etc
//GamePanel.applyRenderHints(g2d);
//draw the image as the background
g2d.drawImage(background, 0, 0, null);
//g2d.dispose();//if I uncomment this no LAbels will be shown
}
}
class PopUpJLabel extends JLabel {
public final static Font defaultFont = new Font("Arial", Font.PLAIN, 50);
public final static Font hoverFont = new Font("Arial", Font.BOLD, 70);
PopUpJLabel(String text) {
super(text);
setHorizontalAlignment(JLabel.CENTER);
setForeground(Color.ORANGE);
setFont(defaultFont);
//allow component to be focusable
setFocusable(true);
//add focus adapter to change fints when focus is gained or lost (used for transversing labels with keys)
addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent fe) {
super.focusGained(fe);
if (isEnabled()) {
setFont(getHoverFont());
}
}
#Override
public void focusLost(FocusEvent fe) {
super.focusLost(fe);
setFont(getDefaultFont());
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
super.mouseEntered(me);
if (isEnabled()) {
setFont(getHoverFont());
}
//call for focus mouse is over this component
requestFocusInWindow();
}
});
}
Font getDefaultFont() {
return defaultFont;
}
Font getHoverFont() {
return hoverFont;
}
}
The thing is that the Graphics context you are using in paintComponent is created and provided by the caller (the framework), which is also responsible for disposing of it.
You only need to dispose of Graphics when you actually create it yourself (for example by calling Component.getGraphics()). In your case, you're not creating it, you're just casting it, so do not call dispose in this case.
Because .dispose() releases your resources. Yes, everything.

How to correctly put a jLabel in jPanel [duplicate]

After learning that dispose() should be called on Graphics/Graphics2D object after use, I went about changing my game to incorporate this.
When I added g2d.dispose() in overridden paintComponent(Graphics g) of JPanel, my components which I added (extensions of JLabel class) where not rendered I was able to still click on them etc but they would not be painted.
I tested with a normal JLabel and JButton with same effect (though JButton is rendered when mouse is over it).
So my question is why does this happen?
Here is an SSCCE to demonstrate:
after uncommenting call to dispose() in paintComponent of MainMenuPanel class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
try {
initComponents();
} catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
MainMenuPanel mmp = new MainMenuPanel();
frame.add(mmp);
frame.pack();
frame.setVisible(true);
}
}
class MainMenuPanel extends JPanel {
//create labels for Main Menu
private PopUpJLabel versusesModeLabel;
private PopUpJLabel singlePlayerModeLabel;
private PopUpJLabel optionsLabel;
private PopUpJLabel helpLabel;
private PopUpJLabel aboutLabel;
//create variable to hold background
private Image background;
private Dimension preferredDimensions;
public static String gameType;
public static final String SINGLE_PLAYER = "Single Player", VERSUS_MODE = "VS Mode";
/**
* Default constructor to initialize double buffered JPanel with
* GridBagLayout
*/
public MainMenuPanel() {
super(new GridBagLayout(), true);
try {
initComponents();
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Could not load main menu background!", "Main Menu Error: 0x004", JOptionPane.ERROR_MESSAGE);
System.exit(4);
}
}
/*
* Create JPanel and its components
*/
private void initComponents() throws Exception {
//set prefered size of JPanel
preferredDimensions = new Dimension(800, 600);
background = scaleImage(800, 600, ImageIO.read(new URL("http://photos.appleinsider.com/12.08.30-Java.jpg")));
//create label instances
singlePlayerModeLabel = new PopUpJLabel("Single Player Mode");
singlePlayerModeLabel.setEnabled(false);
versusesModeLabel = new PopUpJLabel("Versus Mode");
optionsLabel = new PopUpJLabel("Options");
helpLabel = new PopUpJLabel("Help");
aboutLabel = new PopUpJLabel("About");
//create new constraints for gridbag
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.HORIZONTAL;
gc.ipady = 50;//vertical spacing
//add newGameLabel to panel with constraints
gc.gridx = 0;
gc.gridy = 0;
add(singlePlayerModeLabel, gc);
gc.gridy = 1;
add(versusesModeLabel, gc);
//add optionsLabel to panel with constraints (x is the same)
gc.gridy = 2;
add(optionsLabel, gc);
//add helpLabel to panel with constraints (x is the same)
gc.gridy = 3;
add(helpLabel, gc);
//add aboutLabel to panel with constraints (x is the same)
gc.gridy = 4;
add(aboutLabel, gc);
}
public static BufferedImage scaleImage(int w, int h, BufferedImage img) throws Exception {
BufferedImage bi;
//bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
bi = new BufferedImage(w, h, img.getType());
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(img, 0, 0, w, h, null);
g2d.dispose();
return bi;
}
/*
* Will return the preffered size of JPanel
*/
#Override
public Dimension getPreferredSize() {
return preferredDimensions;
}
/*
* Will draw the background to JPanel with anti-aliasing on and quality rendering
*/
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
//convert graphics object to graphics2d object
Graphics2D g2d = (Graphics2D) grphcs;
//set anti-aliasing on and rendering etc
//GamePanel.applyRenderHints(g2d);
//draw the image as the background
g2d.drawImage(background, 0, 0, null);
//g2d.dispose();//if I uncomment this no LAbels will be shown
}
}
class PopUpJLabel extends JLabel {
public final static Font defaultFont = new Font("Arial", Font.PLAIN, 50);
public final static Font hoverFont = new Font("Arial", Font.BOLD, 70);
PopUpJLabel(String text) {
super(text);
setHorizontalAlignment(JLabel.CENTER);
setForeground(Color.ORANGE);
setFont(defaultFont);
//allow component to be focusable
setFocusable(true);
//add focus adapter to change fints when focus is gained or lost (used for transversing labels with keys)
addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent fe) {
super.focusGained(fe);
if (isEnabled()) {
setFont(getHoverFont());
}
}
#Override
public void focusLost(FocusEvent fe) {
super.focusLost(fe);
setFont(getDefaultFont());
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
super.mouseEntered(me);
if (isEnabled()) {
setFont(getHoverFont());
}
//call for focus mouse is over this component
requestFocusInWindow();
}
});
}
Font getDefaultFont() {
return defaultFont;
}
Font getHoverFont() {
return hoverFont;
}
}
The thing is that the Graphics context you are using in paintComponent is created and provided by the caller (the framework), which is also responsible for disposing of it.
You only need to dispose of Graphics when you actually create it yourself (for example by calling Component.getGraphics()). In your case, you're not creating it, you're just casting it, so do not call dispose in this case.
Because .dispose() releases your resources. Yes, everything.

Painting issue in custom layered container?

So I am working on a project here that requires a custom JLayeredPane - like class.
It has two members 'ground' and 'foreground' that are JPanel and an background (Image) member.
The way it was supposed to show was that the background Image should have been drawn and then all the components of the ground on top of it and then foreground's components at the apex. So foreground covers up ground which covers up background. Background should be shown only at places that do not have a Component in ground and foreground or where there is transparency in the JPanels.
It's paint function goes like this:
#Override
public void paint(Graphics g){
g.drawImage(background, 0, 0, null);
ground.paint(g.create());
foreground.paint(g.create());
g.dispose();
}
But nothing like that happens. Just the background image gets painted and nothing else shows.
I have used System.out.println() function to check that ground and foreground actually hold components and they do. But they just don't show.
Can anyone help me here?
The most significant issue is you're not calling super.paint, which is preventing what ever was previously painted to the Graphics context from been cleared or any child components from been painted.
For painting the background, you should be using paintComponent, which is used to paint the background of the component.
If you need to paint under the child components, but above the background, you should still use paintComponent, but paint the background first and then the next layer. The components will be painted after paintComponent.
Painting over components is actually more complex
Take a closer look at Custom Painting and Painting in Swing and AWT
Updated based on code snippets
In Screen which extends from Container, you are doing...
#Override
public void paint(Graphics g) {
super.paint(g);
GraphicsUtilities.drawPictureTiled(background, g);
paintComponents(g);
g.dispose();
}
Don't call paintComponents, super.paint has already done this.
Don't call dispose on a Graphics context you don't create
Based on the rest of the example code I have, you should be extending from JPanel and overriding paintComponent instead. This will allow you to put under the component layer
Because GroundPanel and ForeGroundPanel are both JPanels, there's no need to ever paint them yourself. In fact, you could simply use OverlayLayout or even a GridBagLayout and add them directly to the NestedScreen which is itself a container...
So, I stripped down you example code so I could get it working with the missing code as an example. I got a little more fancy and simply made a JPanel to act as the pause screen
This is all done by simply overlaying the components on top of each other using a GridBagLayout
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test1001 {
public static void main(String[] args) {
new Test1001();
}
public Test1001() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
NestedScreen screen = new NestedScreen();
screen.setBackgroundLayer(ImageIO.read(getClass().getResource("/Sky.png")));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(screen);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public interface GraphicsEngineComponents {
}
public class NestedScreen extends Screen implements GraphicsEngineComponents {
GroundPanel ground;
ForeGroundPanel foreground;
private PausePane pausePane;
public NestedScreen() {
ground = new GroundPanel();
foreground = new ForeGroundPanel();
pausePane = new PausePane();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
add(pausePane, gbc);
add(foreground, gbc);
add(ground, gbc);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
pausePane.setVisible(!pausePane.isVisible());
}
};
addMouseListener(handler);
foreground.addMouseListener(handler);
ground.addMouseListener(handler);
}
public GroundPanel getGroundLayer() {
return ground;
}
public ForeGroundPanel getForegroundLayer() {
return foreground;
}
public void setBackgroundLayer(BufferedImage background) {
super.setBackgroundLayer(background);
}
public class GroundPanel extends JPanel {
public GroundPanel() {
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, getHeight() - 200, getWidth(), 200);
}
}
public class PausePane extends JPanel {
private JLabel label;
public PausePane() {
setVisible(false);
setOpaque(false);
setBackground(new Color(0, 0, 0, 128));
setLayout(new GridBagLayout());
label = new JLabel("Paused");
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
Font font = label.getFont();
font = font.deriveFont(Font.BOLD, 48f);
label.setFont(font);
label.setForeground(Color.WHITE);
add(label);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public class ForeGroundPanel extends JPanel {
private BufferedImage pony;
public ForeGroundPanel() {
setOpaque(false);
try {
pony = ImageIO.read(getClass().getResource("/Pony.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (pony != null) {
int x = (getWidth() - pony.getWidth()) / 2;
int y = getHeight() - 200 - (pony.getHeight() / 2);
g.drawImage(pony, x, y, this);
}
}
}
}
public class Screen extends JPanel implements GraphicsEngineComponents {
private BufferedImage background;
public Screen() {
}
#Override
public String toString() {
return "Screen{" + "background=" + background + '}';
}
public BufferedImage getBackgroundPicture() {
return background;
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
protected void setBackgroundLayer(BufferedImage background) {
if (background != null && background.getHeight() != 0 && background.getWidth() != 0) {
this.background = background;
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
g.drawImage(background, 0, 0, this);
}
}
}
}
Take a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting works in Swing.
A basic idea would be to avoid using all these compound or nested components and instead, create an engine that can paint the layers directly onto a Graphics context, maybe even painting to a BufferedImage which you can the paint onto a single component...
There are a few ways you go about doing this. I'll just introduce one way.
Create a background panel where you paint the background image (in the example below, it is BackgroundPanel with the image only being the forresty background). Set that panel as the content pane to the frame.
Create another ground panel where you can also paint something (in the example below if it the GroundPanel with only the image of bugs bunny painted.
Create your foreground panel and add it to the ground panel. You can add your foreground components to it. (in the example below the foreground image is the grassy hill, and I also add a button to it
All the panels' opaque property should be set to false, as to allow the panel behind it to be shown under any transparency.
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class ThreeTier {
public static final int DIM_WIDTH = 600;
public static final int DIM_HEIGHT = 400;
private BufferedImage backgroundImage;
private BufferedImage groundImage;
private BufferedImage foregroundImage;
public ThreeTier() {
initImages();
JFrame frame = new JFrame();
frame.setContentPane(new BackgroundPanel());
frame.add(new GroundPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void initImages() {
try {
backgroundImage = ImageIO.read(getClass().getResource("/resources/background.png"));
foregroundImage = ImageIO.read(getClass().getResource("/resources/foreground.png"));
groundImage = ImageIO.read(getClass().getResource("/resources/bugsBunny.png"));
} catch (IOException ex) {
Logger.getLogger(ThreeTier.class.getName()).log(Level.SEVERE, null, ex);
}
}
class BackgroundPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backgroundImage, 0, 0, DIM_WIDTH, DIM_HEIGHT, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
}
}
class GroundPanel extends JPanel {
private static final String RIGHT_ACTION = "rightAction";
private int imageX = 50;
private int imageY = 140;
public GroundPanel() {
setOpaque(false);
add(new ForegroundPanel());
InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("RIGHT"), RIGHT_ACTION);
getActionMap().put(RIGHT_ACTION, new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (imageX >= DIM_WIDTH) {
imageX = 0 - groundImage.getWidth();
repaint();
} else {
imageX += 10;
repaint();
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(groundImage, imageX, imageY, groundImage.getWidth(), groundImage.getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
}
}
class ForegroundPanel extends JPanel {
public ForegroundPanel() {
setOpaque(false);
setLayout(new FlowLayout(FlowLayout.TRAILING, 10, 0));
JButton button = new JButton("I'm in the Foreground!");
add(button);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(foregroundImage, 0, 0, DIM_WIDTH, DIM_HEIGHT, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ThreeTier();
}
});
}
}
UPDATE
Of course you could always just use the JLayeredPane. That's what it's for. See this example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class LayeredPaneDemo {
public static final int DIM_WIDTH = 600;
public static final int DIM_HEIGHT = 400;
public LayeredPaneDemo() {
ContainerPanel container = new ContainerPanel();
JLabel title = new JLabel("Lame Google Map");
title.setFont(new Font("verdana", Font.BOLD, 36));
title.setHorizontalAlignment(JLabel.CENTER);
JPanel panel = new JPanel(new GridBagLayout());
panel.add(container);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(title, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new LayeredPaneDemo();
}
});
}
public class ContainerPanel extends JPanel {
public ContainerPanel() {
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(DIM_WIDTH, DIM_HEIGHT));
BackgroundPanel bg = new BackgroundPanel();
GroundPanel gg = new GroundPanel();
ForegroundPanel fg = new ForegroundPanel();
bg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
layeredPane.add(bg, new Integer(1));
gg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
layeredPane.add(gg, new Integer(2));
fg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
layeredPane.add(fg, new Integer(3));
setLayout(new GridBagLayout());
add(layeredPane);
setBorder(new LineBorder(Color.BLUE, 10));
}
}
public class ForegroundPanel extends JPanel {
public ForegroundPanel() {
JPanel buttonPanel = new JPanel(new GridLayout(3, 3));
buttonPanel.setOpaque(false);
buttonPanel.add(new JLabel());
buttonPanel.add(new JButton("UP"));
buttonPanel.add(new JLabel());
buttonPanel.add(new JButton("Left"));
buttonPanel.add(new JLabel());
buttonPanel.add(new JButton("Right"));
buttonPanel.add(new JLabel());
buttonPanel.add(new JButton("Down"));
buttonPanel.add(new JLabel());
FlowLayout flow = (FlowLayout) getLayout();
flow.setAlignment(FlowLayout.TRAILING);
flow.setHgap(0);
flow.setVgap(0);
add(buttonPanel);
setOpaque(false);
}
}
public class GroundPanel extends JPanel {
Image image = null;
public GroundPanel() {
try {
image = ImageIO.read(getClass().getResource("/resources/california.png"));
} catch (IOException ex) {
Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
}
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, DIM_WIDTH, DIM_HEIGHT, this);
}
}
public class BackgroundPanel extends JPanel {
public BackgroundPanel() {
setLayout(new GridBagLayout());
setBackground(Color.WHITE);
try {
Image img = ImageIO.read(getClass().getResource("/resources/google.jpg"));
add(new JLabel(new ImageIcon(img)));
} catch (IOException ex) {
Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}

Overflow JLabel into Another JLabel

Let's say I have a JLabel sized 20x20. Now let's say I add the string "The quick brown fox jumps over the lazy dog." This sentence is too long for the JLabel, so it gets replaces with .... Is there a way that I could get it to overflow to another JLabel, so that the first JLabel would have "The quick brown fox" and the second JLabel would have "jumps over the lazy dog."?
JLabel lbl = new JLabel("The quick brown fox jumps over the lazy dog.");
lbl.setMaximumSize(new Dimension(20, 20));
add(lbl)
Produces a label that says "...".
It would be easier to answer if you provided some more information.
I'm assuming that what you want is two labels that can be placed side by side, or in any other layout. In case the first label's text overflows, the second label will display the remainder.
Here's a solution:
import java.awt.*;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.Override;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
public class Test extends JFrame {
public Test() {
super("Test overflowing label");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocation(200, 200);
setSize(300, 200);
createUI();
}
private void createUI() {
JLabel label2 = new JLabel();
JLabel label1 = new OverflowingLabel("text to truncate since it's too long ...", label2);
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, label1, label2);
splitPane.setDividerSize(2);
addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
splitPane.setDividerLocation(.5d);
}
});
setContentPane(splitPane);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test test = new Test();
test.setVisible(true);
}
});
}
private class OverflowingLabel extends JLabel {
private JLabel[] dependantLabels;
public OverflowingLabel(String text, JLabel... dependantLabels) {
super(text);
this.dependantLabels = dependantLabels;
addComponentListener(new ComponentAdapter() {
#Override
public void componentShown(ComponentEvent e) {
overflowText();
}
#Override
public void componentResized(ComponentEvent e) {
overflowText();
}
});
}
private void overflowText() {
int index = getIndexToChopText();
String text = getText().substring(index);
for (JLabel dependantLabel : dependantLabels)
dependantLabel.setText(text);
}
private int getIndexToChopText() {
Dimension size = getSize();
FontMetrics metrics = getFontMetrics(getFont());
String text = getText();
int index = 0;
int width = 0;
while ((index < text.length()) && (width < size.width)) {
int charWidth = metrics.charWidth(text.charAt(index));
if ((width + charWidth) > size.width)
break;
index ++;
width += charWidth;
}
return index;
}
#Override
public Dimension getMinimumSize() {
Dimension size = super.getMinimumSize();
return new Dimension(0, size.height);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g.create();
Rectangle clip = g2d.getClipBounds();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
g2d.setColor(getBackground());
g2d.fillRect(clip.x, clip.y, clip.width, clip.height);
g2d.setColor(getForeground());
g2d.setFont(getFont());
FontMetrics metrics = g2d.getFontMetrics();
int baseLine = metrics.getAscent() + metrics.getLeading();
int index = getIndexToChopText();
g2d.drawString(getText().substring(0, index), 0, (getHeight() + baseLine) / 2 - 1);
g2d.dispose();
}
}
}
Here are some screen shots to demonstrate the behavior:

Deleting images from JFrame

I created one JFrame. and set layout shown in below code
this.setLayout(new GridLayout());
JPanel panel=new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(new PicturePanel1());
JTabbedPane jtp=new JTabbedPane();
jtp.addTab("show Images", panel);
jtp.addTab("Compare Image", new JButton());
this.add(jtp);
I created another class that draws Images from particular location.
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
int k = 20,y=10;
for (int j = 0; j <= listOfFiles.length - 1; j++) {
g2.drawImage(b[j], k, y, 100, 100, null);
// add(new javax.swing.JCheckBox());
k = k + 120;
if(k>=960)
{
k=20;
y=y+120;
}
}
Its working fine. I want to delete Images when user clicks on particular Image.
This is my output window. I want to delete Image from list.
Here is an example I made (bored and tired of studying :)). It is by no means the best just a quick thing to show you an example, click the image you want to delete and then press the delete button or DEL to remove and image from the panel:
When app starts up (orange just shows focused label for hovering):
Image to delete is selected by clicking on the Label (Border becomes green highlighted and will remain this way until another label is clicked):
After delete button or key is pressed:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class JavaApplication5 {
public static void main(String[] args) {
createAndShowJFrame();
}
public static void createAndShowJFrame() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = createJFrame();
frame.setVisible(true);
}
});
}
private static JFrame createJFrame() {
JFrame frame = new JFrame();
//frame.setResizable(false);//make it un-resizeable
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Test");
ArrayList<BufferedImage> images = null;
try {
images = getImagesArrayList();
} catch (Exception ex) {
ex.printStackTrace();
}
final ImageViewPanel imageViewPanel = new ImageViewPanel(images);
JScrollPane jsp = new JScrollPane(imageViewPanel);
jsp.setPreferredSize(new Dimension(400, 400));
frame.add(jsp);
JPanel controlPanel = new JPanel();
JButton addLabelButton = new JButton("Delete Selected Image");
addLabelButton.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
imageViewPanel.removeFocusedImageLabel();
}
});
controlPanel.add(addLabelButton);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.pack();
return frame;
}
private static ArrayList<BufferedImage> getImagesArrayList() throws Exception {
ArrayList<BufferedImage> images = new ArrayList<>();
images.add(resize(ImageIO.read(new URL("http://icons.iconarchive.com/icons/deleket/sleek-xp-software/256/Yahoo-Messenger-icon.png")), 100, 100));
images.add(resize(ImageIO.read(new URL("https://upload.wikimedia.org/wikipedia/commons/6/64/Gnu_meditate_levitate.png")), 100, 100));
return images;
}
public static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) bi.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
return bi;
}
}
class ImageViewPanel extends JPanel {
JLabel NO_IMAGES = new JLabel("No Images");
ArrayList<BufferedImage> images;
ArrayList<MyLabel> imageLabels;
public ImageViewPanel(ArrayList<BufferedImage> images) {
this.images = images;
imageLabels = new ArrayList<>();
for (BufferedImage bi : images) {
imageLabels.add(new MyLabel(new ImageIcon(bi), this));
}
layoutLabels();
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0, true), "Delete pressed");
getActionMap().put("Delete pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
removeFocusedImageLabel();
}
});
}
void removeFocusedImageLabel() {
if (focusedLabel == null) {
return;
}
imageLabels.remove(focusedLabel);
remove(focusedLabel);
layoutLabels();
}
private void layoutLabels() {
if (imageLabels.isEmpty()) {
add(NO_IMAGES);
} else {
remove(NO_IMAGES);
for (JLabel il : imageLabels) {
add(il);
}
}
revalidate();
repaint();
}
private MyLabel focusedLabel;
void setFocusedLabel(MyLabel labelToFocus) {
if (focusedLabel != null) {
focusedLabel.setBorder(null);
focusedLabel.setClicked(false);
}
focusedLabel = labelToFocus;
focusedLabel.setBorder(new LineBorder(Color.GREEN));
}
}
class MyLabel extends JLabel {
private final ImageViewPanel imageViewPanel;
private boolean clicked = false;
public MyLabel(Icon image, ImageViewPanel imageViewPanel) {
super(image);
this.imageViewPanel = imageViewPanel;
initLabel();
}
public MyLabel(String text, ImageViewPanel imageViewPanel) {
super(text);
this.imageViewPanel = imageViewPanel;
initLabel();
}
private void initLabel() {
setFocusable(true);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
clicked = true;
imageViewPanel.setFocusedLabel(MyLabel.this);
}
#Override
public void mouseEntered(MouseEvent me) {
super.mouseEntered(me);
if (clicked) {
return;
}
setBorder(new LineBorder(Color.ORANGE));
//call for focus mouse is over this component
requestFocusInWindow();
}
});
addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
super.focusLost(e);
if (clicked) {
return;
}
setBorder(null);
}
});
}
public void setClicked(boolean clicked) {
this.clicked = clicked;
}
public boolean isClicked() {
return clicked;
}
}
simply find the location (x, and y) and the size(width, and height) of image, then with the Graphics object (g2) fill a rectangle over the image drawn, like this
g2.setColor(this.getBackground());//set the color you want to clear the bound this point to JFrame/JPanel
g2.fillRect(x, y, width, height);
where x and y where is the location that images is located, and width and height are size of the picture

Categories

Resources