I am dragging a JLabel around the screen, and when I release above the JPanel it is supposed to snap to where it completely covers the JPanel. Also, if I release anywhere else it is supposed to snap to its original position. I have the snap part, but I don't know how to tell if it is over the JPanel. I have my code below.
import java.awt.Color;
java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.event.MouseEvent;
public class Main {
public static final int CARD_HEIGHT = 97;
public static final int CARD_WIDTH = 73;
/**
* Mouse Handler components
* Changes the location of the JLabel with the mouse
*/
public static MouseInputAdapter mouseHandler = new MouseInputAdapter(){
public int labelDisX;
public int labelDisY;
public void mousePressed(MouseEvent e) {
labelDisX = e.getX();
labelDisY = e.getY();
//move the card above all others
e.getComponent().getParent().setComponentZOrder(e.getComponent(), 0);
e.getComponent().getParent().repaint();
}
public void mouseReleased(MouseEvent e) {
//if not above panel, then move to original spot
if(!abovePanel()) {
e.getComponent().setLocation(labelDisX, labelDisY);
}
}
public void mouseDragged (MouseEvent e) {
JPanel panel = (JPanel) e.getComponent().getParent();
//get preliminary new X coordinate
int newX = e.getComponent().getX() + e.getX() - labelDisX;
//get preliminary new Y coordinate
int newY = e.getComponent().getY() + e.getY() - labelDisY;
//Not moved off edges of JFrame
if(newX > panel.getWidth() - CARD_WIDTH) {
newX = panel.getWidth() - CARD_WIDTH;
}
if(newY > panel.getHeight() - CARD_HEIGHT) {
newY = panel.getHeight() - CARD_HEIGHT;
}
if(newX < 0) { newX = 0; }
if(newY < 0) { newY = 0; }
e.getComponent().setLocation(newX, newY);
}
};
/**
* check to see if the JLabel is above the JPanel
* #return
*/
public static boolean abovePanel() {
return false;
}
/**
* Adds ability to drag to JLabel
* #param label
*/
public static void addDrag( JLabel label) {
System.out.println("Adding drag");
label.addMouseMotionListener(mouseHandler);
label.addMouseListener(mouseHandler);
}
public static void main(String[] args) {
// Create a JFrame
JFrame frame = new JFrame("Example Frame");
// JPanel to add JLabels to
JPanel panel = new JPanel();
// Add a drop target text area in the center of the frame
DropTargetArea dropPanel = new DropTargetArea();
dropPanel.setPreferredSize(new Dimension(CARD_WIDTH, CARD_HEIGHT));
dropPanel.setBackground(Color.gray);
panel.add(dropPanel);
// Add several draggable labels to the container
JLabel blue = new JLabel();
blue.setOpaque(true);
blue.setPreferredSize(new Dimension(CARD_WIDTH, CARD_HEIGHT));
blue.setBackground(Color.blue);
addDrag(blue);
panel.add(blue);
// Add the container to the frame
frame.add(panel);
// Display the frame
frame.setPreferredSize(new Dimension(400,400));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
}
I've done this using a JLayeredPane that holds a JPanel that itself holds a grid of JPanels using BorderLayout, with each smaller JPanel representing a chess square, and each smaller JPanel can accept a single JLabel. I added the MouseAdapter to the JLayeredPane itself, and when clicked, it checks to see if a moveable JLabel is located below the click. If so, the JLabel is raised up to the JLayeredPane's DRAG_LAYER, and then when released, check which JPanel the mouse cursor is over, and drop the JLabel if it is a valid square, otherwise return it to its original position. You can see my code here.
Related
I'm trying to resize a window dynamically using a Timer object, but not succeeding... I set the preferred size of the panel in the constructor, which sets the size of the window nicely, though only once. The preferred size changes after the program is initialized, but the window size stays the same. Why? Because the constructor is initialized only once and therefore isn't affected by the size change? If so, how could I get around this to resize the window in real-time?
I know this won't solve the problem in the exercise given in the beginning comments, so please ignore that :-)
/*
* Exercise 18.15
*
* "(Enlarge and shrink an image) Write an applet that will display a sequence of
* image files in different sizes. Initially, the viewing area for this image has
* a width of 300 and a height of 300. Your program should continuously shrink the
* viewing area by 1 in width and 1 in height until it reaches a width of 50 and
* a height of 50. At that point, the viewing area should continuously enlarge by
* 1 in width and 1 in height until it reaches a width of 300 and a height of 300.
* The viewing area should shrink and enlarge (alternately) to create animation
* for the single image."
*
* Created: 2014.01.07
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Ex_18_15 extends JApplet {
// Main method
public static void main(String[] args) {
JFrame frame = new JFrame();
Ex_18_15 applet = new Ex_18_15();
applet.isStandalone = true;
frame.add(applet);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// Data fields
private boolean isStandalone = false;
private Image image = new ImageIcon("greenguy.png").getImage();
private int xCoordinate = 360;
private int yCoordinate = 300;
private Timer timer = new Timer(20, new TimerListener());
private DrawPanel panel = new DrawPanel();
// Constructor
public Ex_18_15() {
panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
add(panel);
timer.start();
}
class DrawPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(yCoordinate <= 50) {
yCoordinate++;
xCoordinate++;
}
else if(yCoordinate >= 300) {
yCoordinate--;
xCoordinate--;
}
panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
repaint();
}
}
}
You need to re-pack your JFrame to resize it. For instance at the end of your ActionListener:
Window win = SwingUtilities.getWindowAncestor(panel);
win.pack();
A question for you though: Why in heaven's name is your class extending JApplet and not JPanel? Or if it needs to be an applet, why are you stuffing it into a JFrame?
Edit
Regarding your comment:
Wouldn't it usually be extending JFrame not JPanel? I'm stuffing it into a JFrame to allow it to run as an application as well as an applet. That's how 'Introduction to Java Programming' tells me how to do it :p Adding your code at the end of the actionPerformed method didn't do anything for me ;o
Most of your GUI code should be geared towards creating JPanels, not JFrames or JApplets. You can then place your JPanels where needed and desired without difficulty. Your book has serious issues and should not be trusted if it is telling you this.
Edit 2
Works for me:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShrinkingGui extends JPanel {
private static final int INIT_W = 400;
private static final int INIT_H = INIT_W;
private static final int TIMER_DELAY = 20;
private int prefW = INIT_W;
private int prefH = INIT_H;
public ShrinkingGui() {
new Timer(TIMER_DELAY, new TimerListener()).start();;
}
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (prefW > 0 && prefH > 0) {
prefW--;
prefH--;
Window win = SwingUtilities.getWindowAncestor(ShrinkingGui.this);
win.pack();
} else {
((Timer)e.getSource()).stop();
}
}
}
private static void createAndShowGUI() {
ShrinkingGui paintEg = new ShrinkingGui();
JFrame frame = new JFrame("Shrinking Gui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
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)
Hi I am new to java and I thought I'd try produce a game where the user actually tries solving the 8 queens problem themselves. However, It increases in difficulty starting 8 rooks, up to 14 bishops then 8 queens.
I have created the chessboard successfully. I have a problem with my mouselistener... each square on the board is a button and when clicked my intention is that that square will change colour to indicate its been clicked, then all squares that cant be clicked on again will also change to indicate squares out of the game.
When the square is clicked it doesn't seem to perform any action.
Sorry, I know its trivial.
Thanks.
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class rooks extends JFrame implements MouseListener{
private final int BOARD_SIZE = 8;
private final int BOARD_SIZE_COLS = 8;
private final int BOARD_SIZE_ROWS = 8;
// private JTextField bottom = new JTextField("") ");
// private JLabel bannerl = new JLabel("The game");
// private JButton queens = new JButton(" Play Queens ");
private JButton rooks = new JButton(" Play Rooks ");
// private JButton bishops = new JButton(" Play Knights ");
private JButton[][] cboard = new JButton[BOARD_SIZE][BOARD_SIZE];
private JTextArea bottomtextarea = new JTextArea();
// constructor creating the chessboard
public rooks(){
this.setSize(500, 500);
this.setTitle("rooks");
// this.setIconImage();
// create JPanels and add JComponents
JPanel main = new JPanel(new BorderLayout());
this.setContentPane(main);
JPanel north = new JPanel();
north.setLayout(new GridLayout(1,3));
main.add(north, BorderLayout.NORTH);
// north.add(queens);
north.add(rooks);
// north.add(bishops);
JPanel south = new JPanel();
main.add(south, BorderLayout.SOUTH);
south.add(bottomtextarea);
bottomtextarea.setEditable(false);
bottomtextarea.setVisible(true);
// create grid (actual chessboard) and initialise each button with no char
JPanel chessBoard = new JPanel(new GridLayout(BOARD_SIZE, BOARD_SIZE));
main.add(chessBoard, BorderLayout.CENTER);
for (int i=0; i<BOARD_SIZE_ROWS; i++){
for(int j=0; j<BOARD_SIZE_COLS; j++){
cboard[i][j] = new JButton("");
chessBoard.add(cboard[i][j]);
// as it loops add colour to the board, if (i+j=even then white, otherwise black)
if ((i + j) % 2 == 0) {
cboard[i][j].setBackground(Color.black);
}
else {
cboard[i][j].setBackground(Color.white);
}
}
}
cboard[7][7].addMouseListener(this);
this.setResizable(false);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
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.print("it has been clicked");
}
void saySomething(String eventDescription, MouseEvent e) {
}
}
Your code is working. I run it and when i click on the 7-7 square, (which is the one in the bottom right corner) i get the message: "it has been clicked".
Since you have added the mouse listener to only this square the code is behaving as expected.
But there are some things you should refactor:
Why do you define BOARD_SIZE, BOARD_SIZE_COLS, BOARD_SIZE_ROWS? If you only use quadratic game boards you only need BOARD_SIZE and if not then you dont need BOARD_SIZE.
Its convention to write the first letter of your classes in upper case. So it is Rooks instead of rooks
You need to add your listener to every square of the board instead of to only one
This should be enough to start with.
You are adding a MouseListener to the last button only, the JButton at cboard[7][7].
Why use a MouseListener and not an ActionListener for JButtons? This makes no sense.
Why not add an ActionListener to all JButtons inside of the for loop?
I have a problem that, I need to only redraw/rebuild the drawing area if the "c" key is pressed.
The way I'm doing using repaint(), turns out to be causing the draw area to be of position.
I also notice that, whenever I re-size the frame, the keylistener is no longer working.
Problems:
unable to repaint correctly.
keylistener is not working after frame is re-sized.
Love to attach the display, but seems like it is blocked because I am newbie.
The following code is the main function that call the class "newZone".
frame.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e){
System.out.println("component Rebuild");
frame.getContentPane().removeAll();
frame.getContentPane().invalidate();
JComponent newContentPane = new newZone(frame.getSize());
newContentPane.setOpaque(true);
frame.getContentPane().add(newContentPane);
frame.getContentPane().revalidate();
frame.setContentPane(newContentPane);
}
});
The following is the class of newZone, which contains Paint & keylistener:
public class newZone extends JComponent implements MouseListener, MouseMotionListener, KeyListener {
JPanel panel1;
JTextArea textArea;
JScrollPane scrollPane;
MyDrawingTool Drawing;
static int firsttimer = 0;
static int preposX = 0;
static int preposY = 0;
static int widthPercentage = 80 , heightPercentage = 93;
static int numberOfYboxes,numberOfXboxes;
static Dimension currentPanelSize;
static final String NEWLINE = System.getProperty("line.separator");
static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public newZone(Dimension currentPanelSize1) {
currentPanelSize = currentPanelSize1;
Drawing = new MyDrawingTool();
Drawing.setBackground(Color.WHITE);
Drawing.setBounds( 10, 10,
(int) currentPanelSize.getWidth()*(widthPercentage)/100,
(int) currentPanelSize.getHeight()*(heightPercentage)/100 );
Drawing.setPreferredSize(new Dimension( (int) currentPanelSize.getWidth()*(widthPercentage)/100,
(int) currentPanelSize.getHeight()*(heightPercentage)/100));
Drawing.addMouseListener(this);
Drawing.addMouseMotionListener(this);
add(Drawing);
addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e){
System.out.println( "Key type: "+e.getKeyChar());
if(e.getKeyChar() == 'c'){
Drawing.redraw();
}
}
});
setFocusable(true);
}
class MyDrawingTool extends JPanel{
void redraw(){
repaint();
}
#Override
public void paint(Graphics q){
//super.paint(q);
int j,k, width, height;
int startX = 10, startY = 10;
int boxSize = 50;
width = (int)currentPanelSize.getWidth()*(widthPercentage)/100;
height = (int)currentPanelSize.getHeight()*(heightPercentage)/100;
numberOfYboxes = (height-20)/50;
numberOfXboxes = (width-20)/50;
for ( j = 0; j < numberOfYboxes; j++)
{
startX = 10;
for ( k = 0; k < numberOfXboxes; k++)
{
q.setColor(Color.WHITE);
q.fillRect(startX, startY, boxSize, boxSize);
q.setColor(Color.BLUE); //Set line color
q.drawRect(startX, startY, boxSize, boxSize);
startX+=boxSize;
}
startY+=boxSize;
}
}
}
}
I don't know why you are using a ComponentListener. I don't see any reason to remove/add/invalidate/revalidat and do all the other stuff.
All you need to do is add the panel to the CENTER of a content pane of the frame. The panel will automatically increase/decrease in size as the frame resizes. There is no need for the ComponentListener.
Custom painting should be done in the paintComponent() method and don't forget to invoke super.paintComponent(...) at the start.
The KeyListener doesn't work because focus is now on the JFrame (not the panel) after you resize the frame. You should NOT be using a KeyListener for this. Instead you should be Key Bindings which work even when the panel doesn't have focus.
It seems, you do not need to switch content pane at all.
If you use some layout on default content pane, as #camickr suggested, you won't need to handle resize and other stuff manually.
Good luck there.
I have the following code
import javax.swing.*;
import java.awt.event.*;
public class MousePos implements MouseMotionListener{
JLabel x = new JLabel();
JLabel y = new JLabel();
public static void main(String[] args) {
MousePos mp =new MousePos();
mp.go();
}
public void go() {
JFrame frame = new JFrame("Mouse Position");
frame.addMouseMotionListener(this);
JPanel p =new JPanel();
p.add(x);
p.add(y);
frame.getContentPane().add(p);
frame.setSize(150,150);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
x.setText("X : " + e.getX());
y.setText("Y : " +e.getY());
}
}
which create a frame with two labels that hold the x position and y position of the mouse pointer on the form.
what I learned is the x value and y value would be 0 and 0 on the top left corner
the problem is the value never go below 4 for x and 23 for y.
Could anyone tell me why.
Thanks in advance.
frame.addMouseMotionListener(this);
The coordinates are relative to the frame and not to the content pane. 4 is the width of the frame's border, 23 the height of border plus frame "title area".
Try this instead:
p.addMouseMotionListener(this);
If you're listening to the frames mouse events by intention, note, that the frame unfortunatly does not fire events if the button is over the border or the title area... That's why you don't observer (0,0) if you point to the frames upper left corner.