Assistance With KeyEvent - java

I am making a platformer game for a class project and so far all I have been able to do is add the chicken character to the game. I need to be able to have him move forward on the press of "D" or right arrow. My code is:
public class Main extends JFrame {
public Main(){
//Creates Title Image
JLabel title = new JLabel(" ");
ImageIcon tl = new ImageIcon("title.gif");
title.setIcon(tl);
//Creates Start Image
final JButton start = new JButton("");
ImageIcon st = new ImageIcon("start.gif");
start.setIcon(st);
//Creates Options Image
JButton options = new JButton("");
ImageIcon opt = new ImageIcon("options.gif");
options.setIcon(opt);
options.setBackground(Color.BLACK);
//Create first frame for "Start" button
final JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 1));
p1.add(start, BorderLayout.CENTER);
//Create second panel for title label
final JPanel p2 = new JPanel(new BorderLayout());
p2.setLayout(new GridLayout(1, 3));
p2.add(title, BorderLayout.WEST);
//Create third panel for "Options" button
final JPanel p3 = new JPanel(new BorderLayout());
p3.setLayout(new GridLayout(1, 1));
p3.add(options, BorderLayout.SOUTH);
//Creates fourth panel to organize all other primary
final JPanel p4 = new JPanel(new BorderLayout());
p4.setLayout(new GridLayout(1, 3));
p4.add(p1, BorderLayout.WEST);
p4.add(p2, BorderLayout.CENTER);
p4.add(p3, BorderLayout.EAST);
//When button is clicked, it changes the level
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(start.isEnabled()) {
remove(p4);
setSize(1440, 500);
add(new ContentPanel1());
validate();
}
else {
return;
}
}
});
//Adds fourth panel to frame
add(p4, BorderLayout.CENTER);
}
public static void main(String arg[]) {
Main frame = new Main();
//Finds screen size of monitor
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//Creates the frame
frame.setTitle("Cockadoodle Duty: Awakening");
frame.setSize(screenSize);
frame.setLocale(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
String background = "#000000";
frame.setBackground(Color.decode(background));
}
}
class coordinate {
public static int x;
public static int y;
}
class ContentPanel1 extends JPanel{
Image back = Toolkit.getDefaultToolkit().getImage("level0.gif");
Image chick = Toolkit.getDefaultToolkit().getImage("chicken.gif");
ContentPanel1() {
MediaTracker mt = new MediaTracker(this);
mt.addImage(back, 0);
try {
mt.waitForAll();
} catch (InterruptedException e){
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
coordinate.x = 20;
coordinate.y = 321;
super.paintComponent(g);
int imwidth = back.getWidth(null);
int imheight = back.getHeight(null);
g.drawImage(back, 1, 1, null);
g.drawImage(chick, coordinate.x, coordinate.y, null);
}
public void MoveDirection(KeyEvent e, Graphics g) {
coordinate.x = 20;
coordinate.y = 321;
super.paintComponent(g);
int key = e.getKeyCode();
if(key == 68) {
coordinate.x += 1;
g.drawImage(chick, coordinate.x, coordinate.y, null);
}
}
}
The main trouble I have been having with my code is the bit at the end with the MoveDirection method. The way I have it going is by adding a new chicken to the frame (This was mainly due to the fact that I was just testing to see if the code worked). Is there a better way to do that too?

Start by taking a look at How to Use Key Bindings
NEVER call super.paintComponent(g); (or paintComponent(g);) directly from outside the context of the paintComponent method, there is a lot more to painting then just painting the component background. See Painting in AWT and Swing and Performing Custom Painting for more details. Instead, simply call repaint when you want to, well, repaint the component.
The use of MediaTracker is out of date and you should be using the ImageIO API instead, which will block automatically while reading the image. See Reading/Loading an Image for more details
Don't use Toolkit.getDefaultToolkit().getScreenSize() in combination with JFrame#setSize, the getScreenSize method does not take into account things like the task bar or dock of some OS's, instead use the JFrame#setExtendedState and pass it JFrame.MAXIMIZED_BOTH
frame.setLocale(null); isn't doing what you think it is

Related

How to make a JPanel that work like JOptionPane?

I'm making a simple POS system on NetBeans that would pop out a JPanel (quantity) asking for the quantity when the photo of the product is clicked. I am using a card layout and putting the panel inside the card layout doesn't seem to work as it is different in size. It's also very hard to position it since moving it makes a bigger panel (buy) absorb it and becomes a part of the panel, messing up the layout of that panel. I want to make the panel initially invisible and pop up only with this code:
public void mouseClicked(MouseEvent e) {
if (e.getSource() == bpie )
{
String name = "Banoffee Pie";
int price = 8;
quantity.setVisible(true);
}
}
I'm currently a beginner and have a hard time customizing JOptionPane dialogs and prefer the use of panels if possible. The problem could be solved with the use of another JFrame, however, the use of multiple frames according to experts, is bad practice.
Here is how I want the option pane to look:
I'm currently a beginner and have a hard time customizing JOptionPanes
The JOptionPane was made for utility rather than customizability. As soon as you start thinking 'How can I change a JOptionPane to..?' abandon the option pane and instead use a modal JDialog.
Here is an example of using a dialog. I've tweaked the layout along these lines:
The food icons centered below the title bar.
Abandoned the simpler button names for more descriptive ones.
Adding the question and answer in the same line with a spinner to choose the number.
Of course, colors need to be adjusted to suit the style seen above, which might (and might not - depending on further factors not immediately evident) best be approached by using a custom Pluggable Look and Feel.
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.Random;
public class SweetShop {
private JComponent ui = null;
private static JFrame frame = new JFrame("Sweet Shop");
private final JDialog dialog = new JDialog(frame, "Choose Sweets", true);
Random random = new Random();
SpinnerNumberModel quantityModel = new SpinnerNumberModel(1, 1, 144, 1);
SweetShop() {
initUI();
}
public final void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridBagLayout());
ui.setBorder(new EmptyBorder(40,100,40,100));
JButton button = new JButton("Buy Sweets");
ui.add(button);
ActionListener openChooserListener = (ActionEvent e) -> {
dialog.setLocationRelativeTo(button);
dialog.setVisible(true);
};
button.addActionListener(openChooserListener);
dialog.add(getSweetSelectionPanel());
dialog.pack();
}
private JPanel getSweetSelectionPanel() {
JPanel panel = new JPanel(new BorderLayout());
int pad = 10;
panel.setBorder(new EmptyBorder(pad, pad, pad, pad));
JPanel iconPanel = new JPanel();
for (int ii=0; ii<12; ii++) {
iconPanel.add(new JLabel(new ImageIcon(getSize16Image())));
}
panel.add(iconPanel, BorderLayout.PAGE_START);
JPanel buttonPanel = new JPanel();
JButton okButton = new JButton("Buy Delicious");
buttonPanel.add(okButton);
ActionListener okListener = (ActionEvent e) -> {
System.out.println("Yuuuummmmm.. x " +
quantityModel.getNumber().intValue());
dialog.setVisible(false);
};
okButton.addActionListener(okListener);
JButton cancelButton = new JButton("No Thanks");
buttonPanel.add(cancelButton);
ActionListener cancelListener = (ActionEvent e) -> {
System.out.println("I just like licking them.");
dialog.setVisible(false);
};
cancelButton.addActionListener(cancelListener);
panel.add(buttonPanel, BorderLayout.PAGE_END);
JPanel questionPanel = new JPanel();
questionPanel.setBorder(new EmptyBorder(20, 50, 20, 50));
panel.add(questionPanel); // automatically uses CENTER constraint
JLabel label = new JLabel("How many do you wish to buy?");
Font font = label.getFont();
label.setFont(font.deriveFont(Font.ITALIC));
label.setText("How many do you wish to buy?");
label.setBorder(new EmptyBorder(5, 5, 5, 5));
questionPanel.add(label);
JSpinner spinner = new JSpinner(quantityModel);
questionPanel.add(spinner);
return panel;
}
private Image getSize16Image() {
int w = 16;
int h = 16;
if (random.nextBoolean()) {
w = random.nextInt(12) + 4;
} else {
h = random.nextInt(12) + 4;
}
BufferedImage bi = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
return bi;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
SweetShop o = new SweetShop();
frame = new JFrame(o.getClass().getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setContentPane(o.getUI());
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}

How to add a JPanel graphic to a JFrame without covering the JFrame

I'm trying to add a small tornado graphic (upside down pyramid) to my Frame. I can get the tornado by adding it to the frame in the main method but when I do that all I see is the tornado graphic and not the GUI underneath it.
So, I'm now trying to add the Tornado graphic to the frame when its created in the createComponents method but it now doesn't appear at all. Instead all I can see it the GUI in the frame.
I' probably missing something easy but I can't seem to figure it out. I'm not sure what I need to to in order to get the GUI and the tornado graphic both to appear.
public class EFScaleViewer {
public static void main(String[] args) {
// TODO Auto-generated method stub
TornadoFrame frame = new TornadoFrame();
frame.setTitle("EF Scale");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
Here is where I create the frame and am trying to add the tornado:
public class TornadoFrame extends JFrame{
private JButton submit;
private JLabel label;
static JLabel errorLabel;
static JTextField textBox;
JPanel tornado = new TornadoComponent();
private static final int FRAME_WIDTH = 400;
private static final int FRAME_HEIGHT = 300;
//Constructor for the frame
public TornadoFrame() {
super();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
createComponents();
}
private void createComponents()
{
textBox = new JTextField(" ");
submit = new JButton("Submit");
label = new JLabel("Please enter a windspeed:");
errorLabel = new JLabel("Error Message " );
JPanel panel = new JPanel();
panel.add(label);
panel.add(textBox);
panel.add(submit);
panel.add(errorLabel);
panel.add(tornado);
add(panel);
}
}
I know this is working but I may be missing something so here is where I create the tornado:
public class TornadoComponent extends JPanel {
public void paintComponent(Graphics g) {
int[] xPoints = {100,200,0};
int[] yPoints = {0,200,200};
int nPoints = 3;
g.drawPolygon(xPoints, yPoints, nPoints);
}
}
You have to set the JPanels size for it to be able to display Graphics.
static class TornadoComponent extends JPanel {
public TornadoComponent() {
setPreferredSize(new Dimension(500, 500));
}
#Override
public void paintComponent(Graphics g) {
//Whatever
}
}
And in order to trigger paintComponent(Graphics g) you have to add tornado.repaint(); at the end of your createComponents() function.
private void createComponents() {
//All your components
panel.add(tornado);
add(panel);
tornado.repaint();
}
Now the Polygon is shown but not at the right place (slightly off the image)
Therefore we have to arrange your JPanels a bit:
private void createComponents() {
textBox = new JTextField(" ");
submit = new JButton("Submit");
label = new JLabel("Please enter a windspeed:");
errorLabel = new JLabel("Error Message " );
JPanel upper = new JPanel();
upper.setLayout(new BoxLayout(upper,BoxLayout.X_AXIS));
upper.add(label);
upper.add(textBox);
upper.add(submit);
upper.add(errorLabel);
JPanel lower = new JPanel();
lower.setLayout(new BoxLayout(lower,BoxLayout.X_AXIS));
lower.add(tornado);
JPanel over = new JPanel();
over.setLayout(new BoxLayout(over,BoxLayout.Y_AXIS));
over.add(upper);
over.add(lower);
add(over);
tornado.repaint();
}
Basically I make some boxes...
Over
Upper
... your stuff with text
Lower
Our tornado
Now our tornado is the wrong way round...
int[] xPoints = {100,200,150};
int[] yPoints = {0,0,150};
And voilĂ :
We just created a very basic tornado that is not aiming at anything :)
If you want to change the tornados position later you just have to recall tornado.repaint(); and you are all set.

JLabel not positioning correctly

I am just throwing together a quick and dirty GUI to display some data when I ran into an odd issue. The last label I add to the JFrame doesn't want to be positioned or display the border I put on it, so it looks like this:
Here is my code:
public DisplayData (Connection tConn)
{
ID = tID;
conn = tConn;
setupObjects();
setupFrame();
}
private void setupObjects()
{
JLabel caseLabel = new JLabel ("Case #:");
JLabel dateLabel = new JLabel ("Date:");
JLabel reportLabel = new JLabel ("Report:");
JLabel offenceLabel = new JLabel ("Offence:");
JLabel descriptionLabel = new JLabel ("Description:");
this.add(caseLabel);
this.add(dateLabel);
this.add(reportLabel);
this.add(offenceLabel);
this.add(descriptionLabel);
caseLabel.setBounds(50, 50, 130, 25); //x, y, width, height
dateLabel.setBounds(50, 100, 130, 25);
reportLabel.setBounds(50, 150, 130, 25);
offenceLabel.setBounds(50, 200, 130, 25);
descriptionLabel.setBounds(100, 50, 130, 25);
caseLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
dateLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
reportLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
offenceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
descriptionLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
private void setupFrame()
{
this.setTitle("Data Display");
this.setSize (650, 700); //Width, Height
this.setLocation(300, 10);
this.setResizable(false);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null);
}
Yes, I know I should be using a proper layout manager, but like I said i just wanted something quick and dirty. Plus, I will not be beaten by something that should be this simple. Any ideas would be appreciated.
EDIT:
As Compass and Neophyte pointed out, my order of operations was off. Flipped my method calls and all is good again in the world. Thanks for the 2nd pair of eyes.
Contrary to the original poster's strategy, or any of the answers so far, the best approach to this problem is to use layouts.
Here is an example that shows how easy it is to position fields using layouts, and to change the GUI on later updates to the specification.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class CourtDetailsGUI {
private JComponent ui = null;
static final String[] FIELD_NAMES = {
"Case #:",
"Date:",
"Report:",
"Offence:",
"Plaintiff:",
"Defendant:"
};
CourtDetailsGUI(int num) {
initUI(num);
}
public void initUI(int num) {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(getFieldsPanel(num), BorderLayout.PAGE_START);
JTextArea ta = new JTextArea(5, 40);
JScrollPane sp = new JScrollPane(ta);
JPanel p = new JPanel(new GridLayout());
p.add(sp);
p.setBorder(new TitledBorder("Details"));
ui.add(p);
}
private JPanel getFieldsPanel(int num) {
JPanel outerPanel = new JPanel(new FlowLayout());
JPanel innerPanel = new JPanel(new GridLayout(0, 1, 15, 15));
outerPanel.add(innerPanel);
for (int ii=1; ii<num; ii++) {
JLabel l = new JLabel(FIELD_NAMES[ii]);
l.setBorder(new LineBorder(Color.BLACK));
innerPanel.add(l);
}
return outerPanel;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
for (int ii=0; ii<FIELD_NAMES.length; ii++) {
CourtDetailsGUI o = new CourtDetailsGUI(ii+1);
JFrame f = new JFrame("Data " + (ii+1));
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);
}
}
Your order of operations is incorrect.
You initially call setupObjects();
This plays your objects out onto a JFrame, which has the default LayoutManager of BorderLayout.
By using the default add(Component comp) method, with BorderLayout, you end up putting the component into null for BorderLayout, which is not supposed to be normal. Furthermore, the reason you can't see the border for this object is because the border is actually the size of the frame. If you explicitly set a region for BorderLayout, then you'll see it work, but setting to no region seems to just break BorderLayout.
Additional add calls appear to free the previous item from the BorderLayout null management, allowing the bounds to take over.
Afterwards, you call setupFrame(); which removes the layout manager, but does not refresh what is currently rendered.
This sets the layout to null, which does nothing to how the frame is displayed, but just removes the layout.
To avoid this issue, call setupFrame(); prior to setupObjects();, and then setVisible(true) can be called at the end of setupObjects();

Background JSwing Image Loading Oddly

I can't seem to figure out how I would add in a background WITH all of my panels showing.
I tried to set the JFrame content pane as a label with an imageicon and the frame does show, it just doesn't show the image like above.
This is the code that I've used.
frame.setContentPane(new JLabel(new ImageIcon("res/Wallpaper.png")));
The second attempt I've used is to ADD (not set) an image into the content pane of the frame. This did not work as shown in the second picture above and it only shows the panels but no background. The code is on the bottom.
frame.getContentPane().add(new JLabel(new ImageIcon("res/Wallpaper.png")));
The third attempt I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane. This does not work and instead turns my screen blank.
Here is the code I've used and the class code is in the 1st answer of this link Setting background images in JFrame. The result is the 3rd image of this post.
File img = new File("res/Wallpaper.png");
BufferedImage myImage;
try {
myImage = ImageIO.read(img);
frame.setContentPane(new ImagePanel(myImage));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The 4th attempt I've tried is adding the picture into the main panel that fills up the screen. This does not work at all and instead breaks the image in half so half of the screen has the image half doesn't.
Here is the code I've used for my 4th attempt. The result is the 4th last image on the top.
BufferedImage myPicture;
try {
myPicture = ImageIO.read(new File("res/Wallpaper.png"));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
pMain.add(picLabel);
} catch (IOException e) {
e.printStackTrace();
}
I'm not sure why the JPanels aren't showing up.
I know that in the 1st example when you set the frame as a JLabel it gives it a null layout but that was the only way I could find to DISPLAY the image.
I would like to somehow add the panels ontop of the frame with that background but after reading numerous threads I could not find out how.
If anyone does find out, please post the code and explain if you can. I also have the class get the system class theme that sets it into the theme of what the computer is using. Ex. I am using a windows operating system so it shows it kind of like my operating system.
This thread is not a duplicate. In other threads they only have a frame but in my thread I have several panels that aren't showing for some particular reason.
EDIT: I don't know what's up, I tried to use this thread Setting background images in JFrame but I had no luck.
The 1st method it gave me I tried and then instead of showing anything it showed nothing at all, no picture no components nothing at all. In case if you need more information I have: 4 JPanels on the bottom of the screen, I also have a border surrounding my window but doesn't show up in the 1st window. I also have borders surrounding my panels too.
So the 1st method I've tried setting it on the content pane, image loads but all of the components are gone.
2nd method I've tried adding it into the content pane but yet again with no luck and I get a panel with no background.
3rd method I've tried is creating a separate class and overriding the paintComponent method and adding an image to the constructor of it then placing this object of the class into the setcontentPane() parameter of the frame. Does not work at all, all I get is a blank frame.
Code I am using for my frame:
public class LoginScreen {
JCheckBox remember_User;
JButton login, create_Account, forums, faqs;
Border whiteLine;
JTextField userField;
JFormattedTextField passField;
private void createView() {
// Created essential details for the frame
JFrame frame = new JFrame();
frame.setTitle("Name of the game");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Defining panels and a constraint on the bottomPanel.
// More info - Total amt of panels: 5
// pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in
// bottomPanel
// bottom panel is in pMain
// Giving panels some attributes like backgrounds and borders
JPanel pMain = new JPanel(new BorderLayout());
pMain.setBorder(BorderFactory.createMatteBorder(3, 3, 6, 3,
Color.DARK_GRAY));
frame.getContentPane().add(pMain);
whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setBackground(Color.green);
pInfo.setPreferredSize(new Dimension(200, 100));
pInfo.setBorder(whiteLine);
JPanel bottomCompPanel = new JPanel(new GridBagLayout());
GridBagConstraints bGBC = new GridBagConstraints();
bGBC.gridx = 0;
bGBC.gridy = 0;
bGBC.insets = new Insets(0, 20, 0, 0);
bGBC.anchor = GridBagConstraints.PAGE_END;
bottomCompPanel.add(pLogin, bGBC);
bGBC.gridx++;
bottomCompPanel.add(pInfo, bGBC);
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(bottomCompPanel);
pMain.add(bottomPanel, BorderLayout.SOUTH);
frame.setVisible(true);
}
public static void main(String[] args) {
LoginScreen login = new LoginScreen();
login.createView();
}
}
POST UPDATE 2: Here is the code that I've used using #peeskillet's 1st method. It works sort of but it gives me the same results as the 3rd photo, a cut off picture. P.S I add the panels down at the bottom to my JLabel at the end.
private void createView() {
//Created essential details for the frame
JFrame frame = new JFrame();
frame.setTitle("Name of the game");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JLabel background = new JLabel(new ImageIcon("res/Wallpaper.png"));
background.setLayout(new BorderLayout());
frame.setContentPane(background);
//Defining panels and a constraint on the bottomPanel.
//More info - Total amt of panels: 5
//pLogin and pInfo are in the bottomCompPanel and bottomCompPanel is in bottomPanel
//bottom panel is in pMain
//Giving panels some attributes like backgrounds and borders
whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400,250));
pLogin.setBorder(whiteLine);
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setBackground(Color.green);
pInfo.setPreferredSize(new Dimension(200,100));
pInfo.setBorder(whiteLine);
JPanel bottomCompPanel = new JPanel(new GridBagLayout());
GridBagConstraints bGBC = new GridBagConstraints();
bGBC.gridx = 0;
bGBC.gridy = 0;
bGBC.insets = new Insets(0,20,0,0);
bGBC.anchor = GridBagConstraints.PAGE_END;
bottomCompPanel.add(pLogin, bGBC);
bGBC.gridx++;
bottomCompPanel.add(pInfo, bGBC);
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
bottomPanel.add(bottomCompPanel);
background.add(bottomPanel, BorderLayout.SOUTH);
"I tried to set the JFrame content pane as a label with an imageicon"
You need to set the layout on the JLabel. It will be null be default.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel background = new JLabel(new ImageIcon(new URL(IMG)));
background.setLayout(new GridBagLayout());
background.add(loginPanel());
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel loginPanel() {
Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {}
});
}
}
"I've tried is to create a subclass of JComponent and Override the paintComponents method then setan object of it as the contentpane"
Should be paintComponent (no "s"), but just like with JLabel, you need to set the layout. JComponent layout is null be default. You also need to give it a preferred size when painting.
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
background.setLayout(new GridBagLayout());
background.add(loginPanel());
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel loginPanel() {
Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
class BackgroundComponent extends JComponent {
public ImageIcon background;
public BackgroundComponent(ImageIcon background) {
this.background = background;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(background.getIconWidth(), background.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background.getImage(),
0, 0,
background.getIconWidth(),
background.getIconHeight(), this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {}
});
}
}
Using (extending) JPanel instead of JComponent would be similar except JPanel does have a default layout which is FlowLayout.
UPDATE
To get your desired layout, you need to play around with the different layout managers. The combination I used is
Outer (main panel) -- BorderLayout
Bottom (bottom panel) -- BoxLayout inside (south) of outer layout
For the BorderLayout, you need to make sure the panel opaque property is set to false, as BorderLayout will stretch the panel and cover the background.
For the BoxLayout, you need to make sure to set the maximum size and the preferred size
import java.awt.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
public class BackgroundImage {
private static final String IMG = "http://i.stack.imgur.com/JEoYs.jpg";
private final Border whiteLine = BorderFactory.createLineBorder(Color.LIGHT_GRAY);
private void init() throws Exception {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent background = new BackgroundComponent(new ImageIcon(new URL(IMG)));
background.setLayout(new BorderLayout());
background.add(bottomPanel(), BorderLayout.SOUTH);
f.setContentPane(background);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel bottomPanel() {
JPanel bottomPanel = new JPanel();
bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
BoxLayout layout = new BoxLayout(bottomPanel, BoxLayout.X_AXIS);
bottomPanel.setLayout(layout);
bottomPanel.setOpaque(false);
bottomPanel.add(Box.createHorizontalGlue());
bottomPanel.add(loginPanel());
bottomPanel.add(Box.createRigidArea(new Dimension(10, 0)));
bottomPanel.add(infoPanel());
return bottomPanel;
}
private JPanel infoPanel() {
JPanel pInfo = new JPanel(new GridBagLayout());
pInfo.setAlignmentY(Component.BOTTOM_ALIGNMENT);
pInfo.setBackground(Color.green);
pInfo.setMaximumSize(new Dimension(200, 100));
pInfo.setPreferredSize(new Dimension(200, 100));
pInfo.setBorder(whiteLine);
return pInfo;
}
private JPanel loginPanel() {
JPanel pLogin = new JPanel(new GridBagLayout());
pLogin.setAlignmentY(Component.BOTTOM_ALIGNMENT);
pLogin.setBackground(Color.cyan);
pLogin.setPreferredSize(new Dimension(400, 250));
pLogin.setMaximumSize(new Dimension(400, 250));
pLogin.setBorder(whiteLine);
return pLogin;
}
class BackgroundComponent extends JComponent {
public ImageIcon background;
public BackgroundComponent(ImageIcon background) {
this.background = background;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(background.getIconWidth(), background.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background.getImage(),
0, 0,
background.getIconWidth(),
background.getIconHeight(), this);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
new BackgroundImage().init();
} catch (Exception ex) {
}
});
}
}
For more information about using the different layout managers, see
Laying Out Components Within a Container
You can try JLayeredPane and setOpaque(boolean) method.
Code:
public class BackgroundImageTest{
private JFrame frame;
public BackgroundImageTest() {
frame = new JFrame("Background Image Frame");
// set frame properties
JPanel panel = new JPanel(new FlowLayout());
panel.setOpaque(false);
JButton btn = new JButton("Change Background");
panel.add(btn);
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae) {
setBackgroundImage(getImage(new File("Wallpaper2.png")));
}
});
JPanel main = (JPanel) frame.getContentPane();
main.setLayout(new FlowLayout());
main.add(panel);
main.setOpaque(false);
setBackgroundImage(getImage(new File("Wallpaper.png")));
frame.setVisible(true);
}
private Image getImage(File imageFile) {
BufferedImage image = null;
try {
image = ImageIO.read(imageFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return image;
}
private void setBackgroundImage(Image img) {
if(img == null) return;
ImageIcon ii = new ImageIcon(img);
JLabel lblBG = new JLabel(ii);
lblBG.setName("BackgroundImageLabel");
JLayeredPane layeredPane = frame.getLayeredPane();
Component[] comps = layeredPane.getComponentsInLayer(new Integer(Integer.MIN_VALUE));
for (int i = 0; i < comps.length; i++) {
System.out.println(comps[i].getName());
if (comps[i] instanceof JLabel && comps[i].getName().equals("BackgroundImageLabel")){
layeredPane.remove(comps[i]);
break;
}
}
layeredPane.add(lblBG, new Integer(Integer.MIN_VALUE));
lblBG.setBounds(0,0,ii.getIconWidth(), ii.getIconHeight());
}
}

What Layout Should I Use for This Project (Java)

I am making a platformer game for a project for class and need to have a chicken character jump on some platforms. I have a start screen and a button, and when the button is clicked, it will change the frame to the first level. When I add the chicken character to the frame as well as the background image, all I can see is the background image. Should I be using a different layout or is there something else I can do. This is my code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Main extends JFrame {
public Main(){
//Creates Chicken Character
final JLabel chicken = new JLabel(" ");
ImageIcon chick1 = new ImageIcon("chicken.gif");
ImageIcon chick2 = new ImageIcon("chicken2.gif");
chicken.setIcon(chick1);
//Sets Chicken Location
chicken.setLocation(1, 1);
//Creates Title Image
JLabel title = new JLabel(" ");
ImageIcon tl = new ImageIcon("title.gif");
title.setIcon(tl);
//Creates Start Image
final JButton start = new JButton("");
ImageIcon st = new ImageIcon("start.gif");
start.setIcon(st);
//Creates Options Image
JButton options = new JButton("");
ImageIcon opt = new ImageIcon("options.gif");
options.setIcon(opt);
options.setBackground(Color.BLACK);
//Creates label for level 0 background image
JLabel background = new JLabel(" ");
ImageIcon back = new ImageIcon("level0.gif");
background.setIcon(back);
//Creates a panel for level 0
final JPanel p5 = new JPanel();
chicken.setLocation(1, 1);
p5.add(background);
//Create first frame for "Start" button
final JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 1));
p1.add(start, BorderLayout.CENTER);
//Create second panel for title label
final JPanel p2 = new JPanel(new BorderLayout());
p2.setLayout(new GridLayout(1, 3));
p2.add(title, BorderLayout.WEST);
//Create third panel for "Options" button
final JPanel p3 = new JPanel(new BorderLayout());
p3.setLayout(new GridLayout(1, 1));
p3.add(options, BorderLayout.SOUTH);
//Creates fourth panel to organize all other primary
final JPanel p4 = new JPanel(new BorderLayout());
p4.setLayout(new GridLayout(1, 3));
p4.add(p1, BorderLayout.WEST);
p4.add(p2, BorderLayout.CENTER);
p4.add(p3, BorderLayout.EAST);
//When button is clicked, it changes the level
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(start.isEnabled()) {
remove(p4);
add(new ContentPanel());
add(chicken);
chicken.setLocation(100, 100);
setSize(1440, 500);
setLocale(null);
chicken.isOpaque();
validate();
}
else {
return;
}
}
});
//Adds fourth panel to frame
add(p4, BorderLayout.CENTER);
}
public static void main(String arg[]) {
Main frame = new Main();
//Finds screen size of monitor
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//Creates the frame
frame.setTitle("Cockadoodle Duty: Awakening");
frame.setSize(screenSize);
frame.setLocale(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
String background = "#000000";
frame.setBackground(Color.decode(background));
}
}
class ContentPanel extends JPanel{
Image bgimage = null;
ContentPanel() {
MediaTracker mt = new MediaTracker(this);
bgimage = Toolkit.getDefaultToolkit().getImage("level0.gif");
mt.addImage(bgimage, 0);
try {
mt.waitForAll();
} catch (InterruptedException e){
e.printStackTrace();
}
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
int imwidth = bgimage.getWidth(null);
int imheight = bgimage.getHeight(null);
g.drawImage(bgimage, 1, 1, null);
}
}
Note: It's been a while since I used the Graphics API
Quick Answer:
You need to draw everything in your paintComponent method. Your drawing routine should check the state of all game objects and draw them accordingly. Right now the panel is drawing the background image - that's it. Add your chicken image the same way you added your bgImage.
Some more things to consider:
If you experience screen flicker look into Double Buffering.
Not to overwhelm you but you might want to do some light reading on game coding. Get a general idea on how to code your game loop and what happens each time the loop is executed.
Since you are using an OO language you should also probably make a Chicken class.
public class Chicken {
private int x;
private int y;
private Image chickenSprtie;
//add get / set for access
}
Or even a general Super Class - Sprite with int x, int y. Or even a "Drawable" interface to forces all your drawable game objects to have common methods....

Categories