Java: Chess - Moving a piece - java

I would like to move the piece using my mouse.
For example, say there's a pawn sitting on a square on the chess board.
If my mouse was to click (press and release) in the square that the pawn is in, it would be selected. Afterwards, I would click (press and release) in an appropriate square. Say, the square in front of it since that is a proper move in Chess. The pawn would move (get erased from the square it was on, then redrawn on the new one) to the final selected square.
Currently, the Pawn is just sitting on a square when execution is finished.
If it's any help, I am using Ready To Program Java (my teacher told me to) as well as the c console (c = new Console();).
Here is the source code of what I have done so far :)
import hsa.Console;
import java.awt.*;
public class Chess
{
static Console c;
public static void main(String[] args)
{
c = new Console(30, 100); // Rows, Columns (X = 790px && Y = 600px)
Board();
Pawn();
}
public static void Board() // Board: 504px x 504px Square: 63px x 63px
{
int Horizontal = 143; // Board's origin point (X)
int Vertical = 48; // Board's origin point (Y)
for (Vertical = 48; Vertical < 552; Vertical+=63) // Moving onto the next "line"
{
for (Horizontal = 143; Horizontal < 647; Horizontal+=63) // Filling the "line" with squares
{
c.drawRect(Horizontal, Vertical, 63, 63); // Drawing the Squares
}
Horizontal = 143; // Resetting the "line"
}
}
public static void Pawn() // Image and properties of a PAWN piece
{
c.setColor(Color.red); // How the Pawn looks
c.drawOval(143, 111, 63, 63);
}
}

The Console Java class documentation can be found here:
http://stbenedict.wcdsb.ca/hsa/Console.html
As it specifies, it implements the EventListener interface, which has a subinterface, MouseListener. There are many guides online which document how to handle events sent from the MouseListener. Here is one from Oracle's documentation:
https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html

Related

How to merge 2D rectangles into larger polygons [Java]

I have a 2D polygon that only has lines that are perfectly horizontal or perfectly verticle. There are 2 other posts relating to this. However, one is merging multiple rectangles at once into a polygon, and the other is written in javascript.
I would like to take a rectangle of any size and add it to an existing 2D Polygon. Some examples are below.
In the diagram, each box represents 1 pixel. The navy boxes are the points that data exists for and the red and green boxes show how these points are connected. The points of both the red polygon and the green rectangle are held in a linked list (the order of points is what determines what point connects to what). Red and Green boxes don't exist in memory, they're used here only to show connections.
A point is defined as having an x and y coordinate.
How would I go about merging the green rectangle into the red polygon?
I really appreciate any help given thanks!
Edit: Here is some code that draws these shapes:
public class Core
{
private static Polygon polygon = new Polygon();
private static Rectangle rect = new Rectangle();
public static void main(String args[])
{
new Core();
}
public Core()
{
polygon = new Polygon(new int[] {0,12,12,24,24,32,32,12,12,5,5,0},new int[] {0,0,4,4,-3,-3,13,13,15,15,8,8},12);
rect = new Rectangle(18,14,7,6);
Draw2D drawing = new Draw2D();
drawing.setVisible(true);
}
public class Draw2D extends JFrame
{
private static final long serialVersionUID = -1033542824627245527L;
public Draw2D()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new DrawPane(), BorderLayout.CENTER);
pack();
}
}
class DrawPane extends JComponent
{
private static final long serialVersionUID = 5457330297413941626L;
public DrawPane() {
setPreferredSize(new Dimension(1280,720));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(Color.black);
g2.clearRect(0,0,1280,720);
g2.translate(getWidth() / 2, getHeight() / 2);
g2.setColor(Color.white);
g2.setStroke(new BasicStroke(0.001f));
g2.draw(polygon);
g2.draw(rect);
}
}
}
Edit 2:
A partial solution that I have is to inflate the rectangle by pushing each side out by 1 pixel/box, then checking if the entire side is inside one of the red polygon lines. By inside I mean collinear. A green rectangle side is sitting inside one of the red polygon sides.
If it does sit inside then leave the points there, if not move them back to where they originally were. Repeat this clockwise until all 4 sides have ha their points moved or not. Duplicate point objects that reference the same point as a point object that already exists will be deleted so that only 1 point object references 1 point.
This is only part of a solution as this method doesn't work when a rectangle is added on the edge of a polygon (shown in the first image, 2nd and 3rd examples from the top down).
You can simplify your problem by separating it in different parts. So the issue is based on lines.
Horizontal case
1.
R1------R2
xxxxxx (overlaps)
G1------------G2
2.
R1----------R2
xxxxxxx (overlaps)
G1------------G2
3.
R1---------------R2
no overlapping
G1-----G2
...
distance: abs(R_y1 - G_y1)
range of overlap: x1 = max(R_x1,G_x1), x2 = min(R_x2,G_x2),
if (distance <= 1 && x1-x2 > 0) {
// both lines are neighbours and has a valid overlapping range
}
Vertical case
Analogous to horizontal
As your boxes are stored in linked lists, you iterate both boxes and calculate distance and range of overlap.
List<Line> greenBox; // {Line((28,30),(60,30)) , Line((60,30),(60,50)), ...
List<Line> redBox; // ...
for (Line r : redBox) {
for (Line g : greenBox) {
if (distance(r,g) <= 1 && rangeOfOverlap(r,g) > 0) {
// both lines matches and can be merged over the range of overlaps
merge(r,g);
}
}
}
This is just an example to inspire you. You'll need to check if the picked green and red line are both horizontal or both vertical.
The complexity of the algorhythm would be around at m^n (without merging) where n is the number of green lines and m is the number of red lines.
lol

Robot.mouseMove not moving to specified location properly

Whenever I run a mouseMove command for a robot, the mouse doesn't always go to the same location. For example, I have the following code:
import java.awt.Robot;
import java.util.concurrent.TimeUnit;
public class MainBot {
public static void main(String[] args){
try {
Robot screenWin = new Robot();
TimeUnit.SECONDS.sleep(2);
screenWin.mouseMove(100, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The code usually makes the mouse end up at the X:
First, I hit run (I am using eclipse) and move my mouse to a location (before the 2 second timer is up). Then the 2 second delay finishes and the mouse moves and then the script ends. The problem is, the mouse never seems to go to the same exact place twice. For example, the mouse should go to (100, 300) but it goes to something that looks like (0, 300) most of the time. Other times, however, if I move the mouse at the beginning to where it should roughly be, then it goes to the right spot.
I am getting where the mouse should be using Paint to get the pixel location of a screenshot but I don't think it is that because the location keeps changing.
Is there anything I'm missing how the coordinates for mouseMove work?
Edit: Basically, I hit start with that program, then I move the mouse to a new position (so there is a different initial position before the mouseMove function) and then mouseMove executes. Each time I do this, the mouse goes to a different location.
There's an open bug on OpenJDK, so this could be related:
https://bugs.openjdk.java.net/browse/JDK-8196030?jql=project%20in%20(JDK)%20AND%20component%20in%20(client-libs)%20AND%20Subcomponent%20in%20(java.awt)
The bug details that a problem may have been introduced in Windows 10 Fall Creators update, related to screen scaling and a mouse_move function.
In the meantime, you could try to set your screen scale to 100% instead of 125% and see if it helps.
I found a solution, you just have to move the mouse to the coordinate (0,0) then you can move it to the place you want.
I wrote a class to do proper cursor positioning.
This works under windows 10 scalings too.
Use the MoveMouseControlled(double, double) function to move the cursor to a specified position. It uses a [0,1] coordinate system. The (0,0) Point is the upper left corner of the screen.
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
public class MouseCorrectRobot extends Robot
{
final Dimension ScreenSize;// Primary Screen Size
public MouseCorrectRobot() throws AWTException
{
super();
ScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
}
private static double getTav(Point a, Point b)
{
return Math.sqrt((double) ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)));
}
public void MoveMouseControlled(double xbe, double ybe)// Position of the cursor in [0,1] ranges. (0,0) is the upper left corner
{
int xbepix = (int) (ScreenSize.width * xbe);
int ybepix = (int) (ScreenSize.height * ybe);
int x = xbepix;
int y = ybepix;
Point mert = MouseInfo.getPointerInfo().getLocation();
Point ElozoInitPont = new Point(0, 0);
int UgyanAztMeri = 0;
final int UgyanAZtMeriLimit = 30;
int i = 0;
final int LepesLimit = 20000;
while ((mert.x != xbepix || mert.y != ybepix) && i < LepesLimit && UgyanAztMeri < UgyanAZtMeriLimit)
{
++i;
if (mert.x < xbepix)
++x;
else
--x;
if (mert.y < ybepix)
++y;
else
--y;
mouseMove(x, y);
mert = MouseInfo.getPointerInfo().getLocation();
if (getTav(ElozoInitPont, mert) < 5)
++UgyanAztMeri;
else
{
UgyanAztMeri = 0;
ElozoInitPont.x = mert.x;
ElozoInitPont.y = mert.y;
}
}
}
}
I just had a similar problem, to solve it I’ve just done a loop :
Test position
Move
Test position
if not OK move again
And it always works in less than 2 loops
Point pd = new Point(X,Y); // X,Y where mouse must go
int n = 0;
while ((!pd.equals(MouseInfo.getPointerInfo().getLocation())) && (++n <= 5))
{
r.mouseMove(pd.x, pd.y);
}
It works well (correct location) in Full Screen mode with zoom=100%. press F-11 in chrome to full screen page.

Drawing lines between clicks draws from top left corner

I'm currently trying to create a program using processing that draws lines from all mouseclicks to new mouseclicks.
As a side it also should save the clicks in a two-dimensional array.
public void setup() {
size(500,500);
}
int clickcount = 0;
int storedclicks = 10000;
int[] mouseclickX = new int [storedclicks];
int[] mouseclickY = new int [storedclicks];
public void draw() {
background(80);
drawing();
}
public void mousePressed() {
if(clickcount >= storedclicks) {
clickcount = 0;
}
mouseclickX[clickcount] = mouseX;
mouseclickY[clickcount] = mouseY;
clickcount++;
}
public void drawing() {
beginShape(LINES);
for (int i = 0; i < storedclicks; i++) {
vertex(mouseclickX[i], mouseclickY[i]);
}
endShape();
}
}
Something works with the code I have now, but something doesn't add up for me. As it is now, on first click I get a line from the upper left corner, next click that line disappears and I get a new line from the ending point of that line and the first line disappears.
Next click a new line from the corner to clicking point comes (line nr. 2 still present). And then it just continues.
I figured if I changed the storeclicks to a number like 5, it doesn't do the from corner thing, just a new line from every previous click position.
It sounds a little confusing, so here's a picture to help (after 3 clicks):
A few notes:
I'd use a lifo ring buffer (you could simulate it with a linked list) or similar to store the clicks, that way you don't have to check storedclicks separately and it should make drawing easier since the head of the buffer moves when you remove elements from the front.
Additionally I'd only draw lines if there are at least two points in the list/buffer.
Third, to prevent synchronization issues (updating only x or y) I'd use a list/buffer/array of Point objects (make your own or use java.awt.Point) rather than two separate x and y arrays.
As for your drawing code you should loop over the stored points rather than all elements (most of which might be empty), i.e. like this:
When using your code:
if( clickcount > 1 ) {
for (int i = 0; i < clickcount ; i++) {
vertex(mouseclickX[i], mouseclickY[i]);
}
}
When using a list/ring buffer as well as Point objects:
if( list.size() > 1 ) {
for (Point clickpos : list ) {
vertex(clickpos.x, clickpos.y);
}
}
Finally, if processing is similar to OpenGL (I don't know processing) the shape type LINES would draw a line between two vertices, i.e. every uneven vertex is a line start and every even vertex is a line end. What you probably want is something like LINE_STRIP (don't know the name or whether it exists in processing) which makes the renderer draw lines between all vertices (i.e. from 0 to 1, from 1 to 2 etc.)
Edit:
As an explanation for the situation in the image you posted, I assume the clicks are ordered from right to left (indices 0, 1, 2). If that's the case then I'd explain it like this (see above for more info):
The first line is drawn between points 0 and 1, which is ok.
The second line is drawn between points 2 and 3 (see paragraph about the loop as well as LINES resp. line strips), which is not what you want.
The third line (if storedclicks > 5) will be drawn between points 4 and 5, which is a point since both vertices have the coordinates 0/0.
The above bulletpoint is repeated for all following lines (again see the paragraph about the loop).
As you can see there are two problems:
You'd want to draw lines between 0 and 1 and between 1 and 2 which is why I suggested a line strip (if that exists in processing, otherwise you'd have to reuse the last point).
You'd want to stop at index 2, i.e. ignore all indices starting from 3, which is why I mentioned not using storedclicks in the loop condition).
Just to add to the existing great answers, here's a hacky approach that simply takes advantage of not clearing the background:
int lastClickX = -1;
int lastClickY = -1;
void setup(){
size(500,500);
background(80);
}
void draw(){}
void mouseReleased(){
if(lastClickX >= 0 && lastClickY >= 0) line(mouseX,mouseY,lastClickX,lastClickY);
lastClickX = mouseX;
lastClickY = mouseY;
}
You can run this as demo bellow:
var lastClickX = -1;
var lastClickY = -1;
function setup(){
createCanvas(500,500);
background(80);
}
function draw(){}
function mouseReleased(){
if(lastClickX >= 0 && lastClickY >= 0) line(mouseX,mouseY,lastClickX,lastClickY);
lastClickX = mouseX;
lastClickY = mouseY;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.17/p5.min.js"></script>
Bare in mind, although this method doesn't store position, it simply takes advantage of not clearing the screen, which isn't the most flexible of options.
To understand what's happening in your sketch, look to the reference.
This code:
beginShape(LINES);
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape();
Generates this image:
(source: processing.org)
So, that's why you're getting gaps where your line segments aren't drawn. Instead of using LINES, you probably want to use the no-args beginShape() function along with the endShape(CLOSE) function:
(source: processing.org)
noFill();
beginShape();
vertex(30, 20);
vertex(85, 20);
vertex(85, 75);
vertex(30, 75);
endShape(CLOSE);
As for why you're getting a point at 0,0: keep in mind that int arrays are initialized to contain all zeroes by default. So when you loop through your entire array, you end up drawing a bunch of points at 0,0. Instead, you probably want a separate variable that keeps track of the total number of clicks (which you stop updating when you reach the maximum number of clicks you want to hold).
As a side it also should save the clicks in a two-dimensional array.
Note that you aren't storing the clicks in a two-dimensional array. You're storing them in two one-dimensional arrays, also known as parallel arrays. This is generally a bad design. Instead, consider using Processing's PVector class along with an ArrayList instead of an array. That way you can keep track of how many valid clicks you have without needing the separate variable I mentioned above.
Putting it all together, it might look something like this:
ArrayList<PVector> clicks = new ArrayList<PVector>();
public void setup() {
size(500, 500);
}
public void draw() {
background(80);
drawing();
}
public void mousePressed() {
clicks.add(new PVector(mouseX, mouseY));
if(clicks.size() > 5){
clicks.remove(0);
}
}
public void drawing() {
noFill();
beginShape();
for(PVector v : clicks){
vertex(v.x, v.y);
}
endShape(CLOSE);
}
draws lines from all mouseclicks to new mouseclicks.
If instead of a closed polygon, you want something like a spider web that connects every point to every other point, then you just have to loop through each click and draw the connecting lines:
public void drawing() {
for (PVector v1 : clicks) {
for (PVector v2 : clicks) {
line(v1.x, v1.y, v2.x, v2.y);
}
}
}

Gridbag layout or Grid layout?

I am a little new to swing. In order to learn to use the API correctly, I am designing the following project:
The project is a solving block puzzle solver sliding block puzzle similar to the rush-hour puzzles common in toy stores - https://en.wikipedia.org/wiki/Rush_Hour_(board_game) except there is no escape for a special car.
By dragging the blocks from an off board area to the board, the user specifies the starting configuration of the puzzle. The user, in the same way, specifies an ending goal configuration which dictates where some (or all) of the blocks the user specified initially must be at the end of the puzzle - the ending configuration can be specified using only SOME of the blocks, making multiple legal ending configurations.
The algorithm for solving the puzzle is already complete - I just need to design the interface and I am getting stuck. For designing the tray, I used a grid layout. Since blocks need to be entered at certain positions, I need to be able to place blocks in specific cells in the grid and move them around.
A 'block' object has four attributes - its height, width, its top row, and its left most column (ie - each block is addressed by its top left corner).
I used the suggestion here ( https://stackoverflow.com/questions/2510159/can-i-add-a-component-to-a-specific-grid-cell-when-a-gridlayout-is-used ) for the grid layout.
Right now I have only programmed to the point where java reads the puzzle from a .txt file and is supposed to display it on the screen ( I have not designed any user interactablity yet ).
First, here is the code I have written so far.
public class SolverPuzzleGUI extends JFrame {
//Specs from the puzzle.
Board initBoard;
ArrayList<Block> goalBlocks;
LinkedList<Move> moveList;
JLayeredPane layeredpane;
JPanel Board;
Dimension boardsize = new Dimension(400, 500);
JPanel[][] panelHolder = new JPanel[5][4];
public SolverPuzzleGUI(Board startBoard, ArrayList<Block> startGoalBlocks,
LinkedList<Move> startMoveList) {
this.initBoard = startBoard;
this.goalBlocks = startGoalBlocks;
this.moveList = startMoveList;
} // end constructor.
//gives the actual simulation
public void runSimulation() {
// Initalizing the main window.
setSize(500, 600);
setName("Solution");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setMinimumSize(getMinimumSize());
//Using layered pane
layeredpane = new JLayeredPane();
add(layeredpane);
layeredpane.setPreferredSize(boardsize);
layeredpane.setBackground(Color.YELLOW);
layeredpane.setVisible(true);
// adding the game tray
Board = new JPanel();
layeredpane.add(Board, JLayeredPane.DEFAULT_LAYER);
Board.setLayout(new GridLayout(5, 4));
// centering the game tray.
Board.setPreferredSize(boardsize);
Board.setMinimumSize(boardsize);
Board.setMaximumSize(boardsize);
Box box = new Box(BoxLayout.Y_AXIS);
box.add(Box.createVerticalGlue());
box.add(Board);
box.add(Box.createVerticalGlue());
add(box);
//Adding placeholders to the board for creating blocks
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
panelHolder[i][j] = new JPanel();
panelHolder[i][j].setBackground(Color.DARK_GRAY);
Board.add(panelHolder[i][j]);
layeredpane.setLayer(panelHolder[i][j], JLayeredPane.DEFAULT_LAYER);
panelHolder[i][j].setVisible(false);
} // end 'j' for
} // end 'i' for
ArrayList<Block> initBlocks = initBoard.getBlocks();
//int count = 0; //DEBUG
for (Block block : initBlocks) {
this.drawBlock(block);
//count++;
//if(count > 4) { break; }
} // end 'for'
Board.setBackground(Color.DARK_GRAY);
Board.setVisible(true);
setVisible(true);
} // end 'run'
private void drawBlock(Block block) {
Dimension blockSize = new Dimension(block.getWidth()*100, block.getHeight()*100);
System.out.println(blockSize.width);
System.out.println(blockSize.height);
JPanel screenBlock = new JPanel();
screenBlock.setPreferredSize(blockSize);
screenBlock.setMinimumSize(blockSize);
screenBlock.setMaximumSize(blockSize);
screenBlock.setSize(blockSize);
screenBlock.setBackground(Color.BLUE);
screenBlock.setBorder(BorderFactory.createLineBorder(Color.BLACK));
layeredpane.setLayer(screenBlock, JLayeredPane.MODAL_LAYER);
int leftRow = block.getRow();
int leftCol = block.getColumn();
panelHolder[leftRow][leftCol].setSize(blockSize);
panelHolder[leftRow][leftCol].setVisible(true);
panelHolder[leftRow][leftCol].add(screenBlock);
layeredpane.setLayer(panelHolder[leftRow][leftCol], JLayeredPane.MODAL_LAYER);
screenBlock.setVisible(true);
}// end 'drawBlock'
public static void main(String[] args) {
String file = "C:\\Users\\Tim\\Desktop\\init.from.handout.txt";
String goal = "C:\\Users\\Tim\\Desktop\\goal.2.from.handout.txt";
/*
A SolverPuzzle object is the object which actually solves the algorithm -
when the class is constructed, it takes the file path of the inital
configuration as an input, as well as the file path of the goal
configuration. It has the following fields:
A 'board' object which specifies the inital configuration of the board.
It contains an ArrayList of Block objects(Remember block objects store
the height and width of the block, as well as the address of the
top left corner of block) which specify the starting
blocks, an ArrayList of EmptySpace objects which specify the empty
spaces on the board, an ArrayList of Move objects, which contain
the legal moves of the configuration, and the height and width of
the tray (in this application, the tray will always be 5 x 4).
An ArrayList of Block objects which specify the ending configuration.
A LinkedList of Move objects which specify the shortest possible
list of Moves which brings the configuration to a position which
satisfies the goal position. A Move object has three fields -
The block object being moved, and the row and column of the
top left corner of the block in the new position.
*/
SolverPuzzle test;
try { test = new SolverPuzzle(file, goal); }
catch (IOException ex) {
System.out.println("IOException");
return;
}
Board testBoard = test.getStartBoard();
ArrayList<Block> testGoalBlocks = test.getGoalBlocks();
LinkedList<Move> testMoveSolution = test.getMoveList();
// testing the gui
SolverPuzzleGUI testGUI = new SolverPuzzleGUI(testBoard, testGoalBlocks,
testMoveSolution);
testGUI.runSimulation();
}
} // end class 'SolverPuzzleGUI'
Here's the current output vs desired output.
http://imgur.com/a/ykXXP
So specifically, I have two questions:
1 - Why is the image only showing the top left corners of the blocks instead of the whole block?
2 - Is it better to continue using the GridLayout or switch to GridBagLayout?
Thanks
GridBagLayout would definitely be suitable for want you want to do. For example, you can expand components to envelop more than one column or row - just like what you want to do. Check out the java tutorials for how to use them.
A key point to remember when using GridBagLayoutis that you need to reset the Constraints after each component, assuming that they're unique to that particular component.
Also - I can't discern what you mean by only showing the top-left - it looks likes its showing the whole thing to me...

User-selected marker in time series data in Java

My code plots 5000 points of time series data in a panel that is 581 pixels wide by default, but this width changes when the user resizes the window. My code also plots several rectangular markers that each identify a local maximum/peak in this same space.
I need to enable the user to right click on any of the rectangular-peak-markers so that the user can manually delete any false peak. The problem is that my code is reporting different x-coordinates than expected when the user right-clicks on a peak-marker. I suspect that the reason may have to do with rounding error in converting from 581 x-pixels back to 5000 data indices. But I am not certain of the reason.
Can anyone suggest a solution that enables my users to manually select one of the above-described peak markers by right-clicking on it?
I am enclosing relevant sections of the code below. My actual code is very, very long, and too complicated to post. But the relevant portions below should be enough for someone to see the logic of my approach, and to then suggest a more effective approach.
The code that declares the class in question is:
class SineDraw extends JPanel implements MouseMotionListener, MouseListener {
// lots of code, including the two segments excerpted below
}
This segment of code overloads the paintComponent of the JPanel so that my data is plotted:
// declare some variables
ArrayList<Double> PeakList = new ArrayList<Double>() // this ArrayList is populated by an extraneous process
visiblePoints = 5000
hstep = getWidth()/visiblePoints //=581/5000 by default, but will change when user resizes window
int numPeaks = PeakList.size();
// scale (y-coordinate) data relative to height of panel
pts = new double[visiblePoints]
for (int i = 0; i < pts.length-1; i++){pts[i]=//data vertical scaled to fill panel;}
// plot the 5000 time-series-data-points within the 581 pixels in x-axis
for (int i = 1; i < visiblePoints; i++) {
int x1 = (int) ((i - 1) * hstep);
int x2 = (int) (i * hstep);
int y1 = (int)pts[i - 1];
int y2 = (int)pts[i];
g2.drawLine(x1, y1, x2, y2);
}
// plot a rectangle for each of the local peaks
for(int m=0;m<=(numPeaks-1);m++){
if(i==(int)(PeakList.get(m)){
int currentVal = (int)pts[(int)(PeakList.get(m)];
g2.drawRect((int)(PeakList.get(m), currentVal, 6, 6);
}
}
This section of code is for handling the right-clicking of the mouse:
public void mousePressed(MouseEvent e){
// check to see if right mouse button was clicked
boolean jones = (e.getModifiers()&InputEvent.BUTTON3_MASK)==InputEvent.BUTTON3_MASK;
if(jones==true){
// test the value returned as x-coordinate when user right-clicks (code always underestimates x-coordinate of local peaks by this test)
double ReverseHstep = visiblePoints/getWidth();
int getX_ConvertedTo_i = (int) (e.getX()*ReverseHstep);
System.out.println("getX_ConvertedTo_i is: "+getX_ConvertedTo_i );
// check to see if peaklist contains a value within the x-coordinates of the user-selected-rectangle
if(PeakList.contains((double)(e.getX()-3))
||PeakList.contains((double)(e.getX()-2))
||PeakList.contains((double)(e.getX()-1))
||PeakList.contains((double)(e.getX()))
||PeakList.contains((double)(e.getX()+1))
||PeakList.contains((double)(e.getX()+2))
||PeakList.contains((double)(e.getX()+3))
){
// handling code will go here, but for now it is a print test that never succeeds because x-coordinate is always underestimated
System.out.println("You just selected a peak!");
}
}
repaint();
}
I suggest you create objects (in this case Rectangles) for each thing you want to be clickable. Here is an over-simplified example of how you can make something you draw clickable. The key thing to take away from this is the mouseClicked method which will display a dialog only if the mouse clicked within the rectangle.
One tricky point is that I wasn't able to figure out how to make the rectangle filled in with color without drawing another rectangle over it. I'll leave that one for you ;-)
public class Canvas extends JPanel implements MouseListener{
private Rectangle rect = new Rectangle(100,100);
public Canvas(){
this.addMouseListener(this);
rect.setSize(100, 100);
}
#Override
public void paintComponent(Graphics g){
g.setClip(rect);
g.setColor(Color.RED);
g.fillRect(0, 0, 100, 100);
}
#Override
public void mouseClicked(MouseEvent e){
if(rect.contains(e.getPoint())){
JOptionPane.showConfirmDialog(this, "Click!");
}
}
// The rest of the MouseListener methods have been cut out
public static void main(String[] a){
JFrame frame = new JFrame("Canvas Thingy");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
frame.add(new Canvas());
frame.setVisible(true);
}
}

Categories