I need to change the cursor while it moves over an array-list of rectangles by the contain(p) method.The problem is
My first algorithm to use an iterator to iterate through the rectangles doesn't work as expected.The cursor only changes when hovering over the first rectangle,in the other rectangles neither does it respond by showing the cursor changing nor indicate through the console that the cursor is hovering above them?!!
My second solution also refuses to work properly.I use a for loop to iterate over the rectangles, although the rectangles indicate through the console that the mouse is hovering above them, the cursor refuses to change with the exception of the last rectangle.
I use a JPanel in this SSCCE ,only because it reproduces the problem am encountering using a JTextPane...assuming my coding approach is what is in question.
I am thinking may be I may need to a thread to improve response and performance but not sure about the approach.Thanks in advance people.
public class UnstableCursor extends JPanel{
Rectangle2D rec;
ArrayList<Rectangle2D> recList = new ArrayList<>();
public UnstableCursor(){
}
public static void main(String[] args) {
UnstableCursor uc = new UnstableCursor();
JFrame frame = new JFrame();
Mover mv = new Mover(uc);
uc.addMouseListener(mv);
uc.addMouseMotionListener(mv);
JScrollPane jx = new JScrollPane(uc);
frame.getContentPane().add(jx);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2d = (Graphics2D)g;
int x = 5;
for(int i = 0;i < 4;i++){
g2d.setColor(Color.red);
rec = new Rectangle2D.Double(20,x,100,5);
g2d.draw(rec);
recList.add(rec);
x += 50;
}
System.out.println("RecList is: " +recList.size());
}
}
class Mover extends MouseInputAdapter{
UnstableCursor uc;
Rectangle2D rec;
ArrayList<Rectangle2D> reList;
public Mover(UnstableCursor ucc){
uc = ucc;
}
#Override
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
Point p = e.getPoint();
System.out.println("xxxx");
}
#Override
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
reList = uc.recList;
//System.out.println("List is: "+reList.size());
Iterator <Rectangle2D> recs = reList.iterator();
//--------------------- First Algorithm ----------------------//
if(recs.hasNext()){
rec = recs.next();
if(rec.contains(p)){
System.out.println("inside the rectangle....");
uc.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else{
uc.setCursor(Cursor.getDefaultCursor());
}
}
//--------------------- Second Algorithm ---------------------//
int r = 0;
for(int i = 0;i<(reList.size());i++){
rec = reList.get(r);
//System.out.println("Rect No: "+r+"X: "+rec.getX()+"Y: "+rec.getY());
r++;
if(rec.contains(p)){
System.out.println("inside the rectangle....");
uc.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else{
uc.setCursor(Cursor.getDefaultCursor());
}
}
}
}
the cursor refuses to change with the exception of the last rectangle.
Your basic search algorithm is wrong. Once you find a rectangle that contains the point you should set the cursor and break out of the loop, otherwise the next rectangle you check will not be a match and the cursor will be reset again.
Also...
for(int i = 0;i < 4;i++){
g2d.setColor(Color.red);
rec = new Rectangle2D.Double(20,x,100,5);
g2d.draw(rec);
recList.add(rec);
x += 50;
}
... A painting method is for painting only.
You should NOT be creating rectangles and adding them to the array, since the paintComponent() method is continually called when Swing determines the panel needs to be repainted.
The rectangles should be added to the List in the constructor of your class so each rectangle is only added once.
Related
I'm writing a Swing project in Java and I've recently stumbled upon a problem.
I have a JTable full of objects (car park full of cars) and this piece of code changes the position of 2 elements. If no car was selected, set the coordinates of the first car. On next click, if there already was a car selected, set coordinates of another car. Next, swap the elements with each other and erase the coordinates.
Now, I also have to implement a possibility to "cancel" my selection, e.g. after selecting the first car, if a key is pressed, the selection should be erased. Any ideas how could I do it?
jt.addMouseListener(new java.awt.event.MouseAdapter() {
int y1 = -1;
int x1 = -1;
public void mouseReleased(java.awt.event.MouseEvent e) {
if(x1 == -1 && y1 == -1) {
y1 = jt.rowAtPoint(e.getPoint());
x1 = jt.columnAtPoint(e.getPoint());
}
else {
int y2 = jt.rowAtPoint(e.getPoint());
int x2 = jt.columnAtPoint(e.getPoint());
Car tmp = (Car)carpark[y1][x1];
carpark[y1][x1] = carpark[y2][x2];
carpark[y2][x2] = tmp;
model.fireTableDataChanged();
x1 = -1;
y1 = -1;
y2 = -1;
x2 = -1;
}
}
});
See How to Use Key Bindings.
Here is something to get you started:
InputMap im = table.getInputMap();
ActionMap am = table.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
am.put("cancel", new CancelAction());
CancelAction is defined by:
class CancelAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("esc button pressed ");
}
}
You need a GUI component, like a JTextField, that can register a KeyListener and program the proper action: see the documentation.
Something like:
JTextField tf = new JTextField();
tf.addKeyListener(
new KeyListener() {
void keyPressed(KeyEvent e) {
// your stuff here
}
// other methods must be overriden
}
);
You can register a key listener for other components like buttons and panels as well.
I have looked through Google searches and a few online tutorials and I am still stuck. It seems unfortunately I am stuck using AWT to do this assignment, seeing as Swing would be better. My assignment is to draw a die.
Currently I am stuck just trying to draw a line from corner of the the square to the edge of the die I am trying to draw. I have read that writing on top frames is ill-advised, but I am waiting on my instructor to let me know if I can just implement Swing components instead.
Currently, I can get the square to show, but I can't get the line to show after its supposedly drawn. I have read it is drawn, but hidden under another frame/object/component/something. However, how can I get the line show?
Once I can get the line to show, I can (hopefully) start drawing the die and the put the dots on it. I am only looking to get the lines to show, and not on how to do the assignment!
Any help is appreciated!
CSC 211
Example #3
P r e t t y a s a p i c t u r e
=====================================
Purpose: To demonstrate the graphic capability of Java.
*/
public class Example03
{
//
// The main method is quite simple.
// We instantiate a (graphical) object, and we play with it.
//
public static void main(String[] args)
{
System.out.println("Hi!"); //say hola
Die myPicture = new Die(); //instantiate object Die
myPicture.action(); //call type Die object myPicture's action method
System.out.println("Bye!"); //say goodbye
}
} // end Example03 class
Here is my Die class, it displays the die:
/*
File: Die.java
Defines and implements the class for our "graphical" object.
*/
// To define a keyboard
import java.awt.*; // AWT = "Abstract Window Toolkit"
public class Die extends Frame
{
public final int WIDTH = 70; // Dimension of the rectangle
public final int HEIGHT = 70; // to be drawn on the window
private int xA = 200; // Coordinates of A (top left corner)
private int yA = xA; // trying to make the frame square
private int faceSide = 0; // the die's face side
public Die() //public constructor Die to set initial stuff
{
setTitle("Let's play some dice!"); // We set the characteristics of our
setLocation(200, 200); // drawing window: the location,
setSize(400, 400); // the size, and
setBackground(Color.lightGray); // the color of the background
setVisible(true); // And we make it appear
}
//
// The action method reads the position of the picture from the keyboard and validates the face side
//
public void action()
{
BrainsOfTheOperation brains = new BrainsOfTheOperation(); //instantiate a new object of BrainsOfTheOperation
brains.action(); //call object brain's, type of BrainsOfTheOperation, method's action
xA = brains.returnXCoordinate(); //return object brain's x coordinate
yA = brains.returnYCoordinate(); //return object brain's y coordinate
faceSide = brains.returnFaceSide(); //return object brain's dice face side position
repaint();
}
//
// The only "graphical" method of the class is the paint method.
//
public void paint(Graphics pane)
{
pane.setColor(Color.cyan); // We use black paint to label
pane.drawString("A", xA - 15, yA + 5); // the 2 opposite corners
pane.drawString("B", 175 + 5, 175 + 5); // of our rectangle
pane.setColor(Color.blue); // Gray is darker than light gray
pane.drawRect(175, 175, WIDTH , HEIGHT); // This is for the rectangle
// drawBlank(pane);
}
private void drawBlank (Graphics pane)
{
pane.setColor(Color.cyan); // We use black paint to label
pane.drawString("A", xA - 15, yA + 5); // the 2 opposite corners
// pane.drawString("B", 175 + 5, 175 + 5); // of our rectangle
pane.setColor(Color.blue); // Gray is darker than light gray
pane.drawRect(175, 175, WIDTH , HEIGHT); // This is for the rectangle
}
private void drawDot (Graphics pane)
{
}
private void drawOne (Graphics pane)
{
}
private void drawTwo (Graphics pane)
{
}
private void drawThree (Graphics pane)
{
}
private void drawFour (Graphics pane)
{
}
private void drawFive (Graphics pane)
{
}
private void drawSix (Graphics pane)
{
}
} // end class Die
And finally, my BrainsOfTheOperation class that validates an user's input and then asks for coordinates:
import java.util.Scanner;
public class BrainsOfTheOperation
{
public int xA, yA; //coordinates of where the dice will play
private int faceSide = 0; //what side the dice is showing
private boolean faceSideNotValid = true; //used in a while loop to ensure a correct side is chosen
public BrainsOfTheOperation() //public constructor
{
//left blank
}
public void action() //action method to ask for a face side, valid it, and then ask for the dice's coordinates on a frame
{
Scanner keyboard = new Scanner(System.in); // Instantiating a keyboard scanner
while ( faceSideNotValid )
{
System.out.print("Enter the number on the face of the die: ");
faceSide = keyboard.nextInt(); //take the next integer
testIfValid(); //make sure its valid: if faceSide >= to 1 and faceSide <= 6, return false, to break out of while loop
}
System.out.print("Enter the location of the die: ");
xA = keyboard.nextInt(); // Determines the upper left corner of
yA = keyboard.nextInt(); // the square AKA die
}
private void testIfValid() //declare method testIfValid to test if faceSide integer is a valid number for a die
{
if ( faceSide >= 1 && faceSide <= 6 )
{
faceSideNotValid = false; //set the faceSideNotValid to false to end the while loop
}
else //otherwise, leave the boolean faceSideNotValid true as they haven't entered a correct number
{
System.out.println("Number entered invalid please try again!");
faceSideNotValid = true;
}
}
public int returnXCoordinate() //returns the die's x Coordinate
{
return xA;
}
public int returnYCoordinate()//returns the die's y Coordinate
{
return yA;
}
public int returnFaceSide()//returns the die's face side (location)
{
return faceSide;
}
}//end class BrainsOfTheOperation
Firstly, i am a complete noob at both C# and Java.
So i have been given this assignment to convert a java applet into C#, i have managed to do everything apart from drawing a rectangle on the screen via drag and drop using mouse events.
Whats supposed to happen is when i click and drag my mouse across the screen a rectangle with no fill and white border should appear. The code i have below is just a white screen with a red cross through it, if i comment out the if(action) statement in the form1_Paint then it works but no rectangle so it must be that code that messing it up.
http://gyazo.com/b2506b8c2ea9b304e34172c42ce98aab <-- what it should look like
http://gyazo.com/a8764ac9f5380f0109623d7a7750ddb6 <-- what it actually looks like
[update]
I have now got a rectangle do display but it happens on the MouseUp event rather than creating it as i am dragging my mouse. The obvious next step was to move it to a different mouse event like mouseMove but then it really messes up and created rectangles constantly as i make it bigger. How can i make it constantly resize the rectangle as i drag my mouse and not keep creating rectangles constantly?
The code
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
}
//added load method
private void Form1_Load(object sender, EventArgs e)//runs functions on load
{
init();
start();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (action)
{
xe = e.X;
ye = e.Y;
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
action = true;
// e.consume();
xs = xe = e.X;
ys = ye = e.Y; // starting point y
Form1_MouseMove(sender, e);
this.Invalidate();
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
using (Graphics g = this.CreateGraphics())
{
Pen pen = new Pen(Color.White);
g.DrawRectangle(pen, xs, ys, Math.Abs(xs - xe), Math.Abs(ys - ye));
}
int z, w;
//e.consume();
//xe = e.X;
//ye = e.Y;
if (xs > xe)
{
z = xs;
xs = xe;
xe = z;
}
if (ys > ye)
{
z = ys;
ys = ye;
ye = z;
}
w = (xe - xs);
z = (ye - ys);
if ((w < 2) && (z < 2)) initvalues();
else
{
if (((float)w > (float)z * xy)) ye = (int)((float)ys + (float)w / xy);
else xe = (int)((float)xs + (float)z * xy);
xende = xstart + xzoom * (double)xe;
yende = ystart + yzoom * (double)ye;
xstart += xzoom * (double)xs;
ystart += yzoom * (double)ys;
}
xzoom = (xende - xstart) / (double)x1;
yzoom = (yende - ystart) / (double)y1;
mandelbrot();
this.Invalidate();
//Repaint();
}
The biggest problem in your code is this statement in the Form1_Paint() method:
g1.Dispose();
You should never be disposing the Graphics instance passed to you. It belongs to the framework, not your code. But you should especially never dispose an object that you plan to use later. When you dispose it here, then the Graphics instance isn't valid later on when you try to draw the rectangle.
Note that this is the same as in Java. I hope the original Java code didn't call Graphics.dispose() too!
Some other suggestions:
when creating a new Pen object, add a using statement to ensure the Pen instance you create is disposed properly (you do own that one! :) ). In this case though, you don't need to create a new Pen object...just use the stock Pen provided by .NET. I.e. Pens.White.
you don't appear to be calling Invalidate() in the MouseDown and MouseMove event handlers. You won't get any visual feedback unless you do that, because the Paint event handler won't be called.
Fix the code so it looks like this:
// Little helper method :)
private static void Swap<T>(ref T t1, ref T t2)
{
T temp = t1;
t1 = t2;
t2 = t1;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g1 = e.Graphics;
g1.DrawImage(bitmap, 0, 0, x1, y1);
if (action)
{
//g.setColor(Color.White);
if (xe < xs)
{
Swap(ref xs, ref xe);
}
if (ye < ys)
{
Swap(ref ys, ref ye);
}
g1.DrawRectangle(Pens.White, xs, ys, (xe - xs), (ye - ys));
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
// e.consume();
if (action)
{
xe = e.X;
ye = e.Y;
Invalidate();
//repaint();
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
action = true;
// e.consume();
if (action)
{
xs = xe = e.X;
ys = ye = e.Y;
Invalidate();
}
}
I've had a look here, this doesn't seem to fix my problem, the Invalidate();'s make it stutter and when I have it in Form1_Paint it doesn't draw correctly, either draws before straight onto the form, straight after I've zoomed but doesn't actually appear when I'm dragging in my zoom!
public void paint( Graphics g ) is not painting for double it is painting for string and i want to convert string to double.
So im trying to do a stack calculator and im using linked list to do it with doubles
the part for paint is not doing what i want. And what i want is that i got buttons to hold the adding and dividing etc.. and im trying to punch in a number and it would paint it right away on my window, and its not doing that. And Im using eclipse.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import NumberTree.Ornament;
import java.util.Iterator;
import java.util.LinkedList;
public class StackCalc extends JFrame implements ActionListener {
private LinkedList<Double> values;
double value1 , value2 ;
JTextField theTextField;
JButton boxButton;
public static void main ( String[] args) {
new StackCalc();
}
public StackCalc() {
setDefaultCloseOperation( EXIT_ON_CLOSE );
setLayout( new FlowLayout());
setTitle("StackCalc");
setSize(new Dimension(600,600));
boxButton = new JButton("add");
add(boxButton);
boxButton.addActionListener( this );
boxButton = new JButton("multi");
add(boxButton);
boxButton.addActionListener( this );
boxButton = new JButton("divide");
add(boxButton);
boxButton.addActionListener( this );
boxButton = new JButton("subt");
add(boxButton);
boxButton.addActionListener( this );
theTextField = new JTextField("Write Something ");
add(theTextField);
theTextField.addActionListener( this );
values = new LinkedList<Double>(); // make the stack
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if ( e.getSource()==theTextField ) {
value1 = Double.parseDouble(theTextField.getText());
values.push(value1);
}
}
public void add() {//return nothing
value1=values.pop();
value2=values.pop();
values.push (value1 + value2);
}
public void multi() { //return nothing
value1=values.pop();
value2=values.pop();
values.push (value1 * value2);
}
public void divide() {//return nothing
value1=values.pop();
value2=values.pop();
values.push (value1 / value2);
}
public void subt() {//return nothing
value1=values.pop();
value2=values.pop();
values.push (value1 - value2);
}
public void paint( Graphics g ) {
Iterator it = values.iterator();
while (it.hasNext()) {
double d = (Double)(it.next());
Double d1 = (Double)(it.next());
System.out.println("d="+d + d1 );
super.paint(g);
//((LinkedList) values).paint(g);
//values = LinkedList.paint(g);
g.create(29, 40, 100, 200); // at the bottom of the screen
//g.drawString( value2, 50,420 );
//g.drawString( values, 50,480 );
}
}
You can convert Double to String with String.valueOf(d) and then paint it on the graphics with g.drawString method
There is very little context to the question, making it difficult to provide a suitable answer.
Firstly, each time you call super.paint, you have the potential of clearing what was previously painted, making the entire loop, worthless...
Secondly, you should also avoid magic numbers where possible.
Thirdly, doing a double iteration (it.next) in the loop could cause a `NoSuchElementException
Fourthly, Graphics does not provide any means to paint anything other than a String, so you HAVE to convert the double value to a String value, there is no other choice...
public void paint( Graphics g )
{
super.paint(g);
FontMetrics fm = g.getFontMetrics();
Iterator it = values.iterator();
int width = getWidth();
int height = getHeight();
int y = height;
while (it.hasNext())
{
double d = (Double)(it.next());
y -= fm.getHeight();
String text = NumberFormatter.getNumberFormat().format(d);
int x = width - fm.stringWidth(text);
g.drawString(text, x, y + fm.getAscent());
}
}
You may wish to take a look at 2D Graphics and Working with Text APIs in particular.
Lastly, you should avoid overriding the paint method. If you're overriding this from something like JFrame or Frame, then you should create a custom component (extending from something like JPanel) and place you custom painting there. Apart from anything else, it is double buffered.
I'm fairly new to Java, and using NetBeans IDE 7.0.1.
Problem:
I'm trying to finish up a Java applet I've been working on that requires a pie chart. I've implemented the pie chart, but I've not been able to get the text labels to appear next to the data in the legend. Does anyone have any pointers?
package piechartapplet;
import javax.swing.*;
import java.awt.*;
public class PieChartApplet extends JApplet {
int TotalPieChartSlices = 7;
SliceValues[] pieSlice = new SliceValues[TotalPieChartSlices];
private int pieChartValueY;
public PieChartApplet()
{
//Source for input statisctics:
//Global Issues. (2012). World Military Spending. Retrieved from http://www.globalissues.org/article/75/world-military-spending
// Link: http://www.globalissues.org/article/75/world-military-spending
pieSlice[0] = new SliceValues(41.0, Color.RED,"United States");
pieSlice[1] = new SliceValues(8.2, Color.CYAN,"China");
pieSlice[2] = new SliceValues(4.1, Color.GREEN,"Russia");
pieSlice[3] = new SliceValues(3.6, Color.BLUE,"UK");
pieSlice[4] = new SliceValues(3.6, Color.PINK,"France");
pieSlice[5] = new SliceValues(21.3, Color.ORANGE,"Next 10 Countries Combined");
pieSlice[6] = new SliceValues(18.2, Color.LIGHT_GRAY,"Rest of the World");
}
// drawing the pir chart using the values in the array
public int drawPieChartValues(Graphics2D graphics, Rectangle pieChartArea, SliceValues[] pieSlice)
{
// setting font size/style
Font font = new Font("Arial", Font.BOLD, 24);
graphics.setFont(font);
// Title of Pie Chart
graphics.drawString("World Military Spending (% by Country)", 20, 20);
graphics.setFont(font);
// establishing inital area positioning
pieChartArea.x=10;
pieChartArea.y = 30;
// using the array values, rectangles, and color to draw the slices
for(int i=0; i<pieSlice.length;i++)
{
graphics. setColor(pieSlice[i].getSliceColor());
graphics.fillRect(pieChartArea.x, pieChartArea.y, 15, 10);
graphics.setColor(Color.BLACK);
pieChartArea.y+=20;
graphics.drawString(""+pieSlice[i].getSliceValue(), pieChartArea.x+25, pieChartArea.y-10);
}
return pieChartArea.y+=10;
}
//The code below was adapted from an example I found that enables me to pull from
// the array and use the values as the slice sizes, putting them into a 360* pie
// Walker, K. (2012). How to Draw a Pie Chart in Java. Retrieved from http://www.ehow.com/how_6647263_draw-pie-chart-java.html
public void drawPieChart(Graphics2D graphics, Rectangle pieChartArea, SliceValues[] pieSlice) {
// pulling array data for the individual slices
double total = 0.0;
for (int i=0; i<pieSlice.length; i++)
{
total += pieSlice[i].getSliceValue(); //pulling value
}
// drawing the slice and positioning it accordingly
double slice = 0.0D;
int StartAngle = 0;
pieChartArea.x = 20;
for (int i=0; i<pieSlice.length; i++) {
// finding initial and final angels
StartAngle = (int)(slice * 360 / total);
int finalAngle = (int)(pieSlice[i].getSliceValue() * 360 / total);
//loop for last slice
if (i == pieSlice.length-1)
{
finalAngle = 360 - StartAngle;
}
// Pulling color from array and setting accordingly
graphics.setColor(pieSlice[i].getSliceColor()); //pulling color
// drawing pie piece
graphics.fillArc(pieChartArea.x, pieChartValueY, pieChartArea.width/2, pieChartArea.height/2, StartAngle, finalAngle);
slice += pieSlice[i].getSliceValue();
}
}
public void paint(Graphics g)
{
super.paint(g);
pieChartValueY = drawPieChartValues((Graphics2D)g, getBounds(), pieSlice);
drawPieChart((Graphics2D)g, getBounds(), pieSlice);
}
public void init() {
// Sizing my applet
setSize(600,600);
// adding applet to pane
getContentPane().add(new PieChartApplet());
}
}
Here is the 'values' code
package piechartapplet;
import javax.swing.*;
import java.awt.*;
public class SliceValues
{
// Establishing values for the pir chart
private double Slicevalue;
private Color Slicecolor;
private String Slicestring;
// Construction begins...
public SliceValues(double value, Color color, String string) {
this.Slicevalue = value; //values from array
this.Slicecolor = color; //color from array
this.Slicestring = string; //string values
}
// calling slice values, colors, strings, and setting values, colors, strings for each slice
public double getSliceValue() {
return Slicevalue;
}
public void setSliceValue(double value) {
this.Slicevalue = value;
}
public Color getSliceColor() {
return Slicecolor;
}
public void setSliceColor(Color color) {
this.Slicecolor = color;
}
public String getSliceString() {
return Slicestring;
}
public void setSliceString(String string) {
this.Slicestring = string;
}
}
The source code for PieChartDemo1, illustrated here with labels, is included in the distribution.