Code works, my bad. But I'm still open to suggestions on how to improve or make the code more elegant.
I have created this layout and I want to be able to draw a circle whenever the user clicks on the white area.
Couldn't post an image, so here is the link
The white area is basically a rectangle. But something with my code isn't working, it just doesn't respond to mouse clicks. When I tried to see if it responds to mouseDragged it worked perfectly but this isn't what I need.
Here is my code, some "tests" are put as /comments/ but neither of them work as intended.
I would be very grateful for help. Here is my code:
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
public class CitiesMapPanel extends JPanel implements MouseListener {
private JButton cmdAddWay, cmdFindPath, cmdClearMap, cmdClearPath;
private JLabel lblFrom, lblTo;
private JTextField txtFrom, txtTo;
public CitiesMapPanel() {
cmdAddWay = new JButton("Add Way");
cmdFindPath = new JButton("Find Path");
cmdClearMap = new JButton("Clear Map");
cmdClearPath = new JButton("Clear Path");
lblFrom = new JLabel("From");
lblTo = new JLabel("To");
txtFrom = new JTextField(6);
txtTo = new JTextField(6);
this.addMouseListener(this);
setLayout(new BorderLayout());
add(buildGui(), BorderLayout.SOUTH);
}
private JPanel buildGui() {
JPanel buttonsBar = new JPanel();
//The "south" of the BorderLayout consist of a (2,4) GridLayout.
buttonsBar.setLayout(new GridLayout(2,4));
buttonsBar.add(lblFrom);
buttonsBar. add(txtFrom);
buttonsBar.add(lblTo);
buttonsBar.add(txtTo);
buttonsBar.add(cmdAddWay);
buttonsBar.add(cmdFindPath);
buttonsBar.add(cmdClearMap);
buttonsBar.add(cmdClearPath);
return buttonsBar;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, this.getSize().height, this.getSize().width);
}
public static void main(String[] args) {
JFrame frame = new JFrame("layout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(530, 550);
CitiesMapPanel gui = new CitiesMapPanel();
frame.add(gui);
frame.setVisible(true);
}
/*abstract private class MyMouseListner implements MouseListener{
public void mouseClicked(MouseEvent e){
int x = e.getX();
int y = e.getY();
Graphics g = getGraphics();
g.setColor(Color.black);
g.fillOval(x,y,15,15);
}
}*/
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
Graphics g = getGraphics();
g.setColor(Color.black);
g.fillOval(x,y,15,15);
System.out.println("test");
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
The click listener is not the problem. Your approach to painting is simply wrong. You can't do a getGraphic, paint on it, and expect the result to be presented. In Swing (AWT) things work fundamentally different. You need to either create an off screen image that you paint to and that you then present on screen in your paintComponent method, or you need to track the objects you want to paint in a data structure and paint those in your paintComponent method. You can trigger a repaint in your click listener by calling repaint so the UI subsystems knows about the changed state that requires a repaint of your component.
Read more about the basics in the Swing painting tutorial.
Related
This question already has answers here:
Implementing back/forward buttons in Swing
(3 answers)
Closed 4 years ago.
I am building a menu for my java game and i need to be able to switch to my game JPanel when i click a button. Here is what i have
public class Menu extends JPanel implements ActionListener {
protected JFrame frame;
JButton btnStart = new JButton();
public Menu(JFrame j) {
super();
frame = j;
//creating and styling button
btnStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
StartGame();
}
});
}
private void StartGame(){
frame.getContentPane().removeAll();
frame.getContentPane().add(new Main(frame));
frame.repaint();
}
`
public class Main extends Universe implements ActionListener {
Timer timer = new Timer(75, this);
JFrame frame;
//#Override
public void actionPerformed(ActionEvent e) {
repaint();;
if(isLoss()){
timer.stop();
}
//update cretures
}
public Main(JFrame frame) {
super();
frame.setLayout(null);
frame.setLayout(null);
//frame.getContentPane().setLayout(null);
this.setBackground(Color.BLACK);
this.map = new Map();
StartUpHeight = 100;
this.Size = 30;
//this.playerCol = new Collision(map, pacman, Size);
pacman = new Player(1*Size, 4*Size, Size / 5, map, this.Size);
red = new RedGhost(9*Size, 8*Size, Size / 6, map, pacman, this.Size);
pinky = new PinkGhost(8*Size, 10*Size, Size / 6, map, pacman, this.Size);
inky = new BlueGhost(9*Size, 10*Size, Size / 6, map, pacman, this.Size, red);
clyde = new YellowGhost(10*Size, 10*Size, Size/6, map, pacman, this.Size);
timer.start();
this.frame = frame;
this.frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
pacman.keyPressed(e, Size);
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
pacman.keyReleased(e);
}
});
setUpPanel();
}
#Override
public void paint(Graphics g) {
//drawing map
//drawing pacman
//drawing ghosts
}
`
I tried everything i found on the internet so far. Main extends from jpanel and implements action listener just like Menu. After this code is executed my jframe just clears. I tried to repaint it did not help. Any help is appreciated. Thanks
When you call repaint() method you should also call revalidate() method.
Also, can you show your Main class code?
And have you added your button to your frame?
I'm making a small java game for fun to practice with my GUI programming. I want to have the center of my content pane's borderLayout be an image, and I would like to put "invisible" buttons on top of the image in specific places (to be placed later, I just want to get one working for now). My issue is getting the button to actually be invisible, it seems to leave a white square where it is now. I looked around but the only things that seem to be suggested were the .setOpaque, .setContentAreaFilled, and .setBorderPainted. (game is space related, explains the names)
galaxyButton1 = new JButton();
galaxyButton1.setFont(starSystem);
galaxyButton1.setBorder(BorderFactory.createEmptyBorder(25,25,25,25) );
galaxyButton1.setOpaque(false);
galaxyButton1.setContentAreaFilled(false);
galaxyButton1.setBorderPainted(false);
Color invis = new Color(Color.TRANSLUCENT);
galaxyButton1.setForeground(invis);
galaxyButton1.setBackground(invis);
galaxyButton1.addActionListener( new ButtonHandler() );
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout());
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout( 1,0,5,5 ) );
buttons.setOpaque(false);
buttons.add(galaxyButton1);
centerPanel.add(buttons,BorderLayout.CENTER);
centerImg.setLayout(new GridBagLayout());
centerImg.add(centerPanel);
contentPane.add(centerImg, BorderLayout.CENTER);
Here is a code outline of how to make your own button. You will need to set up a the actual mouse in some other class.
public class InvisibleButton implements MouseListener{
private final Rectangle rectangle;
public InvisibleButton(int x, int y, int width, int height){
rectangle = new Rectangle(x,y,width,height);
}
#Override
public void mouseClicked(MouseEvent e) {
int x = 0; // Set this to Mouse X
int y = 0; // Set this to Mouse Y
if(rectangle.contains(x,y)){
//Set Something to True or do action here
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
I am currently developing a game in java.When I start my game I get to chose between Full Screen and Window Mode, by clicking somewhere in the frame.The Window Mode works perfectly, but I have some issues at the full screen mode.So if I have in my main() just a simple initialization of the game, like new FullscreenMode(), the game works perfect, the listeners are working.In the code bellow if I launch the full screen Mode frame from the constructor it works perfect, but if I launch it from a function that belongs to my class, all the listeners won't work...And when I say it's not working properly, I mean the listeners are not responding, everywhere I click I get no response from the game, but if the full screen Mode Frame is launched from the constructor everything works perfectly.Thank you in advance!
public class ResolutionChoser extends JFrame implements MouseMotionListener,
MouseListener {
private static final long serialVersionUID = 1L;
private BufferedImageLoader loader;
private BufferedImage rezImg = null;
public ResolutionChoser() {
super("Welcome!");
requestFocus();
loader = new BufferedImageLoader();
rezImg = loader.loadImage("/RezImg.png");
this.setPreferredSize(new Dimension(Game.WIDTH * Game.SCALE + 2,
Game.HEIGHT * Game.SCALE + 2));
this.setMaximumSize(new Dimension(Game.WIDTH * Game.SCALE + 2,
Game.HEIGHT * Game.SCALE + 2));
this.setMinimumSize(new Dimension(Game.WIDTH * Game.SCALE + 2,
Game.HEIGHT * Game.SCALE + 2));
this.pack();
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setVisible(true);
addMouseMotionListener(this);
addMouseListener(this);
JLabel jl = new JLabel() {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g) {
g.drawImage(rezImg, 0, 0, null);
}
};
setContentPane(jl);
//Works Perfectly if I do it like so
// launchFullScreen();
}
//Method that launches my fullscreen game
public void launchFullScreen() {
removeMouseMotionListener(this);
removeMouseListener(this);
MultiBufferTest.main(null);
}
public static void main(String[] args) {
ResolutionChoser rc = new ResolutionChoser();
}
#Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("CLICKED AT: " + arg0.getX() + "--" + arg0.getY());
launchFullScreen();
//not working properly, the listeners for my game aren't responding
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
Well, you are removing the listeners in your launchFullScreen() method:
public void launchFullScreen() {
removeMouseMotionListener(this);
removeMouseListener(this);
MultiBufferTest.main(null);
}
How do you expect the listeners to respond?
Don't attach Mouseisteners directly to a frame, there is a JRootPane and content pane (and possibly a glass pane) between the frame the user, any one of theses could be stealing mouse events, which will prevent your frame from receiving mouse events.
Instead, attach the MouseListener to the top level component directly
Also...
JLabel jl = new JLabel() {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g) {
g.drawImage(rezImg, 0, 0, null);
}
};
this is not only a bad idea (you've broken the paint chain), it's also not required, as JLabel is capable of displaying images.
See Painting in AWT and Swing,
Performing Custom Painting and
How to Use Labels for more details
I'm trying to make a code that will move a red ball with JButtons (and later add keybinders). There are no problems when I compile and when I run I see the ball but the JButtons won't affect him. I think the problem might be that the ball is drawed only once and then is called again and again without being drawed in the new position but I don't know how to fix that.
1) does anybody know how I can fix that?
2) is there a way to change the shape of a JPanel to a ball? (that would probably be a simpler way to move him)
package il.co.atlantis;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class KeyBinders implements ActionListener {
boolean right=true, left=false, up=false, down=false, inGame=true;
JPanel backgroundPanel, bannerPanel, scorePanel, applePanel;
JLabel currentScoreLabel, highestScoreLabel;
JButton upButton, downButton, rightButton, leftButton;
long millis =System.currentTimeMillis(), millisn =System.currentTimeMillis();
public static final int WID = 10, HEI = 10;
public static int x1 = 100, y1 = 100;
public class MyGraphics extends JComponent {
private static final long serialVersionUID = 1L;
MyGraphics() {
setPreferredSize(new Dimension(700, 500));
}
public void moveRight(){
++x1;
}
public void moveLeft(){
--x1;
}
public void moveUp(){
--y1;
}
public void moveDown(){
++y1;
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.red);
g.fillOval(x1, y1, WID, HEI);
}
}
public JPanel CreateContentPane (){
JPanel totalGUI = new JPanel();
totalGUI.setLayout(null);
backgroundPanel = new JPanel();
backgroundPanel.setBackground(Color.black);
backgroundPanel.setLocation(100, 10);
backgroundPanel.setSize(700, 500);
totalGUI.add(backgroundPanel);
upButton = new JButton("up");
upButton.setLocation(0,0);
upButton.setSize(50,50);
totalGUI.add(upButton);
downButton = new JButton ("down");
downButton.setLocation(0,50);
downButton.setSize(50,50);
totalGUI.add(downButton);
rightButton = new JButton("right");
rightButton.setLocation(0,100);
rightButton.setSize(50,50);
totalGUI.add(rightButton);
leftButton = new JButton("left");
leftButton.setLocation(0,150);
leftButton.setSize(50,50);
totalGUI.add(leftButton);
MyGraphics tr = new MyGraphics();
tr.setLocation(100, 100);
backgroundPanel.add(tr);
return totalGUI;
}
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
}
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] JButton Scores! [=]");
//Create and set up the content pane.
KeyBinders demo = new KeyBinders();
frame.setContentPane(demo.CreateContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(280, 190);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public KeyBinders() {
// TODO Auto-generated constructor stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
When you invoke action event, actionPerformed() function gets called, as you did. You have change the drawing position too. you need to call Component.repaint() which tells Swing t hat the entire component, whichever one you specified to be repainted , must be updated . So add this function calling in your code. For example:
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
repaint();
}
Check the tutorial: Performing Custom Painting.
There's a method called repaint() you should familiarize yourself with.
When called on a component (such as a JFrame) it'll repaint all the components within. Naturally you need to call it if you want your changes to become visible on the screen.
As for custom painting, you shouldn't use a Component at all, rather use the Graphics.fillRect/fillOval etc. methods to just draw what you want.
See here for the custom painting tutorial.
Hi I want to make my JPanel disappear so I wrote these lines of code
removeAll();
updateUI();
revalidate();
That only made the JComponents and JButtons disappear. I would like to make the images that I have displayed with the paint method disappear also. If I do setVisible(false), then I cannot add another JPanel behind it.
This is my class:
package screens;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class menuScreen extends JPanel implements MouseListener{
private static final long serialVersionUID = 1L;
//-------------VARIABLES---------------//
Image wallpaper = (Image)Toolkit.getDefaultToolkit().getImage(getClass().getResource("images/wallpaper.jpg"));
Image title_text = (Image)Toolkit.getDefaultToolkit().getImage(getClass().getResource("images/title-text.png"));
ImageIcon startGameimg = new ImageIcon(Toolkit.getDefaultToolkit().getImage(getClass().getResource("images/startGame.png")));
ImageIcon optionsimg = new ImageIcon(Toolkit.getDefaultToolkit().getImage(getClass().getResource("images/options.png")));
//JButton start = new JButton(basketball);
JLabel options = new JLabel(optionsimg);
JLabel startGame = new JLabel(startGameimg);
gameScreen gS = new gameScreen();
CardLayout scenechange = new CardLayout();
JPanel scenechange1 = new JPanel (scenechange);
//-------------PAINT FUNCTION----------//
public void paintComponent(Graphics g){
g.drawImage(wallpaper,0,0,this);
g.drawImage(title_text,0,0,this);
//g.drawImage(basketball1,110,180,this);
}
//-------------CONSTRUCTOR-------------//
public menuScreen(){
scenechange.addLayoutComponent(this,"menuScreen");
scenechange.addLayoutComponent(gS,"gameScreen");
//scenechange.show(this,"menuScreen");
this.setLayout(null);
this.add(options);
this.add(startGame);
startGame.setBounds(110,180,110,110);
options.setBounds(110,300,110,110);
startGame.addMouseListener(this);
options.addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
if(e.getSource() == (startGame)){
removeAll();
revalidate();
add(gS);
}
if(e.getSource() == (options)){
setVisible(false);
}
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}//END OF CLASS startingScreen
Thanks in advance.
First, don't call updateUI, it's related to the Look and Feel and not (directly) to updating your components.
If you have provided a custom paint routine within in your panel, then you need away to stop it from painting the images (without preventing it from painting it's own content). removeXxx will remove child components that you have previously added to the container.
A little more code would be useful
UPDATE
Fisrt, the images your painting aren't components of you container, they are been "stamped", you need some way to tell the component not to the paint the images
public void paintComponent(Graphics g){
super.paintComponent(g); // this is super important
if (paintImages){ // you need to define and set this flag
g.drawImage(wallpaper,0,0,this);
g.drawImage(title_text,0,0,this);
}
}
Now, this will stop the images from been painted.
If, however, you no longer want to use the component (ie, you want to remove it from the screen so you can place a new component on the screen in its place), you need to remove this component from it's parent, which Code-Guru has suggested (so I won't steal his answer ;))
UPDATE
Okay, you had a kernel of an idea but either didn't quite know how to implement it or decided to discard it.
Basically, from the looks of your code, you were either trying to, or had, implement a CardLayout, unfortunately, you kind of got the wrong idea with it.
With CardLayout, you need to "controller", a component that is responsible for switching the screens...
public class ScreenController extends JPanel {
private static final long serialVersionUID = 1L;
//-------------VARIABLES---------------//
MenuScreen ms = new MenuScreen();
GameScreen gs = new GameScreen();
CardLayout sceneChange;
//-------------CONSTRUCTOR-------------//
public ScreenController() {
sceneChange = new CardLayout();
this.setLayout(sceneChange);
add(ms, "menuScreen");
add(gs, "gameScreen");
sceneChange.show(this, "menuScreen");
ms.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equalsIgnoreCase("startgame")) {
sceneChange.show(ScreenController.this, "gameScreen");
}
}
});
}
}//END OF CLASS startingScreen
Then you have your menu and game screens...
public class MenuScreen extends JPanel implements MouseListener {
private static final long serialVersionUID = 1L;
//-------------VARIABLES---------------//
//JButton start = new JButton(basketball);
JLabel options = new JLabel("Options");
JLabel startGame = new JLabel(" >> Start << ");
// gameScreen gS = new gameScreen();
BufferedImage wallpaper;
//-------------PAINT FUNCTION----------//
#Override
public void paintComponent(Graphics g) {
System.out.println("paint");
super.paintComponent(g);
if (wallpaper != null) {
g.drawImage(wallpaper, 0, 0, this);
}
}
//-------------CONSTRUCTOR-------------//
public MenuScreen() {
// Please handle your exceptions better
try {
wallpaper = ImageIO.read(getClass().getResource("/Menu.png"));
setPreferredSize(new Dimension(wallpaper.getWidth(), wallpaper.getHeight()));
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
Cursor cusor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
options.setCursor(cusor);
startGame.setCursor(cusor);
Font font = UIManager.getFont("Label.font").deriveFont(Font.BOLD, 48);
options.setFont(font);
startGame.setFont(font);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
this.add(options, gbc);
gbc.gridy++;
this.add(startGame, gbc);
startGame.addMouseListener(this);
options.addMouseListener(this);
}
public void mouseClicked(MouseEvent e) {
if (e.getSource() == (startGame)) {
fireActionPerformed("startGame");
}
if (e.getSource() == (options)) {
fireActionPerformed("gameOptions");
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
protected void fireActionPerformed(String cmd) {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners != null && listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, cmd);
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}
Menu Screen...
And when you click start...the game screen...
Now this is an EXAMPLE. Please try and take the time to understand what it going on in the code before you march ahead and implement it. I used by own images, you'll need to get your own..
There are several ways to stop your JPanel from "appearing" depending on exactly what you want to accomplish. One was it to to call setOpaque(false);. I'm not entirely sure how this affects custom painting, though.
Another posibility is
Container parent = getParent().remove(this);
parent.validate();
A third posibility is to add a flag in your class which is set when you click on a JLabel (or better yet a JButton -- see comments below). Then in your paintComponent() method you can check the flag and draw accordingly.
Note:
You are incorrectly using a JLabel and mouse events to respond to user input. Typically in a Swing application, we use JButtons and ActionListeners to accomplish what you are trying to do here. One advantage of this is that you only have to implement one method called onActionPerformed() and don't need to worry about adding all the mouse event handlers that you don't want to even respond to.