I'm trying to display images (as image icons for JLabels).
Everything works fine when I am NOT trying to display images, i.e.:
for (int i=0;i<value;i++)
{
for (int j=0;j<value;j++)
{
c.gridx=i;
c.gridy=j;
JLabel element = new JLabel("!");
pane.add(element,c);
}
}
However if I do this:
for (int i=0;i<value;i++)
{
for (int j=0;j<value;j++)
{
c.gridx=i;
c.gridy=j;
JLabel element = new JLabel();
element.setIcon(wall);
pane.add(element,c);
}
}
It will produce a good amount of error messages.
Console output: http://pastebin.com/teuuWjRX
The code: (pastebin version w/ syntax highlighting: http://pastebin.com/2utFJ0UM)
package tut;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class Main extends JFrame{
//private static int value;
public Main()
{
int value=151;//151
ImageIcon wall = new ImageIcon();
try
{
BufferedImage tempImage = ImageIO.read(this.getClass().getResource(("/resources/images/test.png")));
wall = new ImageIcon(tempImage.getScaledInstance(4, 4, Image.SCALE_DEFAULT));
}
catch (IOException e){}
Container pane = getContentPane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
for (int i=0;i<value;i++)
{
for (int j=0;j<value;j++)
{
c.gridx=i;
c.gridy=j;
JLabel element = new JLabel();
element.setIcon(wall);
pane.add(element,c);
}
}
//Main Frame
setTitle("Example1");
setSize(value*8,value*8);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main (String[] args)
{
Main test1= new Main();
}
}
My questions are:
Why does it raise the exception in comparison? (Everything seems to
be fine from my point of view)
Can stackOverFlow problem be caused because of each time object declaration? (As I don't see any other problem in the loop).
P.s.: Is getScaledInstance okay to use or there's a better method?
Any help would be greatly appreciated.
EDIT: Overall, I did not find any real problem with the code, the only thing I can say that the problem is not with scaling. Parsing little-sized images (like 8x8 or 4x4) w/o scaling also produces an error, however everything is fine for parsing images of size 16x16 or higher or scaling to 16x16. It could be kind of a problem with placing/adding little-sized images (i.e. elements) to the layout.
You are using wall as an Icon. And wall is created in a try block where you don't even log exceptions raised.
The problem could be here : maybe you have an exception (IOException) raised at the icon creation and you can't see it.
you can try the JLabel constructor public JLabel(Icon image) instead of empty constructor
Apolo
Related
The cods first goes to the array and gets the file name. Then it converts it to a Buffered Image and changes the size of the image. It then sends the array of pictures to the main method where it is converted to a JLabel before adding it to the frame. I understand my programming convesion skills are kinda lacking but it would be nice if you could explain why when i run this i the image isnt resizing
This is the main class
import java.awt.Color;
import java.awt.Image;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Frame extends JFrame
{
public Frame(JLabel welcomeImage)
{
setTitle("Tower Defence Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setSize(750 , 500);
setLocationRelativeTo(null);
setVisible(true);
getContentPane().setBackground(Color.BLACK);
add(welcomeImage);
}
public static JLabel WelcomeImage(Image[] pics)
{
pics[0].getScaledInstance(750, 1000, Image.SCALE_DEFAULT);
ImageIcon WelcomeImage = new ImageIcon(pics[0]);
JLabel JWelcomeImage = new JLabel();
JWelcomeImage.setIcon(WelcomeImage);
return JWelcomeImage;
}
public static void main(String[] args) throws IOException
{
Image[] pics = Images.Image();
JLabel welcomeImage = WelcomeImage(pics);
JFrame frame = new Frame(welcomeImage);
}
}
This is the class that would hold all the images
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
public class Images
{
public static Image[] Image() throws IOException
{
//Getting all the Picture in a png format
String Picture[] = {"apple.png"};
//Getting the Picture as an image
Image[] Pics = new Image[Picture.length];
BufferedImage iPic;
BufferedImage oPic;
//Using a for loop to put the Picture in an array
for(int i = 0; i < Picture.length; i++)
{
iPic = ImageIO.read(new File(Picture[i]));
oPic = new BufferedImage(750 , 500 , iPic.getType());
Pics[i] = (Image) oPic;
}
return Pics;
}
}
it would be nice if you could explain why when i run this i the image isnt resizing
Well, the first thing is to learn how to display the image at its actual size BEFORE attempting to scale the image. You can't display a scaled image if you don't know how to display the default image.
The problem with your code is that you can't even display the actual image, so trying to display a scaled image has no chance of working.
With that in mind you have several structural issues:
Don't call you class "Frame". There is an AWT component with that name and it is confusing. A class name should be more descriptive.
Don't extend JFrame. You should only extend a class when you add functionality to the class. Adding components to a frame is not adding functionality,
Components need to be added to the frame BEFORE the frame is made visible.
Don't use setSize(). How can the frame size and the image size be the same? The frame contains a titlebar and borders so it must be larger. Instead you should be using pack() before the setVisible(...) statement.
Variable names should NOT start with an upper case character. Be consistent.
Method names should be descriptive. What does the "Image" method do. Nobody could guess by looking at the method name. Maybe something like "readImages" or "loadImages"?
In the Image class:
iPic = ImageIO.read(new File(Picture[i]));
oPic = new BufferedImage(750 , 500 , iPic.getType());
Pics[i] = (Image) oPic;
What is the point of the "oPic" variable. The purpose of this method is to read the image, not scale the image. The "oPic" variable just contains an empty BufferedImage.
So get rid of that variable and just add the "iPic" image to the array.
In the Frame class:
pics[0].getScaledInstance(750, 1000, Image.SCALE_DEFAULT);
ImageIcon WelcomeImage = new ImageIcon(pics[0]);
The above code does nothing because the getScaledInstance(...) returns a new instance of the Image. So you need to assign it to a variable before you can use it:
// pics[0].getScaledInstance(750, 1000, Image.SCALE_DEFAULT);
// ImageIcon WelcomeImage = new ImageIcon(pics[0]);
Image scaled = pics[0].getScaledInstance(750, 1000, Image.SCALE_DEFAULT);
ImageIcon WelcomeImage = new ImageIcon(scaled);
I suggest you learn Swing basics by reading the Swing tutorial. Each section contains examples and the code will be better structured. The examples will show you how to create a class without extending JFrame.
I am trying to programmatically create a background grid for a project I am working on. The problem is that the first item I add to the jpanel is always painted at center of the jpanel. I am expressly trying to put it at the top right. I have even tried just placing a dummy jlabel down first and going from there but then the second and third element just overlap each other. This bug has me thoroughly dumbfounded. Any help would be great.
private void evalWindow(){
window.removeAll();
window.setBorder(BorderFactory.createLineBorder(Color.black));
JLabel p = new JLabel(new ImageIcon(tiles[0][0].getImage()));
p.setLocation(0,0);
System.out.println("1: " + p.getLocation());
p.setSize(64,64);
window.add(p);
System.out.println("2: " + p.getLocation());
for(int i = 0; i < x; i++){
for (int j = 0; j < y; j++){
JLabel piclabel = new JLabel(new ImageIcon(tiles[i][j].getImage()));
piclabel.setSize(64,64);
piclabel.setLocation(64*j, 64*i);
System.out.println("1: " + piclabel.getLocation());
window.add(piclabel);
}
}
}
sample image:
As mentioned elsewhere, a GridLayout would be the easiest way to layout the grid positions. It can be as simple as:
public void initUI(Image img) {
ui = new JPanel(new GridLayout(0,8));
ImageIcon icon = new ImageIcon(img);
for (int ii=0; ii<32; ii++) {
ui.add(new JLabel(icon));
}
}
This is the effect:
Here is the MCVE that produces the above GUI. In future, please post code in the form of an MVCE.
import java.awt.*;
import java.awt.image.*;
import java.io.IOException;
import javax.swing.*;
import javax.imageio.*;
import java.net.URL;
public class ImageGrid {
private JComponent ui = null;
String imageURL = "https://i.stack.imgur.com/DlSgb.png";
ImageGrid() {
try {
BufferedImage img = ImageIO.read(new URL(imageURL));
BufferedImage subImg = img.getSubimage(2, 2, 64, 64);
initUI(subImg);
} catch (IOException ex) {
ex.printStackTrace();
}
}
final public void initUI(Image img) {
ui = new JPanel(new GridLayout(0,8));
ImageIcon icon = new ImageIcon(img);
for (int ii=0; ii<32; ii++) {
ui.add(new JLabel(icon));
}
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ImageGrid o = new ImageGrid();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
You do not tell us the type of the variable "window", but I'll assume it's a JFrame or something else that will take a layout manager. Components on Swing windows are not normally placed with absolute positions like 0,0; they are added to containers which are set to use an extension of LayoutManager, and the LayoutManager class manages where the components added to it will go.
FlowLayout adds things in order; GridLayout puts things in equal-size cells on a grid; BorderLayout allows placement in one of 5 areas, etc. The LayoutManager scheme saves you from having to mess with positioning while the user changes the size of the outer window, allows some elements to grow and shrink with available overall size, etc.
If you must place things with absolute positions, there is a NullLayoutManager, but in over 20 years of Java programming and a number of different Swing applications, I've never seen one.
Read about LayoutManagers. I'm sure whatever one is default for your window variable is placing your component in the center and ignoring the absolute placement.
I have a program that consists of four JButtons in a JFrame. I want to add images to the JButtons. The problem is that I can't seem to add them, despite trying multiple methods. When compiled, the output is input == null. The images are stored in the same folder as my .java files, so I can't figure out why they aren't showing up.
Main class:
import java.awt.GridLayout;
import java.awt.Image;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AutoProgram extends JFrame {
private static String[] files = {"workA","programmingA","leisureA","writingA"};
private static JButton[] bIcons = new JButton[4];
private static Image[] bImg = new Image[4];
public AutoProgram() {
super("Automation Project V.1");
JPanel autoIcons = new JPanel();
autoIcons.setLayout(new GridLayout(2,2));
// Initialize the four buttons (w/ images)
for(int i = 0; i < files.length; i++) {
bIcons[i] = new JButton();
try {
bImg[i] = ImageIO.read(getClass().getResource(files[i].toLowerCase() + ".png"));
bIcons[i].setIcon(new ImageIcon(bImg[i]));
} catch (Exception ex) {
System.out.println(ex);
}
autoIcons.add(bIcons[i]);
}
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));;
mainPanel.add(autoIcons);
add(mainPanel);
pack();
}}
Window class:
public class Window {
public static void main(String[] args) {
AutoProgram frame = new AutoProgram();
frame.setSize(315,315);
frame.setLocationRelativeTo(null);
frame.setFocusable(true);
frame.setResizable(true);
frame.setVisible(true);
}
}
Any help would be greatly appreciated. Thanks!
Before going into the answer to your question, please read the following recommendations:
private static JButton[] bIcons = new JButton[4]; Creating static fields could break your program, so be careful when to use them. Not really needed in this case, please read What does the 'static' keyword do in a class?
JFrame is a rigid container which cannot be placed inside others, and you're not changing it's functionallity anywhere in your program, so there's no need to call extends JFrame, it's better to create a JFrame instance then. See: Extends JFrame vs. creating it inside the program for more information about this.
You're correctly calling pack() but later in the code you're calling frame.setSize(315,315); which "destroys" the changes made by pack(), use one or the other, not both, I recommend you to leave pack() call.
You're not placing your program in the Event Dispatch Thread (EDT), you can fix it by changing your main(...) method as follows:
public static void main (String args[]) {
//Java 7 and below
SwingUtilities.invokeLater(new Runnable() {
//Your code here
});
//Java 8 and higher
SwingUtilities.invokeLater(() -> {
//Your code here
});
}
Now, let's go to the solution:
Your code works fine, I think that your errors might come from the following posibilities:
Calling files[i].toLowerCase() (.toLowerCase() method might be breaking your program, Java is case sensitive).
Your images are not PNG but JPG or JPEG (look at the extension carefully)
Your images are damaged
I'm having trouble changing an icon deep in my GUI using Swing components. I'm creating a chess game for fun with Java and want the right side of the GUI to respond when a piece is taken by showing the taken piece in a grid. My problem is that whenever I call the setIcon() function within JLabel with a new image and add it to the appropriate JPanel, it does not update. It works when I setIcon() the first time, but after it is added to the GUI, I can't change it the way I have been trying to. Here is screenshots so you know what I'm getting at:
Initial State
After
As you can tell, a pawn has been taken but the right panel does not reflect this despite my efforts.
I did some research and the following question was similar: Relevant Question
Camickr responded in that saying it could be two instances of the JLabel I am trying to update which I believe is what is going in my case. I initially set all of my icons on the right panel to null when setting the GUI up for initial state. Here is the code that does this:
for (int i = 0; i < 16; i++)
{
piece1Labels[i] = new JLabel();
piece2Labels[i] = new JLabel();
piece1Panels[i] = new ChessSpace(playerDeadPieceTile);
piece2Panels[i] = new ChessSpace(playerDeadPieceTile);
piece1Labels[i].setPreferredSize(new Dimension(67,66));
piece2Labels[i].setPreferredSize(new Dimension(67,66));
piece1Labels[i].setIcon(null);
piece2Labels[i].setIcon(null);
piece1Panels[i].add(piece1Labels[i]);
piece2Panels[i].add(piece2Labels[i]);
player1PiecePanel.add(piece1Panels[i]);
player2PiecePanel.add(piece2Panels[i]);
}
and here is me trying to change one of those panels after the initialization has been called on the first panel in the piece1Panels array of ChessSpace which extend JPanel:
//Try to change right panel icon after GUI setup
piece1Labels[0] = new JLabel();
piece1Panels[0] = new ChessSpace(playerDeadPieceTile);
piece1Labels[0].setPreferredSize(new Dimension(67,66));
piece1Labels[0].setIcon(new ImageIcon("C:/Users/Shasta/workspacejava/chess/images/terranpawn.jpg"));
piece1Panels[0].add(piece1Labels[0]);
piece1Labels and piece1Panels are variables of a class extending JFrame. I believe that the problem is that I'm just updating the class variable and not updating the instance that was added to the GUI.
EDIT:
As Alican Ozgoren & Hovercraft Full Of Eels pointed out I shouldn't have declared new instances of the JLabel, they were redundant.
The following line of code seems to do what I want:
//Try to change right panel icon after GUI setup
piece1Labels[0].setIcon(new ImageIcon("C:/Users/Shasta/workspacejava/chess/images/terranpawn.jpg"));
As we noted, simply set the Icon of the JLabel. But one more thing -- don't keep reading in the Icons as you're doing here:
piece1Labels[0].setIcon(new ImageIcon(
"C:/Users/Shasta/workspacejava/chess/images/terranpawn.jpg"));
Instead read the Icons in once at the beginning of your program, and store them in variables so that you get:
piece1Labels[0].setIcon(terranpawnIcon);
I would also read them in as resources not Files so that you can later store your images in your jar file and use them.
Just Create a thread which will update the JLable Icone please see the code below
package self.wing.practice.image;
import javax.swing.*;
/**
*
* #author ASHISH KUMAR MISHRA
*
*/
public class ImageDemo {
public ImageDemo() {
JFrame jfrm = new JFrame("Image Demo");
jfrm.setSize(200, 150);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel();
jfrm.add(label);
new ImageUpdator(label).start();
jfrm.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// TODO Auto-generated method stub
new ImageDemo();
}
});
}
}
i have created a thread to whom i am passing a Jlabel in Constructur. see below the what my thread is doing
package self.wing.practice.image;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
/**
*
* #author ASHISH KUMAR MISHRA
*
*/
public class ImageUpdator extends Thread {
String imagePath = "C:\\Users\\Public\\Pictures\\Sample Pictures";
File imageDir = new File(imagePath);
JLabel label = null;
ImageUpdator(JLabel label) {
this.label = label;
}
public void run() {
ImageIcon imageIcon = null;
if (imageDir.isDirectory()) {
File[] files = imageDir.listFiles();
for (int i = 0;; i++) {
i = i % files.length;
File currentFile = files[i];
if (currentFile.getName().endsWith(".jpg"))
;
{
imageIcon = new ImageIcon(currentFile.getAbsolutePath());
label.setName(currentFile.getName().substring(0,
currentFile.getName().indexOf('.')));
label.setIcon(imageIcon);
label.setHorizontalAlignment(JLabel.CENTER);
try {
Thread.sleep(700);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
Heading
I'm doing a project where i need some custom swing components. So far I have made a new button with a series of images (the Java Metal look doesn't fit with my UI at all). Ive implemented MouseListener on this new component and this is where my problem arises. My widget changes image on hover, click etc except my MouseListener picks up mouse entry into a the entire GridLayout container instead of into the image. So I have an image of about 200*100 and the surrounding container is about 400*200 and the mouseEntered method is fired when it enters that GridLayout section (even blank space parts of it) instead of over the image. How can I make it so that it is only fired when I hover over the image? Ive tried setting size and bounds and other attributes to no avail.
EDIT: Here's a demonstration of my issue. As you can see (sort of, colors are very similar) the bottom right button is highlighted just by entering its section of the GridlLayout. I only want it highlighted when I'm over the image actual, not the GridLayout section.
I Won't add the MouseListener methods because they just involve switching the displayed image.
public customWidget()
{
this.setLayout(new FlowLayout());
try {
imageDef=ImageIO.read(new File("/home/x101/Desktop/buttonDef.png"));
imageClick=ImageIO.read(new File("/home/x101/Desktop/buttonClick.png"));
imageHover=ImageIO.read(new File("/home/x101/Desktop/buttonHover.png"));
current=imageDef;
} catch (IOException e)
{
e.printStackTrace();
}
this.addMouseListener(this);
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
g.drawImage(current, 0, 0, current.getWidth(), current.getHeight(), null);
}
EDIT: added code section
As an alternative, consider the The Button API, which includes the method setRolloverIcon() "to make the button display the specified icon when the cursor passes over it."
Addendum: For example,
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ButtonIconTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
String base = "http://download.oracle.com/"
+ "javase/tutorial/uiswing/examples/components/"
+ "RadioButtonDemoProject/src/components/images/";
ImageIcon dog = null;
ImageIcon pig = null;
try {
dog = new ImageIcon(new URL(base + "Dog.gif"));
pig = new ImageIcon(new URL(base + "Pig.gif"));
} catch (MalformedURLException ex) {
ex.printStackTrace(System.err);
return;
}
JFrame frame = new JFrame("Rollover Test");
JPanel panel = new JPanel();
panel.add(new JLabel(dog));
panel.add(new JLabel(pig));
JButton button = new JButton(dog);
button.setRolloverIcon(pig);
panel.add(button);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I assume your image contains ONLY 4 'customWidget' objects (in a 2x2 grid).
Your code is working as I would expect. Your MouseListener methods are responding to MouseEvents for 'customWidget' (not the image drawn in 'customWidget'), which is sized to take up 1/4 of the image, so they will respond when it enters the enlarged area. The error is actually in your Test program, because you are allowing the custom button widget to be larger than the image.
If you want a Test program that provides an image similar to yours, you should create a larger grid (say 4x4), and then only place your buttons in every other grid node. Place an empty component into the gaps.
Although I won't answer to your particular question, I hope this helps:
If the components just look wrong maybe you should reuse Swing components and just write a custom Look&Feel or theme.
It would certainly help ensuring the look of the application is consistent and at least you are using the right tool for the task you want to accomplish.
As a sidenote, be aware that Java comes with multiple Look&feels, including Look&Feels made to mimic the native OS theme.
See: http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html