Creating multiple panels in a frame? - java

I am trying to draw fish at whatever location the user enters, but it will either say
drawFish.java:38: error: cannot find symbol
outer.add(sPanel1);
Or
Exception in thread "main" java.lang.IllegalArgumentException: adding a window to a container
at java.awt.Container.checkNotAWindow(Container.java:483)
at java.awt.Container.addImpl(Container.java:1084)
at java.awt.Container.add(Container.java:410)
at drawFish.main(drawFish.java:38)
I was thinking that I need to make a new panel for each fish, but how do I make a loop to create multiple panels? If that is even the problem? Also, I am supposed to use a method that takes an x and a y coordinate so the user can change the location of a fish, and draw a number of fish at different locations. But that's not what I'm doing. I've tried to make a method including the questions of x and y, but then it says that the variables aren't public and thus can't be used in the paint method. I would appreciate explanations for everything, because I want to comprehend everything that I am doing.
public class drawFish extends JPanel {
int x = Integer.parseInt(JOptionPane.showInputDialog(null, "What is the x location of the fish? "));
int y = Integer.parseInt(JOptionPane.showInputDialog(null, "What is the y location of the fish? "));
int w = 200;
int h = 100;
int a = x + 20;
int b = y + 30;
int d = 50;
public drawFish() {
setPreferredSize(
new Dimension(400,400));
}
public void paint(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, w, h);
g.fillOval((w-5), y, d, h);
g.setColor(Color.BLACK);
g.fillOval(a, b, 25, 25);
}
public static void main(String[] args) {
MyFrame frame1 = new MyFrame("Drawing Fish");
JPanel outer = new JPanel();
int fn = Integer.parseInt(JOptionPane.showInputDialog(null, "How many fish would you like to draw? "));
for(int i=0; i<fn; i++){
drawFish sPanel1 = new drawFish();
}
outer.add(sPanel1);
frame1.add(outer);
frame1.pack();
frame1.setVisible(true);
}
}

Don't make many JPanels, just make one drawing JPanel.
Create a Fish class that is not a JPanel nor a component, but has a draw(Graphics g) method so that can draw itself at its current location when asked to.
Give your JPanel an ArrayList<Fish> and fill the list with Fish objects.
In your JPanel's paintComponent(Graphics g) method (not the paint method), loop through the ArrayList calling draw(g) on each Fish object it contains.
Be sure to call super.paintComponent(g) as the first line of your drawing JPanel's paintComponent(Graphics g) method so that old drawings will be erased.
Your for loop logic is off. If you're going to create objects inside of a for loop, you need to add them to something from inside of the loop. Else all you're dong is creating objects and discarding them, never to use them.
You will want to learn and stick with Java naming conventions. Class names, such as DrawFish, should start with an upper-case letter, and methods and variables with a lower-case letter.

sPanel1 variable's scope finishes as soon as you get out of loop.
Therefore replace
for(int i=0; i<fn; i++){
drawFish sPanel1 = new drawFish();
}
outer.add(sPanel1);
with
for(int i=0; i<fn; i++){
drawFish sPanel1 = new drawFish();
outer.add(sPanel1);
}
Now all panels will be added.
Also consider using a LayeredPane.
Hope this helps.

Related

Painting a group of objects in a JPanel

I'm pretty new to Java and the GUI world. Right now I'm trying to create a really basic space shooter. To create it I started creating a JFrame, in which I've later on put a personal extension of a JPanel called GamePanel, on which I'm now trying to display all my components. Until here it's all pretty clear, the problem comes now: I have my GamePanel in which I display my player, and on the KeyEvent of pressing S the player should shoot the Bullets. I've managed the bullets as an Array, called Shooter[], of Bullet Objects, created by myself this way:
public class Bullet implements ActionListener{
Timer Time = new Timer(20, this);
private int BulletY = 430;
public int PlayerX;
public Rectangle Bound = new Rectangle();
public Bullet(int playerx) {
this.PlayerX = playerx;
Time.start();
}
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillRect(PlayerX + 2, BulletY, 3, 10);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
if (Time.isRunning()) {
BulletY = BulletY - 5;
Bound = new Rectangle (PlayerX + 2, BulletY, 3, 10);
}
}
}
I thought that calling the draw method in the GamePanel's paint() method would have allowed me to display both all the bullets shot and the player. What actually happens is that at the start it seems allright, but when I press S the player disappears and just one bullet is shot. Can you explain me why? This is how my paint() method looks like:
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, 500, 500);
for(int i = 0; i < BulletsCounter; i++) {
Shooter[i].draw(g);
}
g.setColor(Color.RED);
g.fillRect(PlayerX, PlayerY, 20, 20);
//System.out.println("Here I should have painted the player...");
g.dispose();
}
BulletsCounter is a counter I've created to avoid any NullPointerExceptions in painting the whole array, it increases when S is pressed and so another bullet of the array is initialized and shot.
Thank you for your patience, I'm new to the site, so warn me for any mistake.
You've several significant problems, the biggest given first:
You're disposing a Graphics object given to you by the JVM. Never do this as this will break the painting chain. Instead, only dispose of a Graphics object that you yourself have created.
You're drawing within paint which is not good for several reasons, but especially bad for animation since you don't have automatic double buffering of the image
You don't call the super painting method within your override and thus don't allow the JPanel to do house-keeping painting.
Recommendations:
Don't dispose of the Graphics object, not unless you, yourself, create it, for example if you extract one from a BufferedImage.
Override the JPanel's paintComponent method, not its paint method to give you double buffering and smoother animation.
And call super.paintComponent(g) first thing in your override to allow for housekeeping painting

Image flickering upon being repainted by the mouseDragged method

As the title suggests, my problem is that I want to be able to drag an image.
In this specific case, I want to drag an image from one JPanel (or rather my own subclass) into another (different) subclass of JPanel. Therefore, I added an MouseListener to my JPanel subclass, so that upon clicking a certain area in the panel, an image is chosen to be painted on the JFrame (subclass). Here's some code so you'll understand my problem:
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (x >= 10 && x < 42 && y >= 10 && y < 42) {
image = barracks; //barracks is a predefined image, created in the constructor
dragBuilding = true;
PixelMain.pixelMain.repaint(); //pixelMain is an instance of the JFrame subclass
}
}
//irrelevant code, e.g mouseMoved, ...
public void mouseDragged(MouseEvent e) {
if (dragBuilding) {
//System.out.println("GPanel mouseDragged");
PixelMain.pixelMain.repaint();
}
}
the JFrame subclass only contains the constructor and the following code:
public void paint(Graphics g) { //i would have used paintComponent, but it seems like JFrame does not have this method ...?
super.paint(g);
if (PixelMain.panelOffense.getDragBuilding()) { //panelOffense is an instance of the JPanel subclass, getDragBuilding returns a boolean that depends on whether the mouse is held down at the moment
Graphics2D g2 = (Graphics2D) g;
Rectangle2D tr = new Rectangle2D.Double((int)getMousePosition().getX(), (int)getMousePosition().getY(), 16, 16); //size of the texture
TexturePaint tp = new TexturePaint(PixelMain.panelOffense.getImg(), tr);
g2.setPaint(tp);
Rectangle2D r = (Rectangle2D) new Rectangle((int)getMousePosition().getX(), (int)getMousePosition().getY(), 16, 16); //area to fill with texture
g2.fill(r);
System.out.println("test");
}
}
Before you ask - I did move some code to other classes so it's called less often, but that's not the problem. Even if the paint method only draws a rectangle (directly on Graphics g, not Graphics2D), the rectangle flickers.
If anyone could help me figure out a solution, I'd be very thankful!
Note: I know it's probably not very elegant to draw on a JFrame or a subclass of JFrame, but I personally don't know an alternative.
Note 2: According to google/stackoverflow results or threads that I read, I should use a JPanel, which seems to be double-buffered (whatever that is, I didn't really understand that. but then again, it's almost 11 pm here). Hence, I could probably move all my components to a JPanel to solve the issue, but I wanted to try to solve the problem without doing that.
Note 3: Yes, the code belongs to a (strategy) game I'm writing, but considering that the problem is not really related to game development exclusively, I decided to post it here and not at game development stack exchange.

Create Methods to Draw Rectangle and Circle in JFrame?

I was assigned this problem without any teaching on how to do it and I can't figure it out on my own. I've started, but I can't figure out what methods to add.
Below is the main method of a program which paints a circle and a square at the given coordinates. Your job is to write the rest of the code, BUT THE MAIN METHOD CANNOT BE ALTERED!!! You can add methods to the main driver class but you CANNOT add anything to the main method below.
public static void main (String[] args){
JFrame picture = new JFrame("Circle and Square");
picture.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
picture.getContentPane().add(new Drawing(200, 50,100, 150));
picture.pack();
picture.setVisible(true);
}
The first two numbers are the height and width where the rectange should start and the second two numbers are the height and width where the circle should start.
//The following is my failure attempt, so at least you know I tried
to figure something out.
import javax.swing.*;
import java.awt.*;
public class Drawing extends JFrame
{
int a, b, c, d;
public Drawing(int x, int y, int z, int yeah)
{
setSize(400, 400);
a = x;
b = y;
c = z;
d = yeah;
}
public void paint(Graphics g)
{
super.paint(g);
g.drawRect(a, b, c, d);
g.drawOval(c, d, a, b);
}
public getContentPane()
{
}
//Can't change following class:
public static void main (String[] args)
{
JFrame picture = new JFrame("Circle and Square");
picture.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
picture.getContentPane().add(new Drawing(200, 50, 100, 150));
picture.pack();
picture.setVisible(true);
}
}
I know I have to create something called a panel, but I don't even really understand how to do that. I'm sure I could reverse engineer any code anyone here shows me on how to solve my assignment. Thanks.
getContentPane is a method of JFrame, you won't need to implement it.
Drawing doesn't need to extend from JFrame, it should extend from JPanel.
Don't call setSize it will do nothing. You need to override getPreferredSize and return the preferred size you want to use.
Don't override paint, you should be using paintComponent, points for calling super.paint though. But when you move the custom painting to paintComponent, call super.paintComponent instead.
Take a look at:
- Creating a GUI With JFC/Swing
- Performing Custom Painting
- 2D Graphics
Make notes in your documentation or code that the main method is wrong and should taking into consideration Initial Threads

How to call draw method outside paintComponent

I have an assignment where I have to draw a circle in a panel and with that circle calculate the reaction time of the user when the circle changes size or color. I've got the paintComponent method. But now I have to call the method for the circles in another class and I don't know how to do that. Can someone please help me with this?
Here is my class where paintComponent is written:
public class ReactionPanel extends JPanel {
boolean setSmallCircle, setInitialCircle;
Color color = new Color (255,0,0); //color = red
Color c = new Color (255,255,0); //color = yellow
int size;
int x = 250;
int y = x;
public void paintComponent(Graphics g){
super.paintComponent(g);
if (setInitialCircle){
size = 50;
}
if (setSmallCircle) {
size = 50;
}
else {
size = 150;
}
g.drawOval(x,y,size,size);
g.fillOval(x,y,size,size);
}
void setInitialCircle(Graphics g, Color color){
g.setColor(color);
}
void setSmallCircle(Graphics g, Color c){
g.setColor(c);
}
void setBigCircle(Graphics g, Color c){
g.setColor(c);
}
}
Now I would need those (setInitialCircle etc) and call them in my main class ReactionExperiment like so:
void startTest(){
//draw red circle
}
How do I do this?
Thanks for the help!
I believe you want this ?
ReactionPanel reactionPanel = new ReactionPanel();
reactionPanel.setSmallCircle(x, x);
What this code does it instantiates ReactionPanel (it makes a new instance of it). As such you can then use its methods in another class.
I assume you have two classes, and you'd like to call a public function defined in one from the other. Since the method is not a static method, you'd have to instantiate an object for the class like -
ReactionPanel obj = new ReactionPanel();
then using this object, you can call any method defined in the first class, like
obj.paintComponent(g); // you'll have to define g first though

paint() in java applet is called twice for no reason

Is there a common reason why the paint() method may be called twice without being intended. I have the following code:
public void paint(Graphics g)
{
//Graphics2D gg;
//gg=(Graphics2D) g;
drawMatrix(g);
}
private void drawMatrix(Graphics g) {
int side = 40;
hex hexagon=new hex();
for(int i = 0; i<9; i++)
for(int k = 0; k<9; k++){
g.setColor(Color.lightGray);
g.fill3DRect(i*side,k*side, side, side, true);
if (matrix[i][k]!=null){System.out.println("i is "+i+" k is "+k);
g.setColor(Color.black);hexagon.DrawHexfromMatrix(g, i, k, Color.black);}
}
}
hex is a class that extends polygon (to model a hexagon figure), and the DrawHexfromMatrix is a function that draws a hexagon from the index of the matrix that is drawn(put the hexagon in the slot of a matrix). I can provide the whole code if you think it helps, but for now i don't understand why the system.out.println is executed twice.( for example if[1][2] and [2][3] are not null it will print:
i is 1 k is 2
i is 2 k is 3
i is 1 k is 2
i is 2 k is 3
I think this also affects my drawing because sometimes although an element exists at [i][k] is isn't drawn.(matrix is a matrix of hex).
Later edit: Is it possible somehow that g.fill3DRect(i*side,k*side, side, side, true); to overpaint the hexagons i'm trying to paint with hexagon.DrawHexfromMatrix(g, i, k, Color.black);???
First of all, you should not paint directly to a JApplet.
You should define a JPanel that is added to the JApplet. You paint to the JPanel.
Second, you should use the paintComponent() method, and call the super class behavior, like this.
protected void paintComponent(Graphics g) {
// Paint the default look.
super.paintComponent(g);
// Your custom painting here.
g.drawImage(foregroundImage, x, y, this);
}
Third, you have no control over when Swing fires the paintComponent() method. You should do the calculations in some other method, and limit the code in paintComponent() to actual drawing methods.

Categories

Resources