I'm creating a small game, you click buttons (up, down, left and right) to control a cat (represented by a rectangle) to chase a mouse (represented by another rectangle). Lame I know... anyway I'm using the mvc design pattern and I am having problems calling the repaint method from button listeners in the controller on the panel where the two rectangles are to be 'painted'. They paint successfully the first time but not any further time.
I've implemented the the paintComponent() method in two ways but both didn't work
Create a separate class that extends JPanel and does the paintComponent business, creating a new object of that class in the view and using it to paint the rectangles.
Creating a JPanel and writing the paintComponent stuff in the parenthesis of the new JPanel object.
and I've implemented the code to in the controller to repaint in two ways and both didn't work
Call a method from the view that returns the jpanel that uses the paintComponent method and calling repaint on it.
Creating a jpanel in the controller and assigning the panel from the view to it then calling repaint on that.
The code for the view and controller (which is long, sorry!) is below, it also includes the commented out stuff I couldn't get to work from the two methods to approaching the problem mentioned before...
View
/*
* gameView.java
*/
package game;
import java.awt.;
import java.awt.event.;
import javax.swing.*;
public class gameView extends JFrame{
//components
private JButton up = new JButton("Up");
private JButton down = new JButton("Down");
private JButton left = new JButton("Left");
private JButton right = new JButton("Right");
//panels
private JPanel content = new JPanel();
//boardPanel leftPanel = new boardPanel();
private Stroke drawingStroke = new BasicStroke(1);
private JPanel leftPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
myPaint(g);
}
};
private JPanel rightPanel = new JPanel();
//model
private gameModel model;
//mouse and cat
private Rectangle cat;
private Rectangle mouse;
public void myPaint(Graphics g){
Graphics2D g1 = (Graphics2D)g;
Graphics2D g2 = (Graphics2D)g;
g1.setStroke(drawingStroke);
g1.draw(cat);
g1.setPaint(Color.yellow);
g1.fill(cat);
g2.setStroke(drawingStroke);
g2.draw(mouse);
g2.setPaint(Color.red);
g2.fill(mouse);
}
//constructor
public gameView(gameModel _model){
model = _model;
//cat and mouse
cat = new Rectangle(_model.getCatX(), _model.getCatY(), 10, 10);
mouse = new Rectangle(_model.getMouseX(), _model.getMouseY(), 10, 10);
//layout
content.setSize(500, 400);
content.setLayout(new GridLayout(0,2));
leftPanel.setSize(200, 200);
leftPanel.setBackground(Color.blue);
rightPanel.setSize(100, 400);
rightPanel.setLayout(new FlowLayout());
rightPanel.add(new JLabel("Controls"));
rightPanel.add(up);
rightPanel.add(down);
rightPanel.add(left);
rightPanel.add(right);
content.add(leftPanel);
content.add(rightPanel);
this.setSize(500, 400);
this.setContentPane(content);
this.setTitle("Cat & Mouse Game");
}
//returns the leftPanel to repaint in the controller
public JPanel getLeft(){
return leftPanel;
}
//listeners for buttons
public void addUpListener(ActionListener moveUp){
up.addActionListener(moveUp);
}
public void addDownListener(ActionListener moveDown){
down.addActionListener(moveDown);
}
public void addLeftListener(ActionListener moveLeft){
left.addActionListener(moveLeft);
}
public void addRightListener(ActionListener moveRight){
right.addActionListener(moveRight);
}
public void addCloseListener(WindowListener close){
this.addWindowListener(close);
}
//
public Rectangle getCat(){
return cat;
}
public Rectangle getMouse(){
return mouse;
}
//left side board panel
/*class boardPanel extends JPanel{
Stroke drawingStroke = new BasicStroke(1);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g1 = (Graphics2D)g;
g1.setStroke(drawingStroke);
g1.draw(cat);
g1.setPaint(Color.yellow);
g1.fill(cat);
Graphics2D g2 = (Graphics2D)g;
g2.setStroke(drawingStroke);
g2.draw(mouse);
g2.setPaint(Color.red);
g2.fill(mouse);
}
}
public JPanel getLeft(){
return leftPanel;
}*/
}
Controller
/*
* gameController.java
*/
package game;
import java.awt.event.;
import javax.swing.;
public class gameController {
private gameModel model;
private gameView view;
private JPanel lp = new JPanel();
public gameController(gameModel _model, gameView _view){
model = _model;
view = _view;
lp=_view.getLeft();
//listeners
view.addUpListener(new UpListener());
view.addDownListener(new DownListener());
view.addLeftListener(new LeftListener());
view.addRightListener(new RightListener());
view.addCloseListener(
new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
}
//DOWN
class DownListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()+10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
//LEFT
class LeftListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()-10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
//RIGHT
class RightListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()+10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
}
Looks like your button listeners update the model, but nothing actually updates the coordinates of the cat and mouse rectangles. They get their initial bounds from the model, but then are never updated.
The view should probably listen to the model to sync the cat and mouse's locations to the actual Rectangle objects.
Related
I am working on a simple object drawing program using Swing in Java.
My program simply should draw shapes according to buttons when clicked, and move any shapes with the mouse. I have four buttons which draw rectangle, circle and square on screen. So far I did managed to draw to shapes when you click on buttons. but i want to move the shapes on screen which it did not work out.
The problem is this: When I click on circle shape to drag it around with mouse, it clears all the screen and noting is on the screen.
And, is there a way to clean all the screen when I click on clear button?
Thank you?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintProject extends JComponent implements ActionListener,
MouseMotionListener {
private int CircleX=0;
private int CircleY=0;
private int RectX=100;
private int RectY=100;
private int SquareX=300;
private int SquareY=200;
public static void main(String[] args) {
JFrame frame = new JFrame("NEW PAINT PROGRAME!");
JButton CircleButton = new JButton("Circle");
CircleButton.setActionCommand("Circle");
JButton RectangleButton = new JButton("Rectangle");
RectangleButton.setActionCommand("Rectangle");
JButton SquareButton = new JButton("Square");
SquareButton.setActionCommand("Square");
PaintProject paint = new PaintProject();
CircleButton.addActionListener(paint);
RectangleButton.addActionListener(paint);
SquareButton.addActionListener(paint);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(paint);
frame.add(CircleButton);
frame.add(RectangleButton);
frame.add(SquareButton);
frame.addMouseMotionListener(paint);
frame.pack();
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
private void drawCircle() {
Graphics g = this.getGraphics();
g.setColor(Color.red);
g.fillOval(CircleX, CircleY, 100, 100);
}
private void drawRectangle() {
Graphics g = this.getGraphics();
g.setColor(Color.green);
g.fillRect(RectX, RectY, 100, 300);
}
private void drawSquare() {
Graphics g = this.getGraphics();
g.setColor(Color.blue);
g.fillRect(SquareX, SquareY, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Circle")) {
drawCircle();
}
else if (command.equals("Rectangle")) {
drawRectangle();
}
else if (command.equals("Square")) {
drawSquare();
}
}
#Override
public void mouseDragged(MouseEvent e) {
CircleX=e.getX();
CircleY=e.getY();
repaint();
}
}
As noted here and here, getGraphics() is not how to perform custom painting in Swing. Instead, override paintComponent() to render the desired content. It looks like you want to drag shapes using the mouse. A basic approach to moving a selected object is shown here; substitute your fillXxx() invocation for the drawString() shown there. For multiple shapes, use a List<Shape>; the clear command then becomes simply List::clear. A complete example is cited here; it features moveable, selectable, resizable, colored nodes connected by edges.
I'm making a GUI application which finds and draws convex hull for a set of points.
Here's the frame:
public class Frame extends JFrame{
Panel panel = new Panel();
JButton drawHull = new JButton("Draw Convex Hull");
Frame(String title) {
super(title);
// setLayout
setLayout(new BorderLayout());
// add components to the frame
add(panel, BorderLayout.CENTER);
add(drawHull, BorderLayout.SOUTH);
// add actionListener for drawHull button
drawHull.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
panel.drawConvexHull();
}
}
);
}
}
The frame contains a button (at the bottom of the frame) and a Panel object.
Here's the Panel class:
public class Panel extends JPanel{
ArrayList<Point> points = new ArrayList<Point>();
public Panel() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
points.add(new Point(e.getX(), e.getY()));
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
if(!points.isEmpty()) {
Point p = points.get(points.size()-1);
g.fillOval(p.x-2, p.y-2, 4, 4);
}
}
public void drawConvexHull() {
// code for finding convex hull
}
}
I have added a mouseListener to the Panel class so that when the user clicks anywhere on the panel, a point is drawn.
When I run the code, everything looks fine. Here's a sample run.
Now here's the problem:
As soon as I click the panel, this happens
A button appears on the top of the frame. Why is this happening?
One more thing. When I click this button on the top, a point is drawn. Here, have a look:
Without calling super.paintComponent(g) in paintComponent the background is not repainted leading to unpredictable results on the panel component.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point: points) {
g.fillOval(point.x - 2, point.y - 2, 4, 4);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CirclePanel extends JPanel {
private JTextField xField, yField, diameterField;
private JButton Redraw;
private JLabel xLabel, yLabel, rLabel;
Circle myCircle = new Circle (150, 150, 30, Color.red, Color.white);
Graphics g;
//Paint objects on panel
public void paintComponent (Graphics page) {
super.paintComponent(page);
g = page;
myCircle.draw(g);
}
public CirclePanel(){
xLabel = new JLabel("X= ");
yLabel = new JLabel("Y= ");
rLabel = new JLabel("R= ");
xField = new JTextField(5);
xField.addActionListener(new TempListener());
yField = new JTextField(5);
yField.addActionListener(new TempListener());
diameterField = new JTextField(5);
diameterField.addActionListener(new TempListener());
Redraw = new JButton("Redraw!");
Redraw.addActionListener(new ButtonListener());
add(xLabel);
add(xField);
add(yLabel);
add(yField);
add(rLabel);
add(diameterField);
add(Redraw);
setPreferredSize(new Dimension(500, 500));
setBackground(Color.white);
}
private class ButtonListener implements ActionListener{
public void actionPerformed (ActionEvent event) {
//Update page
myCircle.draw(g);
//repaint panel
repaint();
}
private class TempListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int x, y, newbase, newhei;
String text = xField.getText();
String text2 = yField.getText();
x = Integer.parseInt (text);
y = Integer.parseInt (text2);
myCircle.draw(g);
repaint();
}
}
}
}
Hi guys I'm tring to make java application that draw a circle and redraw it with the new values that are in JTextField. I wrote three class for it. One of them is contain accessor, mutators, constructor. one of the class has the main method of course and a one of the class is above. But TempListener not working. Can you help me?
You should get the Graphics field, g, out of your program. Instead use the local Graphics variable, the one you call page inside of your paintComponent method, but don't use it anywhere else.
Suggestions:
Have your ActionListener make changes to the state of the myCircle object, your code does not do this.
Then have it call repaint().
Get this, myCircle.draw(g); out of your ActionListener as it doesn't belong there.
Read the Swing graphics tutorials: Lesson: Performing Custom Painting
Am new to Java GUI Games, therefore, question might be trivial. Am trying to make a foosball game of sort.
I have been trying to add Ball JComp on top of my FoosballTable Jcomp.
There are two table settings.
What it does is, adds Ball Component to bottom of the Table.
I change the table setting and ball is visible. Otherwise not.
How do I add ball to the top? I have been trying to search online to no avail.
Thank you.
Edit 1
The ball class has overridden paintComponent method. and Frame class has various panels. one panel is the Start button i.e supposed to display the ball
....
jp7.add(Start);
final Ball b = new Ball();
Start.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
JPanel contentball = (JPanel) getContentPane();
contentball.add(b);
contentball.revalidate();
contentball.repaint();
}
});
playersOnString.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
JPanel contentgr = (JPanel) getContentPane();
if(e.getItem() == "[1] [2] [4] [4]"){
System.out.println("First choice");
remove(ground2);
contentgr.add(ground1);
}
else if(e.getItem()== "[1] [2] [5] [3]"){
System.out.println("Second choice");
remove(ground1);
contentgr.add(ground2);
}
contentgr.repaint();
setVisible(true);
}
});
public class Ball extends JComponent{
/**
*
*/
private static final long serialVersionUID = 1L;
private static Ball ball;
int xAxisSpeed , yAxisSpeed;
Team lastContactTeam;
private int size = 15;
public Dimension getPreferredSize()
{
return (new Dimension(100, 500));
}
public static Ball getInstance(){
Random r = new Random();
if(ball == null){
ball = new Ball();
ball.xAxisSpeed = r.nextInt(10)+1;
ball.yAxisSpeed = r.nextInt(10)+0;
}
return ball;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(190, 355, size, size);
setVisible(true);
}
}
Edit 2
I wish to add ball to the top of the Table that already exists. (a rectangle drawn with PaintComponent method on a panel)
I need to pass a JPanel extending class to the main class.
Here is what I have so far:
Main class
import java.awt.Color;
import javax.swing.*;
public class main {
private gamePanel gamepanel = new gamePanel();
public JPanel createContentPane(){
// We create a bottom JPanel to place everything on.
JPanel totalGUI = new JPanel();
//We set the Layout Manager to null so we can manually place
// the Panels.
totalGUI.setLayout(null);
//Now we create a new panel and add it to the bottom JPanel.
totalGUI.add(gamepanel);
totalGUI.setOpaque(true);
return totalGUI;
}
private static void createAndShowGUI(){
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] There's a JPanel in here! [=]");
//Create and set up the content pane.
main demo = new main();
frame.setContentPane(demo.createContentPane());
//The other bits and pieces that make your program a bit more stable.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,500);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a jog for the event-dispatching thread:
//creating and showing this application's GUI.
System.out.println(gamepanel);
SwingUtilities.invokeLater(new Runnable() {
public void run(){
createAndShowGUI();
}
});
}
}
The gamePanel class
public class gamePanel extends JPanel implements Commons {
private Dimension d;
private ArrayList snowmens;
private coreFunctions functions = new coreFunctions();
private int snowmenX = 150;
private int snowmenY = 5;
private final String snowmenpix = "snowman.png";
private JPanel background;
public gamePanel() {
add(new JLabel("TEST"));
setFocusable(true);
setDoubleBuffered(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 700, 700);
}
}
I can't figure out why the blue background and the label is not being shown...
EDIT:
Here are more details:
Ok so I am trying to make a little 2D game. For that I need to create some snowmen on the gamePanel class and display it via the main class. To start it off, the createContentPane creates a background panel, the root panel if you want. The createandshowgui creates a JFrame.
The gamepanel class is in fact a JPanel which has 1 panel as of now, which is the background panel. For now, I only want it to have a blue background.
I tried putting it like this because I saw some examples and they were pretty similar to what I have, but for some reason, I can't get it to work....
Thank you,
Ara
You should use LayoutManager instead of setLayout(null); and if only one component is being added no need for it either (that component will stretch to fill unless others are added)
see here for tutorial on LayoutManagers:
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
If all you are trying to do is have a blue background (on which you can add components) then simply override paintComponent() of your gamePanel and paint the background blue:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
then you can add your JLabel as if it was a normal Panel as the background is now being painted blue and not set by/as a component.
If you have an image look into g.drawImage(Image image,int x,int y,ImageObserver iO)
EDIT
DROP THE CALL TO:
setLayout(null);
and it will work