This is my first post in stackoverflow :D
Sorry for my english (I am italian)
So I have a method called setFrame
public static void setFrame()
{
JFrame GameMain = new JFrame();
GameMain.setSize(width, high);
GameMain.setLocationRelativeTo(null);
GameMain.setTitle("Tic Tac Toe!");
GameMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Grid grid = new Grid(600, 600);
GameMain.add(grid);
GameMain.pack();
GameMain.setVisible(true);
}
And this is the class Grid
public class Grid
{
private static int high;
private static int width;
public Grid(int width, int high)
{
width = width;
high = high;
BufferedImage img = null;
try {
img = ImageIO.read(new File("/grids/griglia1.png"));
} catch (IOException e) {
}
}
}
Ok so the problem is that when in the method setFrame I write "GameMain.add(grid);"
The console gives me an error like
"The method add(Component) in the type Container is not applicable for the arguments (Grid)"
Thanks for helping
From what I can tell, you would like to add an image to the JFrame. However, there are a few things wrong with your implementation. First of all, you cannot add images directly to a component. You need to encapsulate them in a JLabel. Additionally, the reason why you cannot add the grid class to your JFrame is because it isn't a swing component.
The easiest way to accomplish what you are trying to do would be to make a JPanel and then add it to the frame, and then make a JLabel that encapsulates your image and add that to the JPanel.
public static void setFrame()
{
JFrame GameMain = new JFrame();
GameMain.setSize(width, high);
GameMain.setLocationRelativeTo(null);
GameMain.setTitle("Tic Tac Toe!");
GameMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel GamePanel = new JPanel();
GamePanel.setSize(width, high);
GameMain.add(GamePanel);
background = new JLabel(new ImageIcon(ImageIO.read(new File("/grids/griglia1.png"))));
GamePanel.add(background);
GameMain.pack();
GameMain.setVisible(true);
}
This way you can bypass the Grid class altogether. Hope this helps.
Related
I'm writing a little photo application (asked some questions before) and I have one problem which I cannot resolve. The idea is that there are two sections: the upper one is for an overview (using thumbnails) and the lower one shows the selected image in it's full size. I cannot use ImageIO (required by my lecturer).
I'm using a JList for the overview but most images are not visible. I chose a folder with about 20 images and only 2 show up. And one of them isn't even centered.
For some reason, if I delete those lines:
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
One image shows up that wasn't visible before, but now the other two disappear.
This is my code:
public class PVE extends JFrame {
private JFileChooser fileChoose;
//MenuBar
private JMenuBar menubar;
private JMenu file;
private JMenuItem openFolder;
private JMenuItem exit;
//Thumbnails
private JList thumbnaillist;
private DefaultListModel<ImageIcon> listmodel;
private JScrollPane tscroll;
private ImageIcon thumbs;
private int thumbW = 100;
private int thumbH = 100;
//for full size view
private JPanel imgview;
public PVE() {
setLayout(new BorderLayout());
//MenuBar
menubar = new JMenuBar();
file = new JMenu("File");
openFolder = new JMenuItem("Open folder...");
exit = new JMenuItem("Quit");
file.add(openFolder);
file.addSeparator();
file.add(exit);
menubar.add(file);
setJMenuBar(menubar);
fileChoose = new JFileChooser();
openFolder.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
fileChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChoose.showOpenDialog(null);
File chosenDir = fileChoose.getSelectedFile();
loadToThumbView(chosenDir);
}
});
//Thumbnail view
listmodel = new DefaultListModel();
thumbnaillist = new JList(listmodel);
thumbnaillist.setLayoutOrientation(JList.HORIZONTAL_WRAP);
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
thumbnaillist.setVisibleRowCount(1);
tscroll = new JScrollPane(thumbnaillist, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tscroll.setPreferredSize(new Dimension(0, 100));
add(tscroll, "North");
//for full size view
imgview = new JPanel();
imgview.setBackground(Color.decode("#f7f7f7"));
add(imgview, "Center");
setTitle("Photo Viewer");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
}
setSize(700, 700);
setLocation(200, 200);
setVisible(true);
}
public void loadToThumbView(File folder) {
listmodel.removeAllElements();
File[] imgpaths = folder.listFiles();
for (int j = 0; j < imgpaths.length; j++) {
listmodel.addElement(resizeToThumbnail(new ImageIcon(imgpaths[j].toString())));
}
}
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bf.createGraphics();
g.drawImage(img, 0, 0, thumbW, thumbH, null);
ImageIcon kB = new ImageIcon(bf);
return kB;
}
public static void main(String argv[]) {
PVE pv = new PVE();
}
}
Your problem is because of the way you're scaling your images.
I'm not exactly sure why but I guess it has something to do with the BufferedImage#createGraphics() call and that I was able to reproduce the problem with .jpg images while .png files were correctly painted.
However if you scale your images instead of converting them to a BufferedImage and getting a new ImageIcon from it, you get the correct output:
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
Image scaled = img.getScaledInstance(thumbW, thumbH, Image.SCALE_SMOOTH);
return new ImageIcon(scaled);
}
This is the folder I used to test:
And the outputs with your code and mine:
Important notes
And as as a recommendation don't make a window that big if all you're using is that little bar above. If you're adding something else below, then it's ok but for now it's not that "user friendly" (IMHO). Instead of JFrame#setSize() you could try using JFrame#pack() method so your frame resizes to it's preferred size.
Some other things I noted in your program:
You're not placing it inside the Event Dispatch Thread (EDT) which is dangerous since your application won't be Thread safe that way. You can change that if you change your main method as follows:
public static void main(String argS[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PVE pv = new PVE();
}
});
}
You're setting the JScrollPane preferred size, instead you should override its getPreferredSize() method, see Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing? (YES)
You're extending JFrame, you should instead create an instance of it unless you're overriding one of its methods (and you're not, so don't do it) or you have any good reason to do it. If you need to extend a Container you should extend JPanel instead, as JFrame is a rigid container which cannot be placed inside another one. See this question and this one.
I think I'm not missing anything, and hope this helps
Your “scaled” images are actually images which are the same size as the original image, but are blank except for a scaled version drawn in the upper left corner. That upper left corner is clipped out of view in each rendered cell (at least for the somewhat large images I tested with).
The scaled image needs to be created with the thumbnail size, not the size of the original image. Meaning, change this:
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
to this:
BufferedImage bf = new BufferedImage(thumbW, thumbH, BufferedImage.TYPE_INT_ARGB);
I'm looking to display an image on a JPanel, but when I run the code, the panel is blank. The method I'm attempting is a slightly modified version of this tutorial.
I've confirmed that all methods in the code are actually called using println. My frame and panel are visible, and I'm fairly certain I've added both the icon to the label, and the label to the panel. What am I missing?
The relevant parts of my code:
public class SYSTEM
public static void start() {
GameFrame GF = new GameFrame();
GamePanel GP = new GamePanel();
GF.add(GP);
GP.loadSprite("Player", new Dimension(0,0));
}
}
public class GameFrame extends JFrame {
public GameFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(SYSTEM.windowSize);
setVisible(true);
}
}
public class GamePanel extends JPanel {
ArrayList<Sprite> sprites = new ArrayList<Sprite>();
GamePanel() {
setVisible(true);
setSize(SYSTEM.windowSize);
setLayout(null);
}
public void loadSprite(String spriteName, Dimension pos) {
sprites.add(new Player());
add(sprites.get(0).getIcon());
}
public class Sprite {
protected JLabel icon;
protected BufferedImage image;
protected String filePath;
protected Dimension pos;
public JLabel getIcon() {
return icon;
}
}
public class Player extends Sprite {
public Player() {
filePath = "FILEPATH_OMITTED";
pos = new Dimension(0,0);
try {
image = ImageIO.read(new File(filePath));
} catch (IOException e) {
System.out.println(e);
}
icon = new JLabel(new ImageIcon(image));
}
}
Don't use components for games, you've thrown out the layout manager which is responsible for determining the size and location of the components, but you've failed to compensate for it. I'd recommend that you use a custom painting approach instead, see Painting in AWT and Swing and Performing Custom Painting for starters.
Just so I'm clear, you problem is directly related to setLayout(null); which is bad regardless of what you're doing
I am working with GUIs in Java using JFrame and JPanel, as well as ActionListener to edit an image when I click a button. Currently, I am having a lot of trouble getting my JPanel class called ButtonPanel to interact with my BufferedImage img. I am trying to display the height of the image but nothing is working and I have tried various solutions. My code for the ButtonPanel class is:
class ButtonPanel extends JPanel
{
//JButton makeBlue;
BufferedImage img;
ButtonPanel(BufferedImage x)
{
final JButton makeBlue = new JButton ("Make Blue");
img = x;
//int width, height;
setBackground(Color.RED);
int height = 0;
add(makeBlue);
ActionListener action =
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource()== makeBlue)
{
//img = x;
height = img.getHeight();
// System.out.println(rgbvalue);
//System.out.println(width + " " + height);
setBackground(Color.GREEN);
repaint();
}
}
};
makeBlue.addActionListener(action);
}
}
Whenever I try to use a method from the BufferedImage API in order to edit the image, such as in the above code, I get this error:
ImageEditorDeluxe.java:184: error: local variable height is accessed from within inner class; needs to be declared final
height = img.getHeight();
I have played around with where I initialize height but nothing has worked. Any help would be appreciated.
I have another class called ProgramWindow in which I add all the different JPanels of the image editor to one main JFrame and I think this is where my problem might be, as the BufferedImage is null. Here is the code for ProgramWindow:
class ProgramWindow extends JFrame
{
ProgramWindow()
{
ImagePanel ip = new ImagePanel();
ChooseFile cf = new ChooseFile();
ButtonPanel bp = new ButtonPanel(ip.getImg());
add(ip, BorderLayout.CENTER);
add(cf, BorderLayout.SOUTH);
add(bp, BorderLayout.WEST);
}
}
I have concluded that the ButtonPanel in ProgramWindow is being passed a null parameter but I do not know why this is. I have a method called getImg in the ImagePanel class which I am calling as the parameter for ButtonPanel. Here is the code for ImagePanel:
class ImagePanel extends JPanel
{
BufferedImage img;
ImagePanel()
{
setBackground(Color.BLUE); //to test
final JButton button = new JButton ("Display picture");
add(button);
ActionListener action =
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==button)
{
try
{
img = ImageIO.read(ChooseFile.getFile());
}
catch(IOException f)
{
f.printStackTrace();
}
repaint();
}
}
};
button.addActionListener(action);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (img != null)
g.drawImage(img, 0, 0, this);
}
public void setImage(BufferedImage i)
{
img = i;
repaint();
}
public BufferedImage getImg()
{
return img;
}
}
You're declaring height in the constructor and so it is local to the constructor. Perhaps it would be better to make it an instance field of the class instead.
public class ButtonPanel extends JPanel {
private BufferedImage img;
private int height;
Having said that, why even have a height variable field, since you can obtain it any time you'd like by calling img.getHeight()?
Edit
Your second problem, one we can't help you on yet, is that your img variable holds a null reference. Given your new code, this suggests that ip.getImg() is returning null, but don't take my word on this, test it. Put this line in your code:
System.out.println("is ip.getImg() returning null? " + (ip.getImg()));
Edit 2
Of course you're getting null. You're extracting img from ImagePanel before the user has had a chance to interact with it. Since it only gets an image when the user presses the button, and since you're extracting the image on class creation, before the user has had a chance to do squat, the only possibility is that when you extract the image on class creation, you're going to get null. Solution: don't do that.
Newbie, so bear with me. I am writing a Sokoban game in Java, I got the game up and going but I am having problems with pack(). I want my frame to resize itself depending on the size of the level, different levels have different sizes. The panel is being painted correctly for the different sizes, so if I just maximize the frame then everything is good, but how do I invoke pack() to automatically resize the frame? I tried to put pack() in my Main method, but I suspect the solution is not so simple (probably the way I have structured my program does not help either). Putting pack() in the Main method produces the image attached, a very small rectangle with basically just the min,max and close buttons.
The recommended solution that I would like to implement is as follows:
write your Sokoban constructor so that it takes the surrounding JFrame as a reference parameter that your object then remembers in a field. Then after you change the preferred size of your Sokoban component, call the method pack for this stored surrounding JFrame.
I have attached the code for my constructor and Main method.
public class Sokoban extends JPanel {
LevelReader lReader = new LevelReader();
private static final int SQUARESIZE = 50; // square size in pixels
int currentLevel = 0;
int height = 0;
int width = 0;
int x = 0;
int y = 0;
Contents [][] mapArray;
public Sokoban(String fileName) {
lReader.readLevels(fileName);
initLevel(currentLevel);
KeyListener listener = new MyKeyListener();
addKeyListener(listener);
this.setPreferredSize(new Dimension(500,500));
setFocusable(true);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Sokoban");
Sokoban sokoban = new Sokoban("m1.txt");
frame.add(sokoban);
frame.setVisible(true);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
write your Sokoban constructor so that it takes the surrounding JFrame as a reference parameter that your object then remembers in a field. Then after you change the preferred size of your Sokoban component, call the method pack for this stored surrounding JFrame
Answer was updated to use key binding as suggested by #mKorbel (thanks for tip, code looks cleaner now)
What your fried was trying to tell is to create something like this (I removed your code that wasn't necessary in this example)
class Sokoban extends JPanel {
private JFrame frame;
private class MyAction extends AbstractAction {
private Dimension dimension;
public MyAction(Dimension dimension) {
this.dimension = dimension;
}
#Override
public void actionPerformed(ActionEvent e) {
//we will pack only when dimensions will need to change
if (!getPreferredSize().equals(dimension)) {
setPreferredSize(dimension);
frame.pack();
}
}
}
public Sokoban(String fileName, JFrame tframe) {
this.frame = tframe;
setFocusable(true);
setPreferredSize(new Dimension(100, 100));
setBackground(Color.red);
add(new JLabel("press A, S, D"));
getInputMap().put(KeyStroke.getKeyStroke('a'), "typed a");
getInputMap().put(KeyStroke.getKeyStroke('s'), "typed s");
getInputMap().put(KeyStroke.getKeyStroke('d'), "typed d");
getActionMap().put("typed a", new MyAction(new Dimension(100, 100)));
getActionMap().put("typed s", new MyAction(new Dimension(200, 100)));
getActionMap().put("typed d", new MyAction(new Dimension(100, 200)));
}
public static void main(String[] args) {
JFrame frame = new JFrame("Sokoban");
Sokoban sokoban = new Sokoban("m1.txt", frame);
frame.setContentPane(sokoban);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
In constructor public Sokoban(String fileName, JFrame tframe) you need to pass reference to frame that will contain your Sokoban panel. You will need to store object from that reference somewhere in your class, like in class field private JFrame frame;.
Now thanks to that reference whenever you change size of your panel you can use it to change size of frame containing that panel by invoking frame.pack() and make it to adapt to new size.
public class MinesweeperMenu extends MinesweeperPanel{
private JPanel picture = new JPanel();
private JButton play = new JButton("Play");
private JButton highScores = new JButton("High Score and \nStatistics");
private JButton changeMap = new JButton("Create Custom \nor Change Map");
private JButton difficulty = new JButton("Custom or\nChange Difficulty");
private JButton user = new JButton("Change User");
Image img;
public MinesweeperMenu()
{
// Set Layout for the menu
LayoutManager menuLayout = new BoxLayout(menu, BoxLayout.Y_AXIS);
menu.setLayout(menuLayout);
// Set Layout for the window
LayoutManager windowLayout = new BorderLayout();
window.setLayout(windowLayout);
// Add buttons to the panels
menu.add(play);
menu.add(highScores);
menu.add(changeMap);
menu.add(difficulty);
menu.add(user);
// Add picture to the frame
try{
File input = new File("./setup/images/MineMenuPicture.jpg");
img = ImageIO.read(input);
}
catch(IOException ie)
{
System.out.println(ie.getMessage());
}
// Add action listeners
changeMap.addActionListener(new ChangeMapListener());
}
public void paintComponent(Graphics g)
{
// POSITION OF THE PICTURE
int x = 650;
int y = 585;
g.drawImage(img, x, y, null);
}
public void displayFrame()
{
// Display Frame
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[] args)
{
MinesweeperMenu menu = new MinesweeperMenu();
window.pack();
menu.displayFrame();
window.repaint();
}
}
public class MinesweeperPanel extends JFrame{
public static final Color COLOR_KEY = new Color(220, 110, 0);
// Initialize all the objects
public static JFrame window = new JFrame("Minesweeper++");
public static JPanel menu = new JPanel();
// Close the current window
public static void close()
{
window.setVisible(false);
window.dispose();
}
}
I can't get my image to display in the frame. I've tried everything, but I'm getting the impression it's a mistake that I'm not realizing since I am new to Java Swing. Any help would be greatly appreciated.
You're making things difficult for yourself by having a very confusing program structure, and I suggest that you simplify things a lot.
For one, there's no need for your current MinesweeperMenu class to extend MinesweeperPanel, and for the latter class to extend JFrame. Then you have a static JFrame somewhere else -- that's too many JFrames, and to boot, you're trying to display your image in one JFrame but showing the other one that doesn't have the picture. Your program needs just one JFrame and it should probably be created, stuffed with its contents, packed and displayed in one place, not scattered here and there as you're doing.
You're trying to display the picture in a paintComponent override, but this method will never get called since your class extends JFrame (eventually) and JFrame doesn't have this method. You're using the right method, but the class should be extending JPanel, and you should have an #Override annotation above the paintComponent method block to be sure that you're actually overriding a parent method.
You should get rid of all static everything in this program. The only thing static here should be the main method and perhaps some constants, but that's it.
There are more errors here, and I have too little time to go over all of them. Consider starting from the beginning, starting small, getting small bits to work, and then adding them together.
For instance, first create a very small program that tries to read in an image into an Image object, place it in a ImageIcon, place the ImageIcon into a JLabel, and display the JLabel in a JOptionPane, that simple, just to see if you can read in images OK, for example, something like this:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class TestImages {
// *** your image path will be different *****
private static final String IMG_PATH = "src/images/image01.jpg";
public static void main(String[] args) {
try {
BufferedImage img = ImageIO.read(new File(IMG_PATH));
ImageIcon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JOptionPane.showMessageDialog(null, label);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then when you've done this, see if you can now create a JPanel that shows the same Image in its paintComponent method, and display this JPanel in a JOptionPane.
Then create a JFrame and display the image-holding JPanel in the JFrame.
Through successive iterations you'll be testing concepts, correcting mistakes and building your program.
File input = new File("./setup/images/MineMenuPicture.jpg");
If MineMenuPicture.jpg is an application resource, it should be in a Jar and accessed by URL obtained from Class.getResource(String).