I am learning Swing and wrote an app that lets user select an image file and displays it on a JPanel. It works, but I want to handle situations when
user doesn't select any file
user selects a non image file
In these cases I want to clear the JPanel and show an error message on a text area.
I tried to do this as below.But I am not sure if this is the way to do this properly.I would like your suggestions.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
class Display extends JFrame {
private MyImagePanel canvas;
private JButton okbutton;
private JTextArea result;
private JFileChooser filechooser;
private static Insets insets = new Insets(0, 0, 0, 0);
public Display(String name) {
super(name);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
addWidgets();
showGUI();
}
private void showGUI() {
this.pack();
this.setVisible(true);
}
private void addWidgets() {
canvas = new MyImagePanel();
okbutton = new JButton("OK");
filechooser = new JFileChooser("Select imagefile");
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Images", "jpg", "JPG", "GIF", "gif", "JPEG", "png", "PNG");
filechooser.setFileFilter(filter);
filechooser.setControlButtonsAreShown(false);
result = new JTextArea(10, 10);
addComponent(filechooser, 0, 0, 2, 4, GridBagConstraints.CENTER, GridBagConstraints.NONE);
addComponent(canvas, 2, 0, 2, 2, GridBagConstraints.CENTER, GridBagConstraints.NONE);
addComponent(result, 2, 2, 2, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE);
addComponent(okbutton, 3, 3, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE);
}
public void addOKButtonListener(ActionListener okl) {
okbutton.addActionListener(okl);
}
public void displayResult(String msg) {
result.setText(msg);
}
public void clearResultField() {
result.setText("");
}
public void displayImage(String imagefilename) {
canvas.setImage(imagefilename);
}
public String getSelectedFile() {
java.io.File selectedFile = filechooser.getSelectedFile();
String filePathName = "";
if (selectedFile == null) {
result.setText("select a file");
} else {
filePathName = selectedFile.getPath();
}
return filePathName;
}
public void addComponent(Component component, int gridx, int gridy,
int gridwidth, int gridheight, int anchor, int fill) {
GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
gridwidth, gridheight, 1.0, 1.0, anchor, fill, insets, 0, 0);
this.add(component, gbc);
}
}//end class Display
class MyImagePanel extends JPanel {
private BufferedImage bi;
public MyImagePanel() {
super();
bi = null;
}
public void setImage(String imagefilename) {
try {
bi = ImageIO.read(new File(imagefilename));
this.setPreferredSize(new Dimension(bi.getWidth(), bi.getHeight()));
} catch (Exception e) {
bi = null;
}
this.revalidate();
this.repaint();
}
#Override
public void paintComponent(Graphics g) {
// clear the background
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
if (bi != null) {
// draw the image
g.drawImage(bi, 0, 0, null);
}
}
}
class GUIController {
private Display display;
public GUIController(Display d) {
display = d;
display.addOKButtonListener(new OKButtonListener());
}
class OKButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
display.clearResultField();//make result field blank
String fileselection = display.getSelectedFile();
if (fileselection.length() > 0) {
display.displayImage(fileselection);
} else {
display.displayResult("actionPerformed:no file selected");
display.displayImage("");
}
}
}
}
public class ImageDisplay {
public static void main(String[] args) {
Display d = new Display("image demo");
GUIController ctrl = new GUIController(d);
}
}
The several drawImage() methods in java.awt.Graphics do "nothing if img is null." As a result, setting the image to null is sufficient. You're clearing the background explicitly, but super.paintComponent(g) is an alternative that clears the panel to the background color.
Addendum: You may also want to study the examples found in the articles How to Use File Choosers and Working with Images.
Addendum: I used a different layout and added the image to a JScrollPane. I also had setImage() return a result to let the Display know what happened.
Addendum: This newer, simpler revision extends JFileChooser to handle approve and cancel directly.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
/** #see https://stackoverflow.com/questions/4053090 */
public class ImageDisplay extends JFrame {
private static final String title = "Select a file";
private MyImagePanel imagePanel = new MyImagePanel();
private JLabel result = new JLabel(title, JLabel.CENTER);
private MyChooser fileChooser = new MyChooser();
public ImageDisplay(String name) {
super(name);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addWidgets();
this.pack();
this.setVisible(true);
}
private void addWidgets() {
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Images", "jpg", "JPG", "GIF", "gif", "JPEG", "png", "PNG");
fileChooser.setFileFilter(filter);
this.add(fileChooser, BorderLayout.WEST);
this.add(new JScrollPane(imagePanel), BorderLayout.CENTER);
this.add(result, BorderLayout.SOUTH);
}
class MyChooser extends JFileChooser {
#Override
public void approveSelection() {
File f = fileChooser.getSelectedFile();
if (imagePanel.setImage(f)) {
result.setText(f.getName());
} else {
result.setText(title);
}
}
#Override
public void cancelSelection() {
imagePanel.setImage(null);
result.setText(title);
}
}
class MyImagePanel extends JPanel {
private BufferedImage bi;
public MyImagePanel() {
this.setPreferredSize(new Dimension(500, 700));
}
/** Return true if read() succeeded. */
public boolean setImage(File f) {
try {
bi = ImageIO.read(f);
} catch (Exception e) {
bi = null;
}
if (bi != null) {
setPreferredSize(new Dimension(bi.getWidth(), bi.getHeight()));
}
this.revalidate();
this.repaint();
return bi != null;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bi, 0, 0, null);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageDisplay("Image Demo").setVisible(true);
}
});
}
}
Related
I am trying to implement a free hand drawing Java applet which allows user to draw something in canvas (canvas is not the priority, it could be anything else as long I can save the image after (need to save it, because I have to display it later in a different place after pressing a button, any other solutions are welcome)). I found a code, which allows me to draw, but now I am having a trouble with drawing inside the canvas... And I have already spent few days with no results on that. Here is the code I have by now and a description below it:
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.*;
import java.applet.*;
public class paintMozApplet extends Applet implements ActionListener
{
int xPressed,yPressed;
int xReleased,yReleased;
int xDragged,yDragged;
private GridLayout gL;
private JPanel buttons;
private JPanel panel;
private Button clear, createMoz;
private Label result_here;
private javax.swing.JPanel drawing;
private JPanel moz;
private Canvas canvas;
private draw draw;
public paintMozApplet()
{
draw = new draw();
gL = new GridLayout(1, 0);
buttons = new JPanel();
drawing = new JPanel();
moz = new JPanel();
canvas = new Canvas();
clear = new Button("clear");
createMoz = new Button("Create Moz");
buttons.add(clear);
buttons.add(createMoz);
result_here = new Label("Result here!");
moz.add(result_here);
drawing.add(canvas);
clear.addActionListener(this);
//canvas.add(draw);
//canvas.addMouseMotionListener(this);
canvas.setPreferredSize(new Dimension(200, 200));
canvas.setBackground(Color.green);
add(drawing);
add(buttons);
add(moz);
add(draw);
setPreferredSize(new Dimension(1000, 1000));
setSize(1000, 1000);
setLayout(gL);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==clear)
{
//setOpaque(false);
repaint();
}
}
}
class draw extends JFrame implements MouseListener, MouseMotionListener, ActionListener {
int xPressed,yPressed;
int xReleased,yReleased;
int xDragged,yDragged;
private JButton clear;
public draw()
{
setPreferredSize(new Dimension(1200, 500));
setBounds(0, 0, 480, 500);
clear=new JButton("CLEAR");
add(clear);
clear.setBounds(540, 5, 100, 25);
clear.addActionListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
protected void paintComponent(Graphics g)
{
g.drawLine(xPressed,yPressed,xDragged,yDragged);
xPressed=xDragged;
yPressed=yDragged;
}
#Override
public void mouseDragged(MouseEvent arg0) {
Graphics g = getGraphics();
g.drawLine(xPressed, yPressed, arg0.getX(), arg0.getY());
xDragged = arg0.getX();
yDragged = arg0.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
xPressed = arg0.getX();
yPressed = arg0.getY();
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
So my idea is to create two classes where one is used to draw and other to create place where to draw and everything else. I have tried lots of things and now I am here and cant figure out, how to cal the draw class on my canvas so it will draw only there. Before I had everything in one class and called mouse events on my canvas. Result was that it drawed only when I clicked on canvas, but the actual drawing went also out of canvas if I did not let go of my mouse and dragged it out of canvas. Also it did not draw in canvas, but on the background of applet, at least it looked like that.
I really hope I explained my self understanding and I am sure, that this can be solved easily since there are lots of solutions online but I can't seem to find one that would work as I intend.
I suggest starting with this approach based around a BufferedImage as the painting surface..
import java.awt.*;
import java.awt.RenderingHints.Key;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
public class BasicPaint {
/** Reference to the original image. */
private BufferedImage originalImage;
/** Image used to make changes. */
private BufferedImage canvasImage;
/** The main GUI that might be added to a frame or applet. */
private JPanel gui;
/** The color to use when calling clear, text or other
* drawing functionality. */
private Color color = Color.WHITE;
/** General user messages. */
private JLabel output = new JLabel("You DooDoodle!");
private BufferedImage colorSample = new BufferedImage(
16,16,BufferedImage.TYPE_INT_RGB);
private JLabel imageLabel;
private int activeTool;
public static final int SELECTION_TOOL = 0;
public static final int DRAW_TOOL = 1;
public static final int TEXT_TOOL = 2;
private Point selectionStart;
private Rectangle selection;
private boolean dirty = false;
private Stroke stroke = new BasicStroke(
3,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,1.7f);
private RenderingHints renderingHints;
public JComponent getGui() {
if (gui==null) {
Map<Key, Object> hintsMap = new HashMap<RenderingHints.Key,Object>();
hintsMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
hintsMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
renderingHints = new RenderingHints(hintsMap);
setImage(new BufferedImage(320,240,BufferedImage.TYPE_INT_RGB));
gui = new JPanel(new BorderLayout(4,4));
gui.setBorder(new EmptyBorder(5,3,5,3));
JPanel imageView = new JPanel(new GridBagLayout());
imageView.setPreferredSize(new Dimension(480,320));
imageLabel = new JLabel(new ImageIcon(canvasImage));
JScrollPane imageScroll = new JScrollPane(imageView);
imageView.add(imageLabel);
imageLabel.addMouseMotionListener(new ImageMouseMotionListener());
imageLabel.addMouseListener(new ImageMouseListener());
gui.add(imageScroll,BorderLayout.CENTER);
JToolBar tb = new JToolBar();
tb.setFloatable(false);
JButton colorButton = new JButton("Color");
colorButton.setMnemonic('o');
colorButton.setToolTipText("Choose a Color");
ActionListener colorListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Color c = JColorChooser.showDialog(
gui, "Choose a color", color);
if (c!=null) {
setColor(c);
}
}
};
colorButton.addActionListener(colorListener);
colorButton.setIcon(new ImageIcon(colorSample));
tb.add(colorButton);
setColor(color);
final SpinnerNumberModel strokeModel =
new SpinnerNumberModel(3,1,16,1);
JSpinner strokeSize = new JSpinner(strokeModel);
ChangeListener strokeListener = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent arg0) {
Object o = strokeModel.getValue();
Integer i = (Integer)o;
stroke = new BasicStroke(
i.intValue(),
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
1.7f);
}
};
strokeSize.addChangeListener(strokeListener);
strokeSize.setMaximumSize(strokeSize.getPreferredSize());
JLabel strokeLabel = new JLabel("Stroke");
strokeLabel.setLabelFor(strokeSize);
strokeLabel.setDisplayedMnemonic('t');
tb.add(strokeLabel);
tb.add(strokeSize);
tb.addSeparator();
ActionListener clearListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int result = JOptionPane.OK_OPTION;
if (dirty) {
result = JOptionPane.showConfirmDialog(
gui, "Erase the current painting?");
}
if (result==JOptionPane.OK_OPTION) {
clear(canvasImage);
}
}
};
JButton clearButton = new JButton("Clear");
tb.add(clearButton);
clearButton.addActionListener(clearListener);
gui.add(tb, BorderLayout.PAGE_START);
JToolBar tools = new JToolBar(JToolBar.VERTICAL);
tools.setFloatable(false);
JButton crop = new JButton("Crop");
final JRadioButton select = new JRadioButton("Select", true);
final JRadioButton draw = new JRadioButton("Draw");
final JRadioButton text = new JRadioButton("Text");
tools.add(crop);
tools.add(select);
tools.add(draw);
tools.add(text);
ButtonGroup bg = new ButtonGroup();
bg.add(select);
bg.add(text);
bg.add(draw);
ActionListener toolGroupListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getSource()==select) {
activeTool = SELECTION_TOOL;
} else if (ae.getSource()==draw) {
activeTool = DRAW_TOOL;
} else if (ae.getSource()==text) {
activeTool = TEXT_TOOL;
}
}
};
select.addActionListener(toolGroupListener);
draw.addActionListener(toolGroupListener);
text.addActionListener(toolGroupListener);
gui.add(tools, BorderLayout.LINE_END);
gui.add(output,BorderLayout.PAGE_END);
clear(colorSample);
clear(canvasImage);
}
return gui;
}
/** Clears the entire image area by painting it with the current color. */
public void clear(BufferedImage bi) {
Graphics2D g = bi.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(color);
g.fillRect(0, 0, bi.getWidth(), bi.getHeight());
g.dispose();
imageLabel.repaint();
}
public void setImage(BufferedImage image) {
this.originalImage = image;
int w = image.getWidth();
int h = image.getHeight();
canvasImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.drawImage(image, 0, 0, gui);
g.dispose();
selection = new Rectangle(0,0,w,h);
if (this.imageLabel!=null) {
imageLabel.setIcon(new ImageIcon(canvasImage));
this.imageLabel.repaint();
}
if (gui!=null) {
gui.invalidate();
}
}
/** Set the current painting color and refresh any elements needed. */
public void setColor(Color color) {
this.color = color;
clear(colorSample);
}
private JMenu getFileMenu(boolean webstart){
JMenu file = new JMenu("File");
file.setMnemonic('f');
JMenuItem newImageItem = new JMenuItem("New");
newImageItem.setMnemonic('n');
ActionListener newImage = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
BufferedImage bi = new BufferedImage(
360, 300, BufferedImage.TYPE_INT_ARGB);
clear(bi);
setImage(bi);
}
};
newImageItem.addActionListener(newImage);
file.add(newImageItem);
if (webstart) {
//TODO Add open/save functionality using JNLP API
} else {
//TODO Add save functionality using J2SE API
file.addSeparator();
ActionListener openListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (!dirty) {
JFileChooser ch = getFileChooser();
int result = ch.showOpenDialog(gui);
if (result==JFileChooser.APPROVE_OPTION ) {
try {
BufferedImage bi = ImageIO.read(
ch.getSelectedFile());
setImage(bi);
} catch (IOException e) {
showError(e);
e.printStackTrace();
}
}
} else {
// TODO
JOptionPane.showMessageDialog(
gui, "TODO - prompt save image..");
}
}
};
JMenuItem openItem = new JMenuItem("Open");
openItem.setMnemonic('o');
openItem.addActionListener(openListener);
file.add(openItem);
ActionListener saveListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser ch = getFileChooser();
int result = ch.showSaveDialog(gui);
if (result==JFileChooser.APPROVE_OPTION ) {
try {
File f = ch.getSelectedFile();
ImageIO.write(BasicPaint.this.canvasImage, "png", f);
BasicPaint.this.originalImage = BasicPaint.this.canvasImage;
dirty = false;
} catch (IOException ioe) {
showError(ioe);
ioe.printStackTrace();
}
}
}
};
JMenuItem saveItem = new JMenuItem("Save");
saveItem.addActionListener(saveListener);
saveItem.setMnemonic('s');
file.add(saveItem);
}
if (canExit()) {
ActionListener exit = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
System.exit(0);
}
};
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.setMnemonic('x');
file.addSeparator();
exitItem.addActionListener(exit);
file.add(exitItem);
}
return file;
}
private void showError(Throwable t) {
JOptionPane.showMessageDialog(
gui,
t.getMessage(),
t.toString(),
JOptionPane.ERROR_MESSAGE);
}
JFileChooser chooser = null;
public JFileChooser getFileChooser() {
if (chooser==null) {
chooser = new JFileChooser();
FileFilter ff = new FileNameExtensionFilter("Image files", ImageIO.getReaderFileSuffixes());
chooser.setFileFilter(ff);
}
return chooser;
}
public boolean canExit() {
boolean canExit = false;
SecurityManager sm = System.getSecurityManager();
if (sm==null) {
canExit = true;
} else {
try {
sm.checkExit(0);
canExit = true;
} catch(Exception stayFalse) {
}
}
return canExit;
}
public JMenuBar getMenuBar(boolean webstart){
JMenuBar mb = new JMenuBar();
mb.add(this.getFileMenu(webstart));
return mb;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
// use default
}
BasicPaint bp = new BasicPaint();
JFrame f = new JFrame("DooDoodle!");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(bp.getGui());
f.setJMenuBar(bp.getMenuBar(false));
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
public void text(Point point) {
String text = JOptionPane.showInputDialog(gui, "Text to add", "Text");
if (text!=null) {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
g.setStroke(stroke);
int n = 0;
g.drawString(text,point.x,point.y);
g.dispose();
this.imageLabel.repaint();
}
}
public void draw(Point point) {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
g.setStroke(stroke);
int n = 0;
g.drawLine(point.x, point.y, point.x+n, point.y+n);
g.dispose();
this.imageLabel.repaint();
}
class ImageMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
if (activeTool==BasicPaint.SELECTION_TOOL) {
selectionStart = arg0.getPoint();
} else if (activeTool==BasicPaint.DRAW_TOOL) {
// TODO
draw(arg0.getPoint());
} else if (activeTool==BasicPaint.TEXT_TOOL) {
// TODO
text(arg0.getPoint());
} else {
JOptionPane.showMessageDialog(
gui,
"Application error. :(",
"Error!",
JOptionPane.ERROR_MESSAGE);
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
if (activeTool==BasicPaint.SELECTION_TOOL) {
selection = new Rectangle(
selectionStart.x,
selectionStart.y,
arg0.getPoint().x,
arg0.getPoint().y);
}
}
}
class ImageMouseMotionListener implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent arg0) {
reportPositionAndColor(arg0);
if (activeTool==BasicPaint.SELECTION_TOOL) {
selection = new Rectangle(
selectionStart.x,
selectionStart.y,
arg0.getPoint().x-selectionStart.x,
arg0.getPoint().y-selectionStart.y);
} else if (activeTool==BasicPaint.DRAW_TOOL) {
draw(arg0.getPoint());
}
}
#Override
public void mouseMoved(MouseEvent arg0) {
reportPositionAndColor(arg0);
}
}
private void reportPositionAndColor(MouseEvent me) {
String text = "";
if (activeTool==BasicPaint.SELECTION_TOOL) {
text += "Selection (X,Y:WxH): " +
(int)selection.getX() +
"," +
(int)selection.getY() +
":" +
(int)selection.getWidth() +
"x" +
(int)selection.getHeight();
} else {
text += "X,Y: " + (me.getPoint().x+1) + "," + (me.getPoint().y+1);
}
output.setText(text);
}
}
This source is very patchy.
It has many parts with // TODO
A dirty attribute is declared but never used in any meaningful way. ..
It is just something I hacked together today and thought should be shown before it hit the posting limit.
Oh, and don't go looking for any 'OO design' since I did not put any in. If there is any, it is only by accident. This code is intended to demonstrate what is possible and how to start doing it.
Aim: to place JButton on a top of an image that is loaded from a different class.
Problem: only JButton or image can be displayed
//main class
JPanel mPanel.add(new JButton("ddd") );
mPanel.add(drawbg);
class DrawBg extends JPanel {
public Dimension getPreferredSize() {
return new Dimension(1280, 720);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// background
Image img = new ImageIcon(getClass().getResource("/images/test_bg.jpg")).getImage();
int imgX = img.getWidth(null);
int imgY = img.getHeight(null);
g.drawImage(img, (getWidth() - imgX), (getHeight() - imgY), imgX, imgY, null);
}
Edit Ah yes, as ControlAltDel points out, you're not adding your JButton to your drawing JPanel instance. Just do that, and your problem is solved.
I don't see the bug in your code, so it might lie in code not shown. I do see a problem in that you're reading the image in, inside of paintComponent, something that should never be done as it will slow down painting and thus slow down the perceived responsiveness of your program. Also, why re-read in the image with each paint. Instead read it in once.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ButtonOnImg extends JPanel {
public static final String IMG_PATH = "https://duke.kenai.com/gun/Gun.jpg";
private BufferedImage img;
public ButtonOnImg() throws IOException {
URL url = new URL(IMG_PATH);
img = ImageIO.read(url);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
}
#Override
public Dimension getPreferredSize() {
if (img == null) {
return super.getPreferredSize();
} else {
int w = img.getWidth();
int h = img.getHeight();
return new Dimension(w, h);
}
}
private static void createAndShowGui() {
try {
ButtonOnImg mainPanel = new ButtonOnImg();
mainPanel.add(new JButton("Button!"));
JFrame frame = new JFrame("ButtonOnImg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which displays as:
Trying to draw an image and I have no idea why it's not appearing on the screen. Image is loaded fine.
System.out.printf("%nPlayer_1.img_player1 is: "+Player_1.img_player1); says that the image is loaded correctly (correct image w/h etc).
Have tried all manner of image observers, drawing the image from different classes (namely Player_1.drawSquare and MyPanel.painComponent)
There are regular repaint() requests coming in from the Control class, but I do not believe this is preventing the drawing.
No error's are thrown.
player_1.gif is located within the game_2 package, I have tried running the code with it in the src and root folder.
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class Main{
public static void main(String[] args) {
GUI.main(args);
}
}
class GUI {
static JFrame f = new JFrame("Swing Paint Demo");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.printf("%nCreated GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.setSize(640,640);
f.setVisible(true);
}
}
class MyPanel extends JPanel {
public MyPanel() {
//setBorder(BorderFactory.createLineBorder(Color.black));
}
public Dimension getPreferredSize() {
return new Dimension(640,640);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.printf("%nPaincomponent on GUI");
Player_1.paintSquare(g);
System.out.printf("%nPlayer_1.img_player1 is: "+Player_1.img_player1);
}
}
class Player_1{
public static Image img_player1;
public int int_x = 0;
public int int_y = 1;
public int int_w = 1;
public int int_h = 1;
public static void paintSquare(Graphics g){
if (img_player1 == null)
img_player1 = IOControl.getImage("player_1.gif");
g.drawImage(img_player1, 32, 32, 32, 32, GUI.f);
}
}
class IOControl {
public static void main(String[] args) {
}
static BufferedImage getImage(String path)
{
BufferedImage tempImage = null;
try
{
URL imageURL = Main.class.getResource(path);
tempImage = toBufferedImage(Toolkit.getDefaultToolkit().getImage(imageURL));
}
catch(Exception e)
{
System.out.printf("%nAn error occured -" + e.getMessage());
}
System.out.printf("%n"+path);
System.out.printf("%nIOControl.path");
System.out.printf("%n"+tempImage);
System.out.printf("%nIOControl.tempImage");
return tempImage;
}
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
// Create a buffered image with transparency
BufferedImage bimage = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
}
Don't call the main method. It is meant for the JVM to call as the starting point of your program. Also, you should only have one main method, in whichever class is the launching class.
Don't create the image in the paintXxx method. You should create in the constructor.
All the other faulty points I mentioned in my comments in the original post.
It looks like your main problem is in the getImage method. I simplified it for you and it works (given I fixed the other points I mentioned above).
public static BufferedImage getImage(String path) {
BufferedImage img = null;
try {
img = ImageIO.read(GUI.class.getResource(path));
} catch (IOException ex) {
ex.printStackTrace();
}
return img;
}
Here's the full running code. Note: you had the image location correct, with it in the same package as the Main class.
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI().createAndShowGUI();
}
});
}
}
class GUI {
JFrame f = new JFrame("Swing Paint Demo");
public void createAndShowGUI() {
System.out.printf("%nCreated GUI on EDT? "
+ SwingUtilities.isEventDispatchThread());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.setSize(640, 640);
f.setVisible(true);
}
}
class MyPanel extends JPanel {
Player_1 player1;
public MyPanel() {
player1 = new Player_1(MyPanel.this);
}
public Dimension getPreferredSize() {
return new Dimension(640, 640);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.printf("%nPaincomponent on GUI");
player1.paintSquare(g);
}
}
class Player_1 {
public Image img_player1;
public int int_x = 0;
public int int_y = 1;
public int int_w = 1;
public int int_h = 1;
JPanel panel;
public Player_1(JPanel panel) {
this.panel = panel;
img_player1 = IOControl.getImage("player_1.png");
}
public void paintSquare(Graphics g) {
g.drawImage(img_player1, 32, 32, 32, 32, panel);
}
}
class IOControl {
public static BufferedImage getImage(String path) {
BufferedImage img = null;
try {
img = ImageIO.read(GUI.class.getResource(path));
} catch (IOException ex) {
ex.printStackTrace();
}
return img;
}
}
I asked here how to add background image to JComboBox properly, but didn't see answers, so i thought that i should separate these two questions...
So. How to add background image to JComboBox text field and to JComboBox popup panel properly?
UPD:
Some code for you)
Current code:
// ... Renderer
public class CBoxListCellRenderer implements ListCellRenderer {
ImagePanel panel;
JLabel label = new JLabel();
public CBoxListCellRenderer(Image img) {panel = new ImagePanel(img);}
public void setImage(Image img) {panel.setImage(img);}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
label.setText(value.toString());
panel.add(label);
return panel;
}
}
// ... ImagePanel
public class ImagePanel extends JPanel {
private BufferedImage img;
public ImagePanel(String img) {
setImage(img);
}
public void setImage(String img)
{
try {
this.img = ImageIO.read(this.getClass().getResource(img));
} catch (IOException ex) {
ex.printStackTrace();
}
Dimension size = new Dimension(this.img.getWidth(), this.img.getHeight());
setSize(size);
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, getWidth(), getHeight(), 0, 0, img.getWidth(), img.getHeight(), this);
}
}
// ... Colorizing arrow
class ColorArrowUI extends BasicComboBoxUI {
public static ComboBoxUI createUI(JComponent c) {
return new ColorArrowUI();
}
#Override protected JButton createArrowButton() {
return new BasicArrowButton(
BasicArrowButton.SOUTH,
Color.cyan, Color.magenta,
Color.yellow, Color.blue);
}
}
// ... Creating object
combo_language = new JComboBox(new DefaultComboBoxModel(new String[] { "English", "日本語", "Русский" }));
combo_language.setBorder(null);
combo_language.setRenderer(new CBoxListCellRenderer(new ImageIcon(getClass().getResource("/Images/form.png")).getImage()));
combo_language.setUI(new ColorArrowUI());
// ... Putting JComboBox to JFrame
Try using a ListCellRenderer like described here:
http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer
Here's an example of a custom ListCellRenderer. I return a JPanel that has painted an image to it then added a JLabel that holds the value of the list object. There's room for improvement on it, but it's just an example of what you can do.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TestCBoxListCellRenderer {
public TestCBoxListCellRenderer() {
String[] list = {"Hello World 1", "Hello World 2", "Hello World 3"};
JComboBox box = new JComboBox(list);
box.setRenderer(new CBoxListCellRenderer());
JOptionPane.showMessageDialog(null, box, "Check out this Renderer", JOptionPane.PLAIN_MESSAGE);
}
public static void main(String[] args) {
new TestCBoxListCellRenderer();
}
class BackGroundPanel extends JPanel {
BufferedImage img = null;
public BackGroundPanel() {
try {
img = ImageIO.read(TestCBoxListCellRenderer.class.getResource("/res/leafcell.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(),
0, 0, img.getWidth(), img.getHeight(), this);
}
}
private class CBoxListCellRenderer implements ListCellRenderer {
final BackGroundPanel panel = new BackGroundPanel();
JLabel label = new JLabel();
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
label.setText(value.toString());
panel.add(label);
return panel;
}
}
}
You may want to add a thin line border or do something when its selected, its up to you. Use the variables from the getListCellRendererComponent method to render to your liking accordingly
I want to be able to update the LookAndFeel attributes of my Swing GUI on the fly. In this case, I have a simple Swing/Awt game running what starts out as the Nimbus LookAndFeel. At various points after start up I want to change (let us say) just one detail: the background color of my application.
I can change the background color by doing this:
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);
SwingUtilities.updateComponentTreeUI(SomeGame.this);
break;
}
}
This "works" in that the background color of the app changes correctly and the program doesn't crash. But on the command line I get error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.plaf.synth.SynthLookAndFeel.paintRegion(SynthLookAndFeel.java:371)
at javax.swing.plaf.synth.SynthLookAndFeel.update(SynthLookAndFeel.java:335)
Obviously, something is null, but I can not figure out what it is or how to fix it. There must be something I don't understand. I have looked at other StackOverflow questions about setting background colors in Nimbus and overriding the LookAndFeel information after startup.
When I call getLookAndFeelDefaults() do I need to specify the rest of the defaults as well?
Have there been changes in how this works between Java 1.6 and 1.7?
all code for Java6, have to change Nimbus imports for Java7
Nimbus has a few suprises, one of them is that is possible (without dirty hacks, I'm leaving comments for those hacks) to change Background for JPanel only one time
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.AlphaComposite;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.EmptyBorder;
public class ButtonTest {
private JFrame frame;
private JPanel panel;
private JButton opaqueButton1;
private JButton opaqueButton2;
private SoftJButton softButton1;
private SoftJButton softButton2;
private Timer alphaChanger;
public void createAndShowGUI() {
opaqueButton1 = new JButton("Opaque Button");
opaqueButton2 = new JButton("Opaque Button");
softButton1 = new SoftJButton("Transparent Button");
softButton2 = new SoftJButton("Transparent Button");
opaqueButton1.setBackground(Color.GREEN);
softButton1.setBackground(Color.GREEN);
panel = new JPanel();
panel.setLayout(new java.awt.GridLayout(2, 2, 10, 10));
panel.add(opaqueButton1);
panel.add(softButton1);
panel.add(opaqueButton2);
panel.add(softButton2);
panel.setBorder(new EmptyBorder(10, 10, 10, 10));
frame = new JFrame();
frame.add(panel);
frame.setLocation(150, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
alphaChanger = new Timer(50, new ActionListener() {
private float incrementer = -.03f;
#Override
public void actionPerformed(ActionEvent e) {
float newAlpha = softButton1.getAlpha() + incrementer;
if (newAlpha < 0) {
newAlpha = 0;
incrementer = -incrementer;
} else if (newAlpha > 1f) {
newAlpha = 1f;
incrementer = -incrementer;
}
softButton1.setAlpha(newAlpha);
softButton2.setAlpha(newAlpha);
}
});
alphaChanger.start();
Timer uiChanger = new Timer(3500, new ActionListener() {
private final LookAndFeelInfo[] laf = UIManager.getInstalledLookAndFeels();
private int index = 1;
#Override
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(laf[index].getClassName());
if (laf[index].getClassName().equals("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel")) {
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.orange);
SwingUtilities.updateComponentTreeUI(frame);
} else {
panel.setBackground(Color.yellow);
SwingUtilities.updateComponentTreeUI(frame);
}
opaqueButton1.setText(laf[index].getClassName());
softButton1.setText(laf[index].getClassName());
frame.pack();
} catch (Exception exc) {
exc.printStackTrace();
}
index = (index + 1) % laf.length;
}
});
uiChanger.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ButtonTest().createAndShowGUI();
}
});
}
private static class SoftJButton extends JButton {
private static final JButton lafDeterminer = new JButton();
private static final long serialVersionUID = 1L;
private boolean rectangularLAF;
private float alpha = 1f;
SoftJButton() {
this(null, null);
}
SoftJButton(String text) {
this(text, null);
}
SoftJButton(String text, Icon icon) {
super(text, icon);
setOpaque(false);
setFocusPainted(false);
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
repaint();
}
#Override
public void paintComponent(java.awt.Graphics g) {
java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
if (rectangularLAF && isBackgroundSet()) {
Color c = getBackground();
g2.setColor(c);
g.fillRect(0, 0, getWidth(), getHeight());
}
super.paintComponent(g2);
}
#Override
public void updateUI() {
super.updateUI();
lafDeterminer.updateUI();
rectangularLAF = lafDeterminer.isOpaque();
}
}
}
but for JComponent it is possible to change its Color, Font, etc by calling UIManager.getLookAndFeel().uninitialize();, but this does not work for containers
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
public class NimbusTestButtonsBackground extends JFrame {
private static final long serialVersionUID = 1L;
private javax.swing.JButton button;
public NimbusTestButtonsBackground() {
button = new javax.swing.JButton();
button.setText("Text");
add(button);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.pack();
Timer t = new Timer(1000, new ActionListener() {
private Random r = new Random();
#Override
public void actionPerformed(ActionEvent e) {
Color c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
try {
LookAndFeel lnf = UIManager.getLookAndFeel().getClass().newInstance();
UIDefaults uiDefaults = lnf.getDefaults();
uiDefaults.put("nimbusBase", c);
UIManager.getLookAndFeel().uninitialize();
UIManager.setLookAndFeel(lnf);
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
UIDefaults defaults = UIManager.getDefaults();
defaults.put("Button.background", c);
SwingUtilities.updateComponentTreeUI(button);
}
});
t.start();
}
public static void main(String args[]) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
return;
}
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new NimbusTestButtonsBackground().setVisible(true);
}
});
}
}
then I see (this way as most comfortable, easiest, etc..) overriding paintComponent for JPanel as best the best way
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
public class ChangePanelBackgroundNimbus {
private JFrame frame = new JFrame();
public ChangePanelBackgroundNimbus() {
GradientPane pane = new GradientPane();
pane.setLayout(new GridLayout(6, 4, 10, 10));
for (int i = 1; i <= 24; i++) {
pane.add(createButton(i));
}
pane.setOpaque(false);
frame.add(pane);
RepaintManager.setCurrentManager(new RepaintManager() {
#Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
Container con = c.getParent();
while (con instanceof JComponent) {
if (!con.isVisible()) {
return;
}
if (con instanceof GradientPane) {
c = (JComponent) con;
x = 0;
y = 0;
w = con.getWidth();
h = con.getHeight();
}
con = con.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
//frame.setSize(400, 300);
frame.pack();
frame.setVisible(true);
}
private JButton createButton(final int text) {
JButton button = new JButton(Integer.toString(text));
return button;
}
class GradientPane extends JPanel {
private static final long serialVersionUID = 1L;
private final int h = 150;
private BufferedImage img = null;
private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
public GradientPane() {
paintBackGround(new Color(150, 250, 150));
Timer t = new Timer(500, new ActionListener() {
private Random r = new Random();
#Override
public void actionPerformed(ActionEvent e) {
paintBackGround(new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)));
}
});
t.start();
}
public void paintBackGround(Color g) {
Graphics2D g2 = shadow.createGraphics();
g2.setPaint(g);
g2.fillRect(0, 0, 1, h);
g2.setComposite(AlphaComposite.DstIn);
g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(0.4f, 0.8f, 0.8f, 0.5f)));
g2.fillRect(0, 0, 1, h);
g2.dispose();
}
#Override
public void paintComponent(Graphics g) {
if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2 = img.createGraphics();
super.paintComponent(g2);
Rectangle bounds = this.getVisibleRect();
g2.scale(bounds.getWidth(), -1);
g2.drawImage(shadow, bounds.x, -bounds.y - h, null);
g2.scale(1, -1);
g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h, null);
g2.dispose();
g.drawImage(img, 0, 0, null);
repaint();
}
}
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ChangePanelBackgroundNimbus ml = new ChangePanelBackgroundNimbus();
}
});
}
}