I'm trying to create a game in Java - the game is going to be a 2-D scrolling game. I have a class called CornPanel which extends JPanel and shows a corn plant - the CornPanel's are what will be moved across the screen. I know the CornPanel class is working because it shows up when I add it directly to a JFrame. However, when I try to add a CornPanel to another JPanel and then add that JPanel to the JFrame, the CornPanel doesn't show up.
Here's my CornPanel class (abbreviated - I took out the stuff I'm pretty sure isn't causing the problem):
package game;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class CornPanel extends JPanel{
BufferedImage cornImage;
public CornPanel(){
loadImages();
}
public void loadImages(){
try{
cornImage = ImageIO.read(new File("src\\cornBasic.png"));
} catch(IOException e){
e.printStackTrace();
}
}
protected void paintComponent(Graphics g){
g.drawImage(cornImage, 0, 0, cornImage.getWidth(), cornImage.getHeight(), this);
}
}
My Game class:
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JFrame{
ArrayList<CornPanel> cornPanels;
JPanel gameContainer;
public Game(){
cornPanels = new ArrayList<CornPanel>();
gameContainer = new JPanel();
setSize(1000, 1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(new Color(98, 249, 255));
setExtendedState(JFrame.MAXIMIZED_BOTH);
getContentPane().add(gameContainer);
addCornPanel();
setVisible(true);
}
public void addCornPanel(){
CornPanel cornPanel = new CornPanel();
cornPanels.add(cornPanel);
gameContainer.add(cornPanel);
cornPanel.setVisible(true);
getContentPane().repaint();
repaint();
}
public static void main(String[] args) {
Game game = new Game();
}
}
Note: I got it to work by setting the LayoutManager for both the JFrame and gameContainer to new GridLayout(1,1), but the problem is that then I can't use setLocation() on the CornPanel in order to make it animate. If there's a way to do it without setLocation() let me know. Also, I took out a lot of code I don't think is necessary for diagnosing the problem - hopefully I didn't take out too much.
Your corn panel doesn't specify a prefered size, so the layout manager probably is just setting it to 0x0.
There is an easier way to add an icon into a pane. JLabel::JLabel(Icon) will create a label that has the image icon specified, and is of the right size to hold it.
If you do need something more complex than a single image, then your JComponent implementation should override getPreferredSize().
You also should call "pack" on your jframe, so that it can figure out the ideal size for display.
A few other comments not related to your original question:
You shouldn't extend JFrame for the main frame, just create a new JFrame instance, and configure it.
You should do the work in the Event Dispatch Thread. See EventQueue and more specifically read through Lesson: Concurrency in Swing
I know the CornPanel class is working because it shows up when I add it directly to a JFrame. However, when I try to add a CornPanel to another JPanel and then add that JPanel to the JFrame, the CornPanel doesn't show up.
The layout of the content pane of a frame is BorderLayout, the default constraint is CENTER which stretches a component to fill the space.
The default layout of a panel is FlowLayout which ..doesn't stretch the component to fit.
The best way to fix this is to (firstly) override the getPreferredSize() method of CornPanel to return a sensible size, then add it to a layout/constraint that has the behavior required when it has more space than it needs.
Related
I have issue with drawing shapes inside of JPanel that I already added using Netbeans GUI. Now, I have no idea where to add code for drawing a circle inside of that JPanel and how to insert and call it in the JPanel that is sitting empty now, waiting for this shape to be drawn. I already set up destination JPanel to be Flow layout.
Netbeans Designer created a big class in which I have entire frame with this JPanel, and I want to keep it inside of it as I can't really add it any other way because Designer doesn't let me change main initComponents method in which all components are sitting now. I have been reading tutorials and previous posts but noone really encountered this using Netbeans Designer.
SO can someone just help me with adding proper method in this frame class and how to call it from JPanel I want to draw in. JPanel is 50x50 pixels.
So as per #Abra, I changed some code:
so I made a new Circle Class, adjusted it a bit as I don't want to create a new frame but put this in JPanel.
public class Circle extends JPanel {
Color color;
public void circle(Color color) {
this.color = color;
setPreferredSize(new Dimension (30,30));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(0, 0, r, r);
g.setColor(color);
}
private void showGUI() {
JPanel panel = new JPanel();
panel.add(this, FlowLayout.CENTER);
panel.setVisible(true);
}
}
Then I opened JPanel in Designer, and added code to run it, in initComponents method like this:
circlePanel.setPreferredSize(new java.awt.Dimension(40, 40));
new Circle().showGUI();
PanelDS.add(circlePanel);
circlePanel is destination for this drawing and is inside PanelDS itself. It doesn't work this way tho, but Netbeans shows no errors in code. Additionally, how can I forward color to circle class.
In order to draw on a JPanel you need to override the paintComponent() method of JPanel. In order to override the method, you need to create a class that extends JPanel. I don't think that there exists a GUI designer that can generate the required code for you. So you have to write the code of the class that extends JPanel.
Here is a minimal example. It displays a blue circle.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Drawing2 extends JPanel {
private JFrame frame;
public Drawing2() {
setPreferredSize(new Dimension(100, 100));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(25, 25, 50, 50);
}
private void showGui() {
frame = new JFrame("Drawing");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
new Drawing2().showGui();
}
}
Here's what you should see when you run the above code.
Background:
I'm tearing my hair here because I've used awt and Swing a couple of times, and I always run into a roadblock during my initial graphics setup and I never seem to have an "Of course, this thing again! I just have to something something"-moment. This time I can't seem to get even basic drawing to work!
Problem description:
I wish to draw a number of simple boxes in a JFrame (via a JPanel, if necessary). To this end I have a Sprite extends JComponent class which currently only draws simple geometric shapes but will eventually do things with BufferedImageor somesuch.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class Sprite extends JComponent {
private Rectangle rctBounds;
private Color clrFill;
public Sprite(int x, int y, Color color) {
this.rctBounds = new Rectangle(x, y, 100, 100);
this.clrFill = color;
}// Sprite(int,int,Color)
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(clrFill);
g.fillRect(rctBounds.x, rctBounds.y, rctBounds.width, rctBounds.height);
}// paintComponent(Graphics)
}// Sprite.class
The window for these to go in is obtained by a simple Win extends JFrame class รก:
import javax.swing.JFrame;
public class Win extends JFrame{
public Win(){
setSize(800,600);
setLocation(100,100);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
Finally, components are initialized and connected in the main method, in the class run, using JComponent's (I believe) add() method, called on an instance of Win:
import java.awt.Color;
public class run {
public static void main(String[] args) {
Win w = new Win();
Sprite s1 = new Sprite(10,100, Color.BLUE);
Sprite s2 = new Sprite(200,200, Color.RED);
Sprite s3 = new Sprite(300,200, Color.CYAN);
w.add(s1);
w.add(s2);
w.add(s3);
}//main()
}//run.class
Expectations vs. Reality:
Now, I expect a window with three colored boxes, as in this image (all boxes visible). Instead, only the final JComponent to be added shows up, as seen here (only cyan box painted). What's even more infuriating is that attempting to edit the JFrame's layout or adding a JPanel as an intermediary container for the Sprites results in a blank window.
Exasperated Plea:
I'm at a complete loss! Everything I find on here talks about improper use of paintComponent(Graphics) (using paint() instead, forgetting to #Override, not propagating the graphical context properly, etc) or to use a JPanel as an intermediary container. The most infuriating part of all this is that I've built two functioning programs using Swing before (school assignments) and, looking at that code, I cannot for the life of me figure out what I'm doing wrong here! Please help!
I am trying to create text-fields on frame by getting input at run-time. Is it possible? Or I have to create another frame for that. I tried this code, but it's not working. Please Help me out, and tell me what's wrong with this code.
import java.awt.BorderLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Check extends JFrame implements ActionListener
{
JTextField txtqty;
JTextField[] tfArr;
JPanel p1,p2;
JButton bsmbt;
public Check()
{
GUIDesign();
}
public void GUIDesign()
{
p1 = new JPanel();
txtqty = new JTextField(10);
JButton bsmbt= new JButton("OK");
p1.add(txtqty);
p1.add(bsmbt);
p2=new JPanel();
p2.setLayout(null);
add(p1,BorderLayout.NORTH);
setSize(500, 500);
setVisible(true);
setLocation(100, 100);
bsmbt.addActionListener(this);
}
public static void main(String[] args)
{
new Check();
}
public void TFArray(JTextField[] temp)
{
int x,y,width,height;
x=10;y=30;width=50;height=20;
int no_of_textboxes = Integer.parseInt(txtqty.getText());
temp=new JTextField[no_of_textboxes];
for(int i=0;i<no_of_textboxes;i++)
{
temp[i]= new JTextField(10);
temp[i].setBounds(x, y, width, height);
x+=(width+10);
p2.add(temp[i]);
}
add(p2);
}
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(this, txtqty.getText());
TFArray(tfArr);
}
}
->Method TFArray() isn't working.
You have many errors in your code:
public void TFArray(JTextField[] temp): method names should start with lowerCamelCase
You're extending JFrame, you shouldn't extend JFrame, because when you extend it your class is a JFrame, JFrame is rigid so you can't place it inside anything else, instead you might consider creating a JFrame instance and if you ever need to extend JComponent extend from JPanel.
JButton bsmbt= new JButton("OK"); the variable bsmbt is a local variable inside your constructor, your global variable bsmbt is not used anywhere, and if you try to use it later you'll get a NullPointerException, instead change that line to:
bsmbt= new JButton("OK");
You're using null layout for p2, instead use a proper Layout manager and read Null layout is evil and Why is it frowned upon to use a null layout in swing?. Swing was designed to work with different PLAFs, screen sizes and resolutions, while pixel perfect GUIs (with setBounds()) might seem like the best and faster way to create a complex GUI in Swing, the more GUIs you make, the more errors you'll get due to this.
To solve your problem call revalidate() and repaint()
The above code creates 2 textfields. but when I again put some value and submit it, it doesn't seem to reflect any changes.
That might be because you're overriding x, y, height and width variables each time you enter TFArray method. But that is a guess, if you want a real answer, follow the suggestions above and post a proper and valid Minimal, Complete, and Verifiable example
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Gui_Window extends JFrame {
private JLabel Main_L;
public Gui_Window() {
setLayout(new FlowLayout());
Main_L = new JLabel("Did you know it is possible to bind keys?");
add(Main_L);
}
public static void main (String args[]) {
Gui_Window gui = new Gui_Window();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(300,300);
gui.setVisible(true);
gui.setTitle("Gamers AudioMute");
gui.setResizable(true);
}
}
I would like to know how to move my "Did you know" Label around. Could you also state how to align left, right, middle and how to move it around by its coordinates?
You can use methods included in Swing classes. Try
mainL.setHorizontalAlignment(SwingConstants.LEFT);
mainL.setVerticalAlignment(SwingConstants.BOTTOM);
The two methods setHorizontalAligment and setVeritcalAlignment both take integers that will set the start of either the horizontal or vertical component of the label to that pixel integer within the Swing window.
You should also read up on SwingConstants which allow you to plug in pre-defined integers by Swing that will align your texts to desirable locations within the panel. Here's a link
http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingConstants.html
They are also useful when manipulating different layouts such as BorderLayout and GridLayout.
I've created an applet game, but when I modify some of the contents, I need to (maximise or minimise) resize the window to show my modified applet.
even when I add a label, or anything, it needs resizing since I've not used the paint method.(no use of repaint).
Help me with this, how to show modified contents without resizing...
here's a sample code that have same problem.
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
public class Appl extends JApplet implements ActionListener{
Button b = new Button();
public void init()
{
setLayout(new FlowLayout());
setSize(300,300);
setVisible(true);
add(b);
b.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource()==b)
{
add(new Label("Button clicked"));
repaint();
}
}
}
If I remember correctly you just call the repaint method after the modifications of your content, then it should show up.
Repaint is always implicitly called when you resize the Applet.
Edit: Applying the validate medthod on the Japplet Container works for me in the given example. This also redraws added components, repaint just calls the paint method. try it :-)