Basically, I'm trying to move a JButton (or even a JLabel) inside a frame using the arrow keys.
I've successfully figured out the part to detect the arrow key presses. Now all i want to do is to change the position of the button (or label) depending on the key pressed.
E.G. when I press the "UP" key, the button/label should move up by say 5 pixels. I couldn't find the property to change the position of the button.
Do I need to put button/label inside the panel or something like that?
Please help, its not a homework, just curious :)
How I would do it is to use the Graphics instead of a Panel. So the bit of code that draws it could be:
public class panel extends JPanel{
public int X = 50; //Starting x
public int Y = 50; //Starting y
public panel(){
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
g.drawString("Hello this will be moved", X, Y);//<--- This draws the text
}
}
This bit of code will draw the text and repeatedly draw it. All you have to do is in the Key Listener or what ever was used, do;
X++;
or:
Y++;
That will add 1 everytime. So when you press the key it is moved one x pixel or y pixel or back or forth, depending on the ++ or --. Then add this to the JFrame and it will draw it on screen.
use of a raw image is much better in the application i'm doing but here is something that i accidently found while doing it ;)
This infact can be done by absolute positioning of label(dont know about button) ie. without use of any Layout Manager.
all we have to do is the follwing:
setLayout(null);
Jlabel testLabel = new JLabel("Test Moving label");
now with that done. we have to set
testLabel.setBounds(XCoord+ insets().left, yCoord+ insets().top, 150, 25);
here xCoord and yCoord are the coordinates of the top left pixel of the label. the above line can be added to the actionListener. in my case its the action for pressing UP, RIGHT and LEFT arrow keys.
we can increment and decrement the xCoord and yCoord accordingly.
Related
What I want to accomplish is simple, I press a JButton (called 'right') and the x bounds of a JLabel is increased by 100, effectively moving the JLabel 100 pixels to the right. I have been experimenting with stuff such as :
if(clicked == right) {
piece.getBounds().x = +100;
}
and I tried :
if(clicked == right) {
piece.addBounds(100,0,0,0);
}
the method addBounds was undefined for type JLabel
so I tried :
if(clicked == right) {
piece.setBounds(+100,0,0,0);
}
and clearly all of the above didn't work, but were worth the try. Is there a way to do what I'm tried to do?
The bounds are actually a Rectangle, and so you can get the JLabel's Bounds, advance its x position, and then set the bounds by calling the appropriate methods:
Rectangle bounds = piece.getBounds(); // get the bounds
bounds.x += 100; // increment the x value
piece.setBounds(bounds); // re-set the new bounds
repaint(); // call repaint on the container that holds the JLabel so it is repainted
If I remember correctly, the swing components in Java are required to be repainted when a change is made to them.
Try simply calling the "repaint()" method when the button has been pressed and your changes to the component should update.
Good day,
I might've been a bit vague with the title of my question, but I hope this will explain. The scenario is quite basic - I have a JFrame, in which I have an array of JPlanes. The idea is that when I click on one of them, upon clicking in should become black. Here is the code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.border.Border;
public class PixelArt {
JFrame frame;
Border blackline;
JPanel squares[][] = new JPanel[100][100];
int x;
int y;
public PixelArt() {
frame = new JFrame("Pixel Art");
frame.setSize(1000, 1000);
frame.setLayout(new GridLayout(100, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
x = i;
y = j;
squares[i][j] = new JPanel();
squares[i][j].setBorder(BorderFactory.createDashedBorder(null));
squares[i][j].addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
squares[x][y].setBackground(Color.black);
}
});
frame.add(squares[i][j]);
}
}
frame.setVisible(true);
}
public static void main(String[] args) {
new PixelArt();
}
}
The actual problem is that this code does not do what I explained above. It does color in one of the JPlane's black when clicked, but within a 9x9 area starting from the upper corner of the grid. I do not have an explanation for this. The problem seems to be in the following 2 lines:
x = e.getX();
y = e.getY();
One of my guesses is that I have some kind of an offset in the coordinate system, but then this does not explain why regardless on which JPanel I press, the JPanels colored are only in the upper 9x9 area.
Does anyone have a clue how I could fix the problem I described above? If something is unclear in my explanation, please ask. Thank you in advance.
Here is a screenshot of the working code:
you can detect clicked panel using event.getSource() like follow example code
public void mouseClicked(MouseEvent e) {
JPanel panel = (JPanel)e.getSource();//
panel.setBackground(Color.black);
}
the problem is you can't use x,y directly as indexes to array element. because panels has a width and borders too.if you go with x y you have to make some mathematics logic. for example you click middle of your first jpanel in the grid so let's assume x and y coordinate is about 10px but in your code you call [10][10] Janel but actually you should call [0][0].
also as #Cr0w3 says you add listners to all panels.so if you clicked middle of first grid cell or last grid cell there is no difference in x,y.
but if you make a mathematical logic to detect clicked element you need to take in to account your frame/main panel width(also have to update when risize) and border thickness.
also do you really want to do this using 10000 panels ? you may need use a one panel and override paint component method.10000 panels isn't effective for this kind of thing.if you resize or click quickly on panels you will see it take a lot of time. so you may need to draw graphics on a jpanel .see this example
I think you should not add the listener to the panels themselves, but to the frame.
Because the X and Y coordinates might be relative to the panel size (e.g., upper corner of the panel returns 1/1, thus you apply the color to the panel at [1][1] even though you click the panel at [50][50].
If you use the frame for listening at the point you will receive 50/50 as coordinates.
Unfortunately I cannot comment, because of my low reputation but I hope I could help a little.
If you want to add a listener to the panel do not use the coordinates and just apply color to the clicked panel without listening to the coordinates. Using e.getSource() should help you in that case.
I am having an issue getting this code to run properly. It compiles and initially the frame displays properly. The problem is that when I manually re-size the frame by either maximizing or by dragging the side of the frame over, the text disappears. I am using jGRASP, not sure if that is the issue or not. The code seems to make sense to me, and like I said, it compiles(I know that does not necessarily make it right). I'm still a newbie at this so if anyone can point me in the right direction I would be very appreciative.
import javax.swing.*;
import java.awt.*;
public class JFontSizes extends JFrame {
int x = 5;
int y = 50;
String homework = "This is the first homework assignment";
public JFontSizes() {
super("Increasing Font Sizes");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics brush) {
super.paint(brush);
// This works sometimes. I am not sure if it is a jGRASP issue or something else.
// If I resize the frame, the text disappears, and I cannot get the text to start at the top of the frame
for(int n = 6; n<= 20; ++n) {
brush.setFont(new Font("Serif", Font.PLAIN, n));
brush.drawString(homework, x, y);
y += 15;
}
}
public static void main(String[] args) {
JFontSizes frame = new JFontSizes();
frame.setSize(400, 500);
frame.setVisible(true);
}
}
When first time paint() is called the value of y was 5. And it is incremented in a loop. So that before leaving paint() its value will be 275.
But when you resize your frame paint() is called again and this time the value of y is 275 and when brush.drawString(homework, x, y); is called the homework is printed at 275px bottom from top left corner.
So what you need to do is re-initialize y every time :
public void paint(Graphics brush) {
y = 50;
....
Edit :
As commented by camickr you should override paintComponent(...) instead of paint(...) until you have some specific reason to override paint().
And you mean you are not able to print text at top (even in beginning) then it is because you had initialized y with 50. Which means the text will be drawn at 50px from top.
I am interested in simple game programming with AndEngine. And I would like to do some basic round based strategy stuff. So I would like to have a top down view to some grid. Every square in this chess like grid should be clickable (touchable on android of course). But I can´t imagine drawing lines and squares is the best solution to do so. I would like to have some kind of abstract object list, which I can extend to different behaviours (one click triggers menu to open, on other field a click triggers an explosion, whatever...).
I have been searching for this in several engines over the years now. It is a hobby, but I would like to find a solution for it. Can anyone give me a hint about how this could be done in an elegant way? Double buffering, rendering and stuff isn´t that important. The important thing is, every square should be an object that gets painted.
Anyone? ;)
Regards.
Simplet solution would be something like that (lets say that your screen is 800x480 in portrait mode, and I assume that you have GLES2-AC andEngine branch).
in your onCreateScene() method:
Rectangle rect1 = new Rectangle(80, 133, 160, 266, engine.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY){
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
//here put what you want to be done after your button was pressed
}
}
Rectangle rect2 = new Rectangle(240, 133, 160, 266, engine.getVertexBufferObjectManager()){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY){
if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){
//here put what you want to be done after your button was pressed
}
}
and you continue 7 more times with changing first two numbers in new Rectangle(x, y....) which are coordinates of the center of rectangle(second pair of numbers is the height and wisth of the rectangle). (so bottomrow has coordinates: (80, 133), (240, 133) and (400, 133). Middle row: (80, 399), (240, 399) and (400, 399). Third row you can figure out. Of course it does not give you completely covered screen. This you can achieve by dividing your WIDTH and HEIGHT of the screen by certain numers und use it as a coordinates for rectangles. remember to attach all rectangles to your scene and add
this.setOnSceneTouchListener(getOnSceneTouchListener());
this.setOnSceneTouchListenerBindingOnActionDownEnabled(true);
and register touch area for all rectangles.
More difficult way would be to create class for example MyButton.class that extends rectangle or sprite class that has a methods that will be used when "button" is pressed. It depends on what you really need.
I have a question regarding the callback speed of the mouseDragged message of the MouseMotionListener in Java Swing. This post is sort of related but it's not entirely the same so I started a question of my own.
I'm making a small in-house application with no eye on commercial distribution that is basically a digitalized TCG (Trading Card Game) emulator. For any of you familiar with MtG (Magic the Gathering), you might've heard from such a similar program. I'm trying to create something that looks sort of like this, but less fancy.
My GUI consists of a JFrame with menu and then some panels containing various buttons and labels, but I'll only go over the relevent parts to explain my problem.
In essence, I'm using a vertical split JSplitPane with a JPanel on the left, with in that a JScrollPane with a JList in it, which represents at any time the cards in your hand that you can play. On the right side of the split, I have a JLayeredPane with a background image in the DEFAULT_LAYER (subclass of JPanel that overrides the draw function to add an image) and, on various layers above the PALETTE_LAYER, I display the cards that are in play (gathered in an ArrayList) by means of custom CardPanels (another subclass of JPanel that illustrates a card). The entire JLayeredPane is thus a representation of the table in front of you with all the cards you've already played.
I first started by adding a MouseListener and a MouseMotionListener to the JLayeredPane to pick up events, allowing me to register a mouse press, check if this was above a card, then use the mouse dragged event to move the card around and finally mouse release to place it back . This all works perfectly fine and if I add logging information I can see the mouseDragged callback function is called often, allowing for a visually fast dragging motion without lag.
Today I decided to add functionality to allow the user to drag a card from his hand to the "table" (instead of double clicking on the card in the JList), so I added the appropriate listeners to the JList along with filling in some functions like MousePressed and MouseReleased. On a mouse press, I check what card from the list was clicked, I lock the list, create a custom CardPanel (but don't add it anywhere yet, I just allocate and initiate it!) and set a flag. In mouse dragged, I check if this flag is set. If it is, I check where the cursor is. If it is anywhere above the JLayeredPane, I add the CardPanel to the DRAG_LAYER and set another flag. If this second flag is set in successive calls to mouse dragged, I don't add the panel again but I just change the location. This functionality is practically the same as the one in my previous mouse dragged callback. On mouse release, I unlock the list and add the CardPanel on the correct layer in the JLayeredPane.
Everything is working as intended so I'm pretty sure my code is okay, but there is just one slight issue:
When dragging a card from the list to the layered pane (instead of from the layered pane to the layered pane), I notice the mouseDragged callback is called at a pretty low frequency by the JList (approx 10 times per second), introducing some visually disturbing lag (compared to approx 30 times per second in the first case of dragging).
I'm going to add some code snippets as to clarify my problem but I'm afraid adding all the code to allow you to run it yourself would be serious overkill.
The main question in this post is: does anybody know why the mouseDragged is called faster by one MouseMotionListener than by another MouseMotionListener? The listener to the JLayeredPane component makes fast successive calls, the listener to the JList calls significantly slower.
Note: I'm developing in Netbeans and I'm using the built-in graphical Swing Interface Builder. I'm using a JFrame form as my main class.
public class MyFrame extends JFrame{
...
protected JLayeredPane layeredPane;
protected JList cardsInHandList;
...
...
protected ArrayList<String> cardsInHand;
...
private void attachListeners(){
layeredPane.addMouseListener(new MouseAdapter(){
public void MousePressed(MouseEvent e){
// set a flag, start a drag
}
public void MouseReleased(MouseEvent e){
// unset a flag, stop a drag
}
});
layeredPane.addMouseMotionListener(new MouseMotionAdapter(){
public void MouseDragged(MouseEvent e){
// drag the card around
// gets called a lot!
// actual code:
if (e.getButton() == MouseEvent.BUTTON1) {
if (!dragging) return; // the flag
int x = e.getX() - 10;
int y = e.getY() - 10;
// snap to grid
x /= GRIDX;
x *= GRIDX;
y /= GRIDY;
y *= GRIDY;
// redraw the card at its new location
draggedCard.setLocation(x, y);
}
}
});
cardsInHandList.addMouseListener(new MouseAdapter(){
public void MousePressed(MouseEvent e){
// set a flag, start a drag
}
public void MouseReleased(MouseEvent e){
// unset a flag, stop a drag
}
});
cardsInHandList.addMouseMotionListener(new MouseMotionAdapter(){
public void MouseDragged(MouseEvent evt){
// check cursor location, drag if within bounds of layeredPane
// gets called a whole lot less!! _Why?_
// actual code:
if (!draggingFromHand) return; // the flag
// check location of cursor with own method (contains() didn't work for me)
if (isCursorAtPointAboveLayeredPane(evt.getLocationOnScreen())) {
// calculate where and snap to grid
int x = (int) (evt.getLocationOnScreen().getX() - layeredPane.getLocationOnScreen().getX())-10;
int y = (int) (evt.getLocationOnScreen().getY() - layeredPane.getLocationOnScreen().getY())-10;
// snap to grid
x /= GRIDX;
x *= GRIDX;
y /= GRIDY;
y *= GRIDY;
if(!draggingFromHandCardPanelAdded){
layeredPane.add(draggingFromHandCardPanel, JLayeredPane.DRAG_LAYER);
draggingFromHandCardPanelAdded = true;
} else {
draggingFromHandCardPanel.setLocation(x,y);
}
}
}
});
}
I'll try to build a short runnable example reproducing the problem and then attach the code somewhere but right now I got to skoot.
Thanks in advance
PS: I am aware that there is another way to drag in Java, involving TransferHandlers and all that but it just seems like too much hassle and it isn't an actual answer to my question of how come the one callback seems to be called more than the other, so please don't tell me to use that instead.
Once you drag outside the list, Java start generating synthetic mouse events for the list, which might be the cause. See the javadoc for JComponent#setAutoscrolls(boolean).
You might get better results using a global event listener, see
http://tips4java.wordpress.com/2009/08/30/global-event-listeners/