I have a card project that I am doing and it uses GUI's. I have a JFrame
JFrame frame = new JFrame("Card Game");
//Splits the Jframe into two sections where the cards will be placed
//according to what user draws them
frame.setLayout(new GridLayout(1,2));
//The users, with different hands of cards
JPanel user1 = new JPanel();
JPanel user2 = new JPanel();
frame.add(user1);
frame.add(user2);
I want to be able to efficiently add/remove cards for each users hand. The maximum amount of cards that a user could draw is 9. Initially the user will start of with two cards and I want to make it so that I can add another card neatly. If the space in the panel runs out the cards should go start forming a row beneath.
How do I achieve this? I was thinking of somehow using JLabels, but don't know if this is a correct way. Also I don't know what layout I should use, so any help/tips would be appreciated. Thank you.
EDIT
Thank you for the help, but I still have a problem. I use the code that 'Lourenco' posted to use as my panel where I add cards. I didn't change it.
In my GUI class I added
MyPanel myPanel = new MyPanel();
public void addPlayerCard(Card c){
myPanel.addCard(c.getImageIcon());//should draw the card into the panel
}
This is how I add my imageicon to the card
java.net.URL imgURL = Card.class.getResource(imgFileName);
if (imgURL != null) {
image = new ImageIcon(imgFileName, "");
} else {
System.err.println("Couldn't find file: " + imgFileName);
image = new ImageIcon();
}
What am I doing wrong?
Try to use this class. Its a JPanel, so you can create an instance of MyPanel and add to your JFrame.
To add a card you must create an ImageIcon object [ex: ImageIcon card = new ImageIcon("c:\users\desktop\aceOfSpades.png")].
After creating the ImageIcon object you must call the addCard function and pass the card as argument. The card will be added to the ArrayList of cards and the painel will be repainted. You can manipulate the 2 constants CARD_WIDTH and CARD_HEIGHT and the variables x, y and widthToNextCard in the rapaintComponent method.
This way will give you a lot more freedom to paint the cards the way you want, instead of using a layout with different JLabels.
Good luck ;)
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
public final static int CARD_WIDTH = 50;
public final static int CARD_HEIGHT = 100;
private ArrayList<ImageIcon> cardsList;
public MyPanel() {
cardsList = new ArrayList<ImageIcon>();
}
public void addCard(ImageIcon newCard) {
cardsList.add(newCard);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int widthToDrawNextCard = 75;
int x = 50;
int y = 100;
for (int i = 0; i < cardsList.size(); i++) {
ImageIcon card = cardsList.get(i);
Image image = card.getImage();
g.drawImage(image, x, y, CARD_WIDTH, CARD_HEIGHT, null);
x = x + widthToDrawNextCard;
}
}
}
Related
I have some images that i need to change on click, right now there is only three images of each category, 3 noses, 3 eyes and 3 mouths. So i took this approach to my solution, however i realize this is not the best way to go about it because the number of images is hard coded i would like it to change dinamically. Im in need of some ideas, or suggestions.
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class ImagePanel extends JPanel {
/**
* Create the panel.
*/
private int nose = 1;
private int mouth = 1;
private int eyes = 1;
Color[] color ={Color.BLUE, Color.RED, Color.PINK,Color.CYAN,Color.WHITE};
static int colorCounter =1 ;
public ImagePanel() {
}
public void changeNose(){
nose = ++nose % 3;
nose++;
}
public void changeMouth(){
mouth = ++mouth % 3;
mouth++;
}
public void changeEyes(){
eyes = ++ eyes % 3;
eyes++;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.green);
g.setColor(color[colorCounter]);
g.fillOval(40, 120, 400, 400);
ImageIcon hat = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/santa.png"));
hat.paintIcon(this, g, 160, 3);
ImageIcon eyes1 = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/eyes"+eyes+".png"));
eyes1.paintIcon(this, g,180, 200);
ImageIcon nose1 = new ImageIcon(ImagePanel.class.getResource("/a06Face/Images/nose"+nose+".png"));
nose1.paintIcon(this, g, 180, 300);
ImageIcon mouth1 = new ImageIcon
(ImagePanel.class.getResource("/a06Face/Images/mouth"+mouth+".png"));
mouth1.paintIcon(this, g, 170, 400);
repaint();
}
}
You could use a MouseListener.
How to do this:
//in your Class constructor
public XYZ()
{
.....
Timer t = new Timer(0,new Listener());
t.start();
addMouseListener(new Mouse());
// later in program
private class Mouse extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
<object>.doMethod(e.<otherMethod>);
}
}
This is just how to use a generic MouseListener. Modify this to fit your program.
Well, let's try this out. Let's define an instance field which holds all the image items in our system. This may be something like,
private List<ImageIcon> imgIcons = new ArrayList<ImageIcon>;
Then write a method to add image icons to this list. It may look like this.
private void addImageIcon(ImageIcon imgIcon){
this.imgIcons.add(imgIcon);
}
Call this method from anywhere you need to add the images. Then you can get the size of the array when you need to count the number of images in this panel. Hope this helps. Happy Coding !
I am beginner to Swing and I am writing some codes. I have added images on JLabel and JLabel on JFrame. I want to move that Image. Is it possible to move that image(fish). If yes, How can I do it?
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Aquarium extends JFrame{
private ImageIcon fish2image;
private ImageIcon fish1image;
private ImageIcon image;
private JLabel imglabel;
private JLabel fish1label;
private JLabel fish2label;
int numberFish = 12;
public Aquarium(){
initComponents();
setTitle("The Aquarium");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setResizable(false);
setBounds(500,200,500,300); //left,top,width,height
add(fish1label);
add(fish2label);
add(imglabel);
}
private void initComponents(){
image = new ImageIcon(getClass().getResource("../res/aquarium.gif"));
fish1image = new ImageIcon(getClass().getResource("../res/smallFish.gif"));
fish2image = new ImageIcon(getClass().getResource("../res/smallFish2.gif"));
imglabel = new JLabel(image);
fish1label = new JLabel(fish1image);
fish2label = new JLabel(fish2image);
fish1label.setBounds(100,100,250,200);
fish2label.setBounds(50,25,200,200);
}
public static void main(String[] args) {
new Aquarium();
}
}
Repeat question. But you would shift the x, and y values (Based on keyBindings or KeyListener added on frame) and it will automatically repaint.
But since you want the fist to move automatically. You are going to need either a loop based on a swing timer, Thread.sleep(1000); <= Highly not recommended, or a Thread.
Then you would shift the x and y values as described above as a certain amount of seconds pass within the method that you choose
Current code
ThreeColorButton class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ThreeColorButton {
private static CompositeIcon icons = new CompositeIcon();
private static JPanel panel = new JPanel();
private static JFrame frame = new JFrame();
private static JLabel label = new JLabel();
public static void main(String[] args) {
//create rgb buttons
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
//add rgb buttons to panel
panel.add(redButton);
panel.add(greenButton);
panel.add(blueButton);
//add action listeners to buttons
redButton.addActionListener(buttonListener(40, Color.red));
greenButton.addActionListener(buttonListener(40, Color.green));
blueButton.addActionListener(buttonListener(40, Color.blue));
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private static ActionListener buttonListener(final int size,final Color color) {
return new ActionListener() {
public void actionPerformed(ActionEvent event) {
SquareIcon icon = new SquareIcon(size, color);
icons.addIcon(icon);
label.setIcon(icons);
frame.add(label, BorderLayout.SOUTH);
frame.repaint();
frame.pack();
}
};
}
}
CompositeIcon code
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class CompositeIcon implements Icon{
private ArrayList<Icon> icons;
private int size;
public CompositeIcon() {
icons = new ArrayList<Icon>();
}
public void paintIcon(Component c, Graphics g, int x, int y) {
int position = x;
for(Icon z : icons) {
z.paintIcon(c,g,position,y);
position = position + z.getIconWidth();
}
}
public int getIconHeight() {
return size;
}
public int getIconWidth() {
int total = 0;
for(Icon z : icons) {
total = total + z.getIconWidth();
}
return total;
}
public void addIcon(Icon z) {
icons.add(z);
}
}
SquareIcon class is only a simple little class that creates a square of a single color with a given size.
My question is, in my ThreeColorButton class, when I run it, it doesn't show any icons when I press either of the RGB buttons. However, in the buttonListener method, if I set label.setIcons(icons) to label.setIcons(icon), it shows a single square and it doesnt place it side by side.
I can't seem to figure out whats causing this behavior. Is there a problem with displaying an array of icons using JLabel?
There is nothing to paint in the label since the height of your Icon is 0, since you never set the size.
I would suggest code something like:
#Override
public int getIconHeight()
{
int size = 0;
for(Icon z : icons)
{
size = Math.max(size, z.getIconHeight());
}
return size;
}
You may want to check out Compound Icon. Similar to your class but it has more features. It supports horizontal/vertical/stacked icon and icon alignment options.
It doesn't support dynamically adding Icons so you would need to change that. I might looking adding that feature myself (when I get time) :)
I can't seem to figure out whats causing this behavior. Is there a problem with displaying an array of icons using JLabel?
Yes, as #mKorbel mentioned, there is a problem. A JLabel can only display a single icon. If you want to display n icons, you will need n JLabel instances.
Please excuse me if this is a very simple solution or stupid mistake - this is my first time attempting to implement graphics in Java! :)
I'm attempting to make a board of tiles, each is a Tile object, and all positions of the tiles are stored in a triple array of Tiles called 'content' (content[][][]).
In order to make each tile "clickable", I'm basically creating a label with each tile icon and positioning that tile on the board based on the Tile object's x,y coordinates. I do this for each of the non-null Tile objects in the content array.
This works fine when I use the graphics.drawImage function, but when I position each label using the setBorders() function it:
Creates the layout of tiles, but not perfectly - it seems some are missing or below others.
and
It creates a duplicate unpositioned layer above the other tiles that are in their sort-of correct positions.
The code for the function I'm calling is:
public void paintComponent(Graphics graphics) {
// let superclass paint to fill in background
super.paintComponent(graphics);
Tile[][][] content = b.getContent();
if (content==null || tileImages==null) {
return;
}
/* Set dummy previous label */
prevT.setBounds(-1,-1,1,1);
// draw tiles back to front
for (int i = 0; i<content.length; i++) {
for (int y = 0; y<content[i].length; y++) {
for (int x = 0; x<content[i][y].length; x++) {
final Tile t = content[i][y][x];
if (t!=null) {
if (y>0 && content[i][y-1][x]!=null && t.equals(content[i][y-1][x])) {
continue;
}
if (x>0 && content[i][y][x-1]!=null && t.equals(content[i][y][x-1])) {
continue;
}
Image image = tileImages[t.getValue()][t.getSubindex()];
if (b.free(t)) {
image = tileImagesHL[t.getValue()][t.getSubindex()];
}
/* Mouse event magic */
graphics.drawImage(image, x*TILEW+TILEW/2+i*TILESKEW, (y+1)*TILEH/2-i*TILESKEW, null);
/* Create icon to be displayed */
ImageIcon icon = new ImageIcon(image);
/* Label that acts as the clickable tile */
final JLabel label = new JLabel();
/* Associate image with label */
label.setIcon(icon);
/* Allow mouse events to interact with label */
label.addMouseListener(this);
/* Position labels according to tile coordinates */
label.setBounds(x*TILEW+TILEW/2+i*TILESKEW, (y+1)*TILEH/2-i*TILESKEW, image.getWidth(null), image.getHeight(null));
/* Associate label with specified tile */
t.setLabel(label);
/* Add label to list*/
labels.add(label);
this.setVisible(true);
this.add(label);
}
}
}
}
}
Any explanation for why this is happening would be greatly greatly appreciated! I've tried to re-write this function SO many times and am out of ideas!
Thank you! :)
1) don't create Object inside paintComponent(Graphics graphics), prepare these Object before
my view, simple comtainer with Mouse event magic without MouseListener
2) create JPanel and put there JButton#setBackground(someColor), and add JButton#setRolloverIcon(someIcon), no longer any MouseListener needed
3) if you create Tiles then look for GridLayout
4) prepare Icons and add these Icon to the JButton, nothing else, any Array of Objects, no code more than I described
import java.awt.*;
import javax.swing.*;
public class TilesWithButton {
private Icon warningIcon = UIManager.getIcon("OptionPane.warningIcon");
private Icon infoIcon = UIManager.getIcon("OptionPane.informationIcon");
private Icon errorIconRoll = UIManager.getIcon("OptionPane.errorIcon");
private JPanel myPanel = new JPanel();
public TilesWithButton() {
myPanel.setLayout(new GridLayout(1, 2, 1, 1));
JButton btn = new JButton();
btn.setBackground(Color.white);
btn.setIcon(infoIcon);
btn.setRolloverIcon(errorIconRoll);
btn.setFocusPainted(false);
myPanel.add(btn);
JButton btn1 = new JButton();
btn1.setBackground(Color.white);
btn1.setIcon(warningIcon);
btn1.setRolloverIcon(errorIconRoll);
btn1.setFocusPainted(false);
myPanel.add(btn1);
JFrame frame = new JFrame("Tiles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(myPanel);
frame.pack();
frame.setLocation(150, 100);
frame.setVisible(true);
}
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TilesWithButton tilesWithButton = new TilesWithButton();
}
});
}
}
I have created a class that extends JLabel to use as my object moving around a JPanel for a game.
import javax.swing.*;
public class Head extends JLabel {
int xpos;
int ypos;
int xvel;
int yvel;
ImageIcon chickie = new ImageIcon(
"C:\\Users\\jjpotter.MSDOM1\\Pictures\\clavalle.jpg");
JLabel myLabel = new JLabel(chickie);
public Head(int xpos, int ypos, int xvel, int yvel){
this.xpos = xpos;
this.ypos = ypos;
this.xvel = xvel;
this.yvel = yvel;
}
public void draw(){
myLabel.setLocation(xpos, ypos);
}
public double getXpos() {
return xpos;
}
public double getYpos() {
return ypos;
}
public int getXvel() {
return xvel;
}
public int getYvel() {
return yvel;
}
public void setPos(int x, int y){
xpos = x;
ypos = y;
}
}
I am then trying to add it onto my JPanel. From here I will randomly have it increment its x and y coordinates to float it around the screen. I can not get it to paint itself onto the JPanel. I know there is a key concept I am missing here that involves painting components on different panels. Here is what I have in my GamePanel class
import java.awt.Dimension;
import java.util.Random;
import javax.swing.*;
public class GamePanel extends JPanel {
Random myRand = new Random();
Head head = new Head(20,20,0,0);
public GamePanel(){
this.setSize(new Dimension(640, 480));
this.add(head);
}
}
Any suggestions on how to get this to add to the JPanel? Also, is this a good way to go about having the picture float around the screen randomly for a game?
First of all there is no need to extend a JLabel to do this.
a) you set the size of the label after you add the image to the label by using:
label.setSize( label.getPreferredSize() );
b) You don't need the draw(), and all the setter methods. To move the label all you do is use:
label.setLocation(...);
c) if you want to increment the location you would use something like:
label.setLocation( label.getLocation().x + 5, ...);
Once you set the size and location of the label you can add it directly to the panel. Make sure you have done:
panel.setPreferredSize()
when you add your panel to the content pane of your frame.
Your code is too vague to give specific suggestions. If you need more help post your SSCCE. Your problem could be the usage of layout manager or the fact you aren't using layout managers.
Yes, you should set the layout manager for your JPanel ( GamePanel ) to null that tells the system:
Don't place it for me, I'll do it manually
edit
I think it would be clearer if I give you a running demo.
See this example. As camickr points, you don't have to subclass the components.
import javax.swing.*;
import java.util.Timer;
import java.util.*;
class FloatingDemo {
public static void main( String [] args ){
// create the panel
JPanel panel = new JPanel();
panel.setLayout(null);
// create the label with an image
final JLabel label = new JLabel(new ImageIcon("StackOverflowLogo.png"));
label.setSize(label.getIcon().getIconWidth(),
label.getIcon().getIconHeight());
panel.add( label );
// create the frame containing both
JFrame frame = new JFrame();
frame.add( panel );
frame.setSize(800, 600 );
frame.setVisible( true );
// move it randomly every second
Timer timer = new Timer();
final Random random = new Random();
timer.schedule( new TimerTask() {
public void run(){
label.setLocation( random.nextInt(800-label.getWidth()),
random.nextInt(600-label.getHeight()));
}
}, 0, 1000 );
}
}
BTW, not setting the layout manager to null also works, but if you resize the window, the jpanel would automatically set the location for you.
running demo http://img444.imageshack.us/img444/2567/capturadepantalla201006c.png
The main problem I believe is that you don't really add the image to Head in your constructor.
What you need to do is create a new ImageIcon like you are doing, and in your constructor do something lie this;
public Head(int xpos, int ypos, int xvel, int yvel){
// calls the JLabel constructor to create a label with an image
super(new ImageIcon("C:\\Users\\jjpotter.MSDOM1\\Pictures\\clavalle.jpg"))
this.xpos = xpos;
this.ypos = ypos;
this.xvel = xvel;
this.yvel = yvel;
}
This will create your Head with the specified image.
Once you sort out the constructor issue, you can then call setLocation() on you Head object from the JPanel you have added it to. That is how you can move it around randomly.
Also, in the JPanel you are adding the Head to, you need to make sure you set the LayoutManaer to null, so you can manually place the component on the panel yourself.