so this is my problem. I have an 8*8 grid of panels, all white. Then, when one of them is clicked, it's supposed to change to a random color. The only problem I have right now is that I don't know how to see if the user clicked their mouse in a specific panel. Here is the code I have so far (I'm going to implement the random element afterwards)
`
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GridOfPanels extends JPanel{
int x, y;
public GridOfPanels(){
JPanel content = new JPanel(new GridLayout(8,8));
for(int i = 0; i < 64; i++){
JPanel panel = new JPanel();
panel.setBackground(Color.white);
content.add(panel);
}
this.add(content);
}
public GridOfPanels(Color backColor){
setBackground(backColor);
addMouseListener(new PanelListener());
x = 200;
y = 200;
}
private class PanelListener extends MouseAdapter{
public void mousePressed(MouseEvent e){
x = e.getX();
y = e.getY();
repaint();
}
}
public static void main(String[] args){
JFrame theGUI = new JFrame();
theGUI.setTitle("Grid");
theGUI.setVisible(true);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theGUI.setSize(400,400);
Rectangle z = new Rectangle(x, y, 50, 50);
}
}
`
You have to add a listener to each clickable object. Here is a working example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestFrame extends JFrame{
public TestFrame(int size){
JPanel content = new JPanel(new GridLayout(size, size));
JPanel[] panel = new JPanel[size * size];
PanelListener listener = new PanelListener();
for(int i = 0; i < panel.length; i++){
panel[i] = new JPanel();
panel[i].setBackground(Color.white);
panel[i].addMouseListener(listener);
content.add(panel[i]);
}
this.add(content);
}
// MouseListener offers the method mouseClicked(MouseEvent e)
private class PanelListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent event) {
/* source is the object that got clicked
*
* If the source is actually a JPanel,
* then will the object be parsed to JPanel
* since we need the setBackground() method
*/
Object source = event.getSource();
if(source instanceof JPanel){
JPanel panelPressed = (JPanel) source;
panelPressed.setBackground(Color.blue);
}
}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
}
public static void main(String[] args){
TestFrame theGUI = new TestFrame(8);
theGUI.setTitle("Grid");
theGUI.setVisible(true);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theGUI.setSize(400,400);
}
}
You have to add MouseListener to one of the panels. Only one panel will react to click event. In the listener cast the source to JPanel and change the color.
Related
I thought I implemented MouseListener correctly, but when I click on the canvas it doesn't reach the line System.out.println("Click registered");
All the tutorials I've looked at implement a mouse listener the way I did.
The program compiles and everything works except for the mouse listener.
package ttt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Frame extends JFrame implements MouseListener
{
public static Field field = new Field();
public static Game game = new Game();
public static TTTCanvas tttcanvas = new TTTCanvas();
static final long serialVersionUID = 1l;
private static final int width = 700;
private static final int height = 700;
public Frame()
{
setLayout(new BorderLayout());
setResizable(false);
setBounds(400, 400, width, height);
setTitle("Tic Tac Toe");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
add(tttcanvas);
addMouseListener(this);
}
public void mouseClicked(MouseEvent e)
{
System.out.println("Click registered");
int x = field.getFieldfromPixel(e.getX());
int y = field.getFieldfromPixel(e.getY());
game.updateField(x, y);
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
Add the mouselistener to your ttt canvas
package ttt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Frame extends JFrame implements MouseListener
{
public static Field field = new Field();
public static Game game = new Game();
public static TTTCanvas tttcanvas = new TTTCanvas();
static final long serialVersionUID = 1l;
private static final int width = 700;
private static final int height = 700;
public Frame()
{
setLayout(new BorderLayout());
setResizable(false);
setBounds(400, 400, width, height);
setTitle("Tic Tac Toe");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
add(tttcanvas);
tttcanvas.addMouseListener(this); //changed here
}
public void mouseClicked(MouseEvent e)
{
System.out.println("Click registered");
int x = field.getFieldfromPixel(e.getX());
int y = field.getFieldfromPixel(e.getY());
game.updateField(x, y);
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
Works fine for me when I remove:
//add(tttcanvas);
A MouseEvent is only dispatched to a single component.
Your TTTCanvas class must also have a MouseListner, so it is receiving the event.
Not sure what your exact requirement is so I would guess you could either:
add a second MouseListener to the TTTCanvas class or combine the logic of both listeners into one listener, or
remove the listener from the TTTCanvas class
Some code to demonstrate my answer:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Frame extends JFrame implements MouseListener
{
// public static Field field = new Field();
// public static Game game = new Game();
// public static TTTCanvas tttcanvas = new TTTCanvas();
// static final long serialVersionUID = 1l;
private static final int width = 700;
private static final int height = 700;
public Frame()
{
setLayout(new BorderLayout());
setResizable(false);
setBounds(400, 400, width, height);
setTitle("Tic Tac Toe");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
//add(tttcanvas);
JPanel panel = new JPanel();
panel.setPreferredSize( new Dimension(700, 400) );
panel.setBackground(Color.RED);
panel.addMouseListener( new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
System.out.println("panel listener");
}
});
add(panel, BorderLayout.PAGE_START);
addMouseListener(this);
}
public void mouseClicked(MouseEvent e)
{
System.out.println("frame listener");
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> new Frame() );
}
}
if you click on the red panel you see "panel listener" because the panel receives the event not the frame.
if you click on the grey you see "frame listener" because no other component has been added to the CENTER of the frames BorderLayout, so the frame receives the MouseEvent.
I have a class whitch extends JPanel:
public class ButtonPanel extends JPanel {
private label;
public ButtonPanel() {
label=new JLabel("waiting for click");
add(label);
}
public void setButtonText() {
label.setText("just clicked");
}
}
I have several instances of that class which is added to JFrame. I want to create one instanse of MouseAdapter class and then add them as a mouse listener to all of the ButtonPanel components on my JFrame. I meen:
ButtonPanel butt1 = new ButtonPanel();
ButtonPanel butt2 = new ButtonPanel();
ButtonPanel butt3 = new ButtonPanel();
//... here goes code which add ButtonPanels to JFrame
MouseAdapterMod mam = new MouseAdapterMod();
butt1.addMouseListener(mam);
butt2.addMouseListener(mam);
butt3.addMouseListener(mam);
The MouseAdapterMod class I want to be separate from the other and locate in it's own package. It should looks like this:
public class MouseAdapterMod extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
//here goes the code of calling setButtonText method of ButtonPanel component on which the event had occurred
}
}
So the problem is that I don't know how to implement mouseClicked method to make it determine which of ButtonPanel generate the event and call the corresponding to that component setButtonText() method. Is anyone know how to do that?
I know that I can achieve this by including event handling functionality in the ButtonPanel class, but thats not appropriate way for me, cuz I want to keep the class structure as I described above and have only one instance of MouseAdapterMod class for handling all of the ButtonPanels.
The MouseEvent#getSource method will return which object has been clicked:
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
As the comments note, you're often better off listening for mousePressed or mouseReleased rather than mouseClicked because for mouseClicked to work, the press and release must be from the same point, and if the mouse shifts even a slight amount, the click won't register.
My test program:
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import javax.swing.*;
public class MainForButtonPanel extends JPanel {
public MainForButtonPanel() {
setLayout(new GridLayout(4, 4));
MouseAdapter myMA = new MouseAdapterMod();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
ButtonPanel btnPanel = new ButtonPanel();
btnPanel.addMouseListener(myMA);
add(btnPanel);
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MainForButtonPanel");
frame.getContentPane().add(new MainForButtonPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ButtonPanel extends JPanel {
private static final int TIMER_DELAY = 2000;
private static final String JUST_CLICKED = "just clicked";
private static final String WAITING_FOR_CLICK = "waiting for click";
private static final Color CLICKED_COLOR = Color.pink;
private JLabel label;
public ButtonPanel() {
label = new JLabel(WAITING_FOR_CLICK);
add(label);
}
public void setButtonText() {
label.setText(JUST_CLICKED);
setBackground(CLICKED_COLOR);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText(WAITING_FOR_CLICK);
setBackground(null);
((Timer)ae.getSource()).stop();
}
}).start();
}
}
class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
ButtonPanel btnPanel = (ButtonPanel)e.getSource();
btnPanel.setButtonText();
}
}
So I have created a program that accepts the radius of a circle in a text box, creates the circle of a random color in a random spot and another button to clear the page of all circles. The problem I am having is with my overridden paint().
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class PushPanel extends JPanel
{
private JButton newb;
private JButton clear;
private JLabel label;
private int x, y, width, r;
private int color;
private JTextField radius;
public PushPanel()
{
newb = new JButton("New");
clear = new JButton("Clear");
radius = new JTextField(5);
radius.addActionListener(new TextListener());
newb.addActionListener(new ButtonListener());
clear.addActionListener(new ButtonListener2());
label = new JLabel ("Circle creator", SwingConstants.CENTER);
add(radius);
add (newb);
add (clear);
add(label);
setPreferredSize(new Dimension(300,300));
}
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
paintComponent(getGraphics());
}
public void paintComponent(Graphics page)
{
Random rand = new Random();
int redValue = rand.nextInt(255);
int greenValue = rand.nextInt(255);
int blueValue = rand.nextInt(255);
Color clr = new Color(redValue, greenValue, blueValue);
Random generator = new Random(101);
x = generator.nextInt();
y = generator.nextInt();
width = r*2;
page.setColor(clr);
page.fillOval(x,y,width,width);
}
}
public class ButtonListener2 implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
paintComponent(getGraphics());
}
public void paintComponent(Graphics page)
{
page.setColor(Color.white);
}
}
public class TextListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String text = radius.getText();
r = Integer.parseInt(text);
}
}
}
This is the driver class, pretty basic
public class Circle
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Circle stuff");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
PushPanel panel = new PushPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
You haven't actually told us what the problem is, but I would bet it's because your paintComponent() method is inside your ButtonListener class, not your PushPanel class.
Also, you should never call getGraphics() on a component, unless you really know what you're doing. Recommended reading: http://docs.oracle.com/javase/tutorial/uiswing/painting/
I have a program which at the moment I am trying to find the position of co-ordinates on the panel when clicked. So far I'm currently get 0,0. Any suggestions?
P.S - Sorry about the lack of comments...
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.lang.Math;
public class ShapePanel extends JPanel{
private JButton startButton, stopButton;
private JTextField textField;
private JLabel label;
private Timer timer;
private final int DELAY = 5;
ArrayList<Shape> obj = new ArrayList<Shape>();
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ShapePanel());
frame.pack();
frame.setVisible(true);
}
public ShapePanel(){
DrawingPanel dpanel = new DrawingPanel();
JPanel cpanel = new JPanel();
startButton = new JButton("Start");
stopButton = new JButton("Stop");
cpanel.setLayout(new GridLayout(2,1));
cpanel.add(startButton);
cpanel.add(stopButton);
dpanel.addMouseListener(new MouseListen());
TimerListener tListen = new TimerListener();
startButton.addActionListener(tListen);
stopButton.addActionListener(tListen);
add(cpanel);
add(dpanel);
timer = new Timer(DELAY, tListen);
timer.start();
}
private class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == timer){
for (int i = 0; i < obj.size(); i++){
obj.get(i).move();
}
}else if (e.getSource() == startButton){
timer.start();
}else if (e.getSource() == stopButton){
timer.stop();
}
repaint();
}
}
private class MouseListen implements MouseListener {
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
System.out.println(getX());
}
}
private class DrawingPanel extends JPanel{
DrawingPanel(){
setPreferredSize(new Dimension(400,400));
setBackground(Color.pink);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i = 0; i < obj.size(); i++){
obj.get(i).display(g);
}
}
}
}
Check the following portion of your code:
public void mouseClicked(MouseEvent e) {
System.out.println(getX());
// you are putting here only getX() which get the postion of panel
// put e.getX() instead
}
You need to implement the mouselistener correctly. The MouesEvent carries the position of the MouseClick.
public void mouseClicked(MouseEvent e) {
System.out.println(e.getPoint().x);
}
I'm attempting to overlap JPanel instances. Put a panel directly on another, in the exact same position and exact size. Every time I do this it moves the other panel to the other side or underneath, the previous panel is inside another much larger one and has buttons in it.
How would I do this? Keep in mind it's using the Window Builder tool.
You might also want to look at OverlayLayout, seen here. It's not included in the conventional gallery, but it may be of interest.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
/** #see http://stackoverflow.com/a/13437388/230513 */
public class OverlaySample {
public static void main(String args[]) {
JFrame frame = new JFrame("Overlay Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new OverlayLayout(panel));
panel.add(create(1, "One", Color.gray.brighter()));
panel.add(create(2, "Two", Color.gray));
panel.add(create(3, "Three", Color.gray.darker()));
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private static JLabel create(final int index, String name, Color color) {
JLabel label = new JLabel(name) {
private static final int N = 64;
#Override
public boolean isOpaque() {
return true;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(index * N, index * N);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(index * N, index * N);
}
};
label.setHorizontalAlignment(JLabel.RIGHT);
label.setVerticalAlignment(JLabel.BOTTOM);
label.setBackground(color);
label.setAlignmentX(0.0f);
label.setAlignmentY(0.0f);
return label;
}
}
I'm attempting to overlap JPanels
Use a JLayeredPane (image below from the linked tutorial).
Put a JPanel directly on another,
..or a CardLayout as shown here..
..depending on which of those two you mean, since I understand them as quite different effects.
Use a JDesktopPane (or its superclass JLayeredPane) as its content, adding to the pane.
See How to Use Internal Frames for examples.
Here you can see a nice way of letting components overlay, and pop up when the cursor rests on it:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ShiftedStackPanel extends JPanel implements MouseListener,
ActionListener {
private static final long serialVersionUID = 1988454751139668485L;
private int layer;
private JDesktopPane desktopPane;
private Timer timer;
private Component currentComponent;
private int layerOfCurrent;
private int shiftDivision;
public ShiftedStackPanel() {
this(4);
}
public ShiftedStackPanel(int shift) {
shiftDivision = shift;
setLayout(new BorderLayout(0, 0));
desktopPane = new JDesktopPane();
desktopPane.setBackground(SystemColor.window);
super.add(desktopPane);
timer = new Timer(1000, this);
timer.setRepeats(false);
}
public Component add(Component c) {
Dimension dim = c.getPreferredSize();
c.setBounds(
(desktopPane.getComponentCount() * (dim.width / shiftDivision)),
0, dim.width, dim.height);
desktopPane.add(c, new Integer(++layer));
c.addMouseListener(this);
return c;
}
public void remove(Component c) {
throw new IllegalArgumentException(
"Removal of component, not yet supported.");
// FIXME: allow removal, and shift all latter comps, to left
}
public void removeAll() {
desktopPane.removeAll();
}
public static void main(String[] args) {
JFrame f = new JFrame("JFrame Wrapper");
ShiftedStackPanel p;
f.setContentPane(p = new ShiftedStackPanel(4));
p.add(new JTextField("ABCDEFGHI"));
p.add(new JTextField("DEFGHIJKL"));
p.add(new JTextField("GHIJKLMNO"));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.setMinimumSize(new Dimension(400, 200));
f.setLocationRelativeTo(null);
}
#Override
public void mouseClicked(MouseEvent evt) {
if (currentComponent != null) {
Component c = (Component) evt.getSource();
currentComponent = c;
layerOfCurrent = desktopPane.getLayer(c);
desktopPane.remove(c);
desktopPane.add(c, new Integer(100));
}
}
#Override
public void mouseEntered(MouseEvent evt) {
timer.start();
Component c = (Component) evt.getSource();
currentComponent = c;
layerOfCurrent = desktopPane.getLayer(c);
}
#Override
public void mouseExited(MouseEvent evt) {
if ((currentComponent != null) && currentComponent == evt.getSource()) {
desktopPane.remove(currentComponent);
desktopPane.add(currentComponent, new Integer(layerOfCurrent));
currentComponent = null;
timer.stop();
}
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
desktopPane.remove(currentComponent);
desktopPane.add(currentComponent, new Integer(100));
}
}
Still has some problems, when using components that require focus, but should work well with JLabel, and JPanel.