extends javax.swing.JTextField......
A better version and standalone instead of previus ...
~1000 code lines,,3 classes
for easy creating ...." like mspaint" applications
https://drive.google.com/file/d/1K-S2h-s3bbOdQS6-Zmnmx56p7Pop0eji/view?usp=sharing
The main problem to create a paint application is the complexity.
So user must have as less as i can ,,of swing Components to asjust the Image.
Thats why preparing this class.
To avoid ,as an example, having 4 JTextFields for some Rectangle that we painting.
Read LAST the main to understand
/*
* Tsoukalas I. Dimitrios jimakoskx@hotmail.com
*/
package jdoublemousedriverfield;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Path2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
/**
*
* @author jimis
* @date 14 Απρ 2022
*/
public class JdoubleMouseDriverField extends JTextField implements Stepable{
public static void main(String[] args) {
Vector<Class> vClasses=new Vector();
Vector<Shape> vShapes=new Vector();
vShapes.add(new java.awt.geom.Arc2D.Double(100,0,100,100,45,270,2));
vClasses.add(java.awt.geom.Arc2D.Double.class);
vShapes.add(new java.awt.geom.CubicCurve2D.Double(0,0,400,400,0,400,300,0));
vClasses.add(java.awt.geom.CubicCurve2D.Double.class);
vShapes.add(new java.awt.geom.Ellipse2D.Double(100,200,200,100));
vClasses.add(java.awt.geom.Ellipse2D.Double.class);
vShapes.add(new java.awt.geom.Line2D.Double(100,100,200,200));
vClasses.add(java.awt.geom.Line2D.Double.class);
vShapes.add(new java.awt.geom.QuadCurve2D.Double(400,400,0,0,0,400));
vClasses.add(java.awt.geom.QuadCurve2D.Double.class);
vShapes.add(new java.awt.geom.Rectangle2D.Double(10,10,100,100));
vClasses.add(java.awt.geom.Rectangle2D.Double.class);
vShapes.add(new java.awt.geom.RoundRectangle2D.Double(20,20,80,80,40,20));
vClasses.add(java.awt.geom.RoundRectangle2D.Double.class);
JList<Shape> jli=new JList<>(vShapes);
jli.putClientProperty("type",0);
JPanel jpDraw=new JPanel(){
public void paintComponent(Graphics gr){
super.paintComponent(gr);
Graphics2D g=(Graphics2D)gr;
int i=0,l=vShapes.size();
while(i<l){
g.draw(vShapes.get(i));
++i;
}
}
};
Vector <Constructor> vCons=new Vector<>();
Vector<JdoubleMouseDriverField>vDrivers=new Vector<>();
Vector<String> vFieldsNamesStrings=new Vector<>();
Vector<Vector<Field>> vVFields=new Vector<>();
//JComboBox<String> jcmb=new JComboBox<>();
Class cl;
Constructor con;
JdoubleMouseDriverField jtest;
int i=0,l=vClasses.size();
Class paramsNull[]=null;
JTextField jtfFieldValues=new JTextField();
try{
while(i<l){
cl=vClasses.get(i);
con=cl.getConstructor(paramsNull);
System.out.println(""+con);
Field fs[]=cl.getDeclaredFields();
int j=0;
String fsnames="";
Vector<Field> vfs=new Vector<>();
while(j<fs.length){
if(fs[j].getType()==double.class){
fsnames+=fs[j].getName()+",";
vfs.add(fs[j]);
//System.out.println(j+" "+fs[j].getName()+" , "+fs[j].getType());
}
++j;
}
vFieldsNamesStrings.add(fsnames);
vVFields.add(vfs);
vCons.add(con);
jtest=new JdoubleMouseDriverField(fs.length-1){
@Override
public boolean setValueAtIndex(int index, double neo) {
boolean outfromsuper= super.setValueAtIndex(index, neo);
Shape sh=jli.getSelectedValue();
if(sh!=null){
int type=(int)jli.getClientProperty("type");
Vector<Field> vFs=vVFields.get(type);
Field field=vFs.get(index);
//System.out.println("type->"+type+" field:"+index+" "+field.getName());
try{
field.set(sh, neo);
jpDraw.repaint();
}catch(Exception e){
e.printStackTrace();
}
}
jtfFieldValues.setText(this.valuesText);
return outfromsuper;
}
};
jtest.invert(1).invert(3);//all
jtest.qArrowColor(new Color(cl.getName().hashCode()));
vDrivers.add(jtest);
//jcmb.addItem(cl.getName());
++i;
}
}catch(Exception e){
e.printStackTrace();
}
//invert also some other indexes
vDrivers.get(1).invert(5).invert(7);//CubicCurve ys
vDrivers.get(4).invert(5);//QuadCurve ys
JButton jbNew=new JButton("new copy selected");
JButton jbRemove=new JButton("remove");
JPanel jplinorth=new JPanel(new BorderLayout());
jplinorth.add(BorderLayout.WEST,jbNew);
jplinorth.add(BorderLayout.EAST,jbRemove);
//jplinorth.add(BorderLayout.CENTER,jcmb);
JPanel jplisouth=new JPanel(new BorderLayout());
JTextField jtfFieldNames=new JTextField();
jtfFieldNames.setEditable(false);
jtfFieldValues.setEditable(false);
JPanel jpli=new JPanel(new BorderLayout());
jpli.add(BorderLayout.CENTER,new JScrollPane(jli));
jpli.add(BorderLayout.NORTH,jplinorth);
jpli.add(BorderLayout.SOUTH,jplisouth);
jli.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
Shape sh=jli.getSelectedValue();
if(sh!=null){
Class cl=sh.getClass();
int clind=vClasses.indexOf(cl);
if(clind>-1){
jli.putClientProperty("type",clind);
jplisouth.removeAll();
JdoubleMouseDriverField jtestToBeSetted=vDrivers.get(clind);
jplisouth.add(BorderLayout.CENTER,jtestToBeSetted);
jtfFieldNames.setText(vFieldsNamesStrings.get(clind));
jplisouth.add(BorderLayout.SOUTH,jtfFieldNames);
jplisouth.validate();
jplisouth.repaint();
///////////////////
Vector<Field> vFs=vVFields.get(clind);
int i=0;
double val;
while(i<vFs.size()){
try{
val=vFs.get(i).getDouble(sh);
//System.out.println(i+" : "+val);
jtestToBeSetted.setValueAtIndex(i, val);
}catch(Exception ex){
ex.printStackTrace();
}
++i;
}
}
}
}
});
jli.setSelectedIndex(0);
JFrame jfr=new JFrame("src @.jar - test/show JdoubleMouseDriverField.class - Right (or left/middle) press on ARROWS !");
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfr.setBounds(0,0,888,555);
JPanel jpEdit=new JPanel(new BorderLayout());
JSplitPane jspl=new JSplitPane(1,jpli,jpDraw);
jfr.getContentPane().add(BorderLayout.CENTER,jspl);
jfr.getContentPane().add(BorderLayout.SOUTH,jtfFieldValues);
jfr.setVisible(true);
jbNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
Shape selShape=jli.getSelectedValue();
if(selShape!=null){
int type=(int)jli.getClientProperty("type");
Object nullParams[]=null;
try{
Shape neoShape=(Shape)vCons.get(type).newInstance(nullParams);
//System.out.println(selShape+" , "+neoShape);
Vector<Field> vFs=vVFields.get(type);
int i=0;
Field ff;
while(i<vFs.size()){
ff=vFs.get(i);
double val=ff.getDouble(selShape);
ff.set(neoShape, val+10);
//System.out.println(i+" setted "+val);
++i;
}
vShapes.add(neoShape);
jli.setListData(vShapes);
jli.setSelectedIndex(vShapes.size()-1);
jli.ensureIndexIsVisible(jli.getSelectedIndex());
}catch(Exception ee){
ee.printStackTrace();
}
}
}
});
jbRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
int ind=jli.getSelectedIndex();
if(ind>6){
vShapes.remove(ind);
jli.setListData(vShapes);
if(ind<vShapes.size()){
}
else{
--ind;
}
if(ind>-1){
jli.setSelectedIndex(ind);
jli.ensureIndexIsVisible(ind);
}
}
else{
JOptionPane.showMessageDialog(jli, "Use this as prototype.Cant remove");
}
}
});
}
protected static final Stepper stepThread=new Stepper(100);
protected static final ComponentListener jtfCL=new ComponentListener() {
@Override
public void componentResized(ComponentEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfcomponentResized(e);
}
@Override
public void componentMoved(ComponentEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfcomponentMoved(e);
}
@Override
public void componentShown(ComponentEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfcomponentShown(e);
}
@Override
public void componentHidden(ComponentEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfcomponentHidden(e);
}
};
protected static final MouseListener jtfML=new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseClicked(e);
}
@Override
public void mousePressed(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmousePressed(e);
}
@Override
public void mouseReleased(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseReleased(e);
}
@Override
public void mouseEntered(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseEntered(e);
}
@Override
public void mouseExited(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseExited(e);
}
};
protected static final MouseMotionListener jtfMML=new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseDragged(e);
}
@Override
public void mouseMoved(MouseEvent e) {
((JdoubleMouseDriverField)e.getComponent()).jtfmouseMoved(e);
}
};
protected double[] values;
protected double[] valuesMin;
protected double[] valuesMax;
protected double[][] valuesDefAndDifs;//default, dif normal, dif small,dif Big
protected boolean[] inverted;
protected float[] valuesDrawingWidthPercentage;
protected int[] valuesDrawingWidthActual;
protected boolean[] valuesDrawingVertical;
public static final int decr=0;
public static final int incr=1;
protected Color[][] valuesColor;
protected Path2D[][] valuesPath;
public JdoubleMouseDriverField(){
this(2);
}
public JdoubleMouseDriverField(int size){
this(size,false);
}
public JdoubleMouseDriverField(int size,int orientationOfFirstArrows){
this(size,orientationOfFirstArrows,false);
}
public JdoubleMouseDriverField(int size,boolean nextOrientationSame){
this(size,JSplitPane.HORIZONTAL_SPLIT,nextOrientationSame);
}
public JdoubleMouseDriverField(int size,int orientationOfFirstArrows,boolean nextOrientationSame){
constructingJNumbersField0(size, orientationOfFirstArrows, nextOrientationSame);
resetTextFromCurrentValues();
qCursorCrossHair();
stepThread.checkToStart();
super.addComponentListener(jtfCL);
super.addMouseListener(jtfML);
super.addMouseMotionListener(jtfMML);
}
protected void initilisingArrays(int size){
values=new double[size];
values=new double[size];
valuesDefAndDifs=new double[4][size];
valuesMin=new double[size];
valuesMax=new double[size];
inverted=new boolean[size];
valuesColor=new Color[2][size];
valuesPath=new Path2D[2][size];
valuesDrawingWidthPercentage=new float[size];
valuesDrawingWidthActual=new int[size];
valuesDrawingVertical=new boolean[size];
}
protected void constructingJNumbersField0(int size,int orientationOfFirstArrows,boolean nextOrientationSame){
size=Math.max(1, size);
initilisingArrays(size);
int i=0;
boolean verticalArrows=orientationOfFirstArrows==JSplitPane.VERTICAL_SPLIT;
while(i<size){
values[i]=createDefaultValue(i);
valuesDefAndDifs[0][i]=(createDefaultValue(i));
valuesDefAndDifs[MouseEvent.BUTTON1][i]=(createDefaultValueDif(i));
valuesDefAndDifs[MouseEvent.BUTTON2][i]=(createDefaultValueDifSmall(i));
valuesDefAndDifs[MouseEvent.BUTTON3][i]=(createDefaultValueDifBig(i));
valuesMin[i]=(createDefaultValueMin(i));
valuesMax[i]=(createDefaultValueMax(i));
inverted[i]=(createDefaultInverted(i));
valuesColor[decr][i]=(createDefaultValueArrowColorDecr(i));
valuesColor[incr][i]=(createDefaultValueArrowColorIncr(i));
valuesPath[decr][i]=(createDefaultValueArrowPathDecr(i));
valuesPath[incr][i]=(createDefaultValueArrowPathIncr(i));
valuesDrawingWidthPercentage[i]=(createDefaultValuesDrawingWidthPercentage(i));
valuesDrawingWidthActual[i]=(50);//some default actual width
valuesDrawingVertical[i]=(verticalArrows);
if(!nextOrientationSame){
verticalArrows=!verticalArrows;
}
++i;
}
}
public double createDefaultValue(int index){
return 0.0;//Math.random();
}
public double createDefaultValueDefault(int index){
return 0.0;
}
public double createDefaultValueDif(int index){
return 1.0;
}
public double createDefaultValueDifBig(int index){
return 10.0;
}
public double createDefaultValueDifSmall(int index){
return 0.1;
}
public double createDefaultValueMax(int index){
return Integer.MAX_VALUE;
}
public double createDefaultValueMin(int index){
return Integer.MIN_VALUE;
}
public boolean createDefaultInverted(int index){
return false;
}
public double createDefaultValueDirectionIncreaseMultiplier(int index){
return 1.0;
}
public static Color defArrowColor=new Color(255,0,0,90);
public Color createDefaultValueArrowColorIncr(int index){
return defArrowColor;
}
public Color createDefaultValueArrowColorDecr(int index){
return defArrowColor;
}
public Path2D createDefaultValueArrowPathIncr(int index){
return new Path2D.Double();
}
public Path2D createDefaultValueArrowPathDecr(int index){
return new Path2D.Double();
}
public float createDefaultValuesDrawingWidthPercentage(int index){
float out=1f;
out/=values.length;
return out;
}
public String createTextForCurrentValues(){
String out="";
int i=0;
int l=values.length-1;
while(i<l){
out+=getTextForValue(i)+" , ";
++i;
}
out+=getTextForValue(i);
return out;
}
/**
* Override with some formatter etc...
* @param index
* @return double as it is
*/
public String getTextForValue(int index){
return values[index]+"";//String.format("%.2f", val);
}
protected String valuesText="";
/**
* Not seting JTextField text <br>
* because supposed to be as minimised as application wants<br>
* to not trigger some JScrollPane<br>
* This is the purpose of class<br>
* Arrows always visble to user to press them<br>
* If want values visible then override<br>
* or override making some call to setText for other JTextFields...<br>
*
* But because of this (no text in JTextField)<br>
* may need to call setPrefferedSize(some min dimention) to ensure is visble
*/
public void resetTextFromCurrentValues(){
valuesText=createTextForCurrentValues();
setToolTipText(valuesText);
//setText(valuesText);
}
public JdoubleMouseDriverField q(Cursor cursor) {super.setCursor(cursor); return this;}
public JdoubleMouseDriverField qCursorCrossHair() {super.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); return this;}
public JdoubleMouseDriverField qCursorHand() {super.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); return this;}
public JdoubleMouseDriverField qCursorMove() {super.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); return this;}
public JdoubleMouseDriverField qCursorText() {super.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); return this;}
public JdoubleMouseDriverField qCursorWait() {super.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); return this;}
public JdoubleMouseDriverField qArrowColor(Color c){
int i=0;
int l=values.length;
while(i<l){
valuesColor[decr][i]=c;
valuesColor[incr][i]=c;
++i;
}
return this;
}
public JdoubleMouseDriverField invert(int ind){
inverted[ind]=!inverted[ind];
return this;
}
protected int prw=0,prh=0;
protected long prwhchanged=0,prwhtimegap=100;
protected void jtfcomponentResized(ComponentEvent e) {
int nw=getWidth();
int nh=getHeight();
long ct=System.currentTimeMillis();
if((nw!=prw || nh!=prh)&&(ct-prwhchanged>prwhtimegap)){
int hmiddle=nh/2;
int hmup=hmiddle;
int hmdown=hmiddle+1;
int i=0,l=values.length;
float percentwidth;
int prevwidth=0;
int actualwidth;
int totalwidth=0;
Path2D p;
while(i<l){
percentwidth=valuesDrawingWidthPercentage[i];
actualwidth=(int)(percentwidth*nw);
totalwidth+=actualwidth;
valuesDrawingWidthActual[i]=actualwidth;
if(valuesDrawingVertical[i]){
p=valuesPath[decr][i];
p.reset();
p.moveTo(prevwidth,hmdown);
p.lineTo(prevwidth+actualwidth, hmdown);
p.lineTo(prevwidth+actualwidth/2, nh);
p.closePath();
p=valuesPath[incr][i];
p.reset();
p.moveTo(prevwidth,hmup);
p.lineTo(prevwidth+actualwidth, hmup);
p.lineTo(prevwidth+actualwidth/2, 0);
p.closePath();
}
else{
p=valuesPath[decr][i];
p.reset();
p.moveTo(-1+prevwidth+actualwidth/2,0);
p.lineTo(-1+prevwidth+actualwidth/2, nh);
p.lineTo(prevwidth, hmiddle);
p.closePath();
p=valuesPath[incr][i];
p.reset();
p.moveTo(prevwidth+actualwidth/2,0);
p.lineTo(prevwidth+actualwidth/2, nh);
p.lineTo(prevwidth+actualwidth, hmiddle);
p.closePath();
}
prevwidth+=actualwidth;
++i;
}
//int remains=nw-totalwidth;
//System.out.println(""+valuesDrawingWidthActual);
//System.out.println("Remains "+remains+" / "+nw);
prw=nw;
prh=nh;
prwhchanged=System.currentTimeMillis();
repaint();
}
//else{
//if(nw==prw || nh==prh){System.out.println("Skipping "+prw+","+prh+" -> "+nw+","+nh);}
//else{System.out.println("Skipping from timegap avoiding overworking");}
//}
}
protected void jtfcomponentMoved(ComponentEvent e) {
}
protected void jtfcomponentShown(ComponentEvent e) {
System.out.println("componentShown");
}
protected void jtfcomponentHidden(ComponentEvent e) {
System.out.println("componentHidden");
}
@Override
protected void paintComponent(Graphics gr) {
super.paintComponent(gr);
Graphics2D g=(Graphics2D)gr;
int i=0,l=values.length;
while(i<l){
g.setColor(valuesColor[decr][i]);
g.fill(valuesPath[decr][i]);
g.setColor(valuesColor[incr][i]);
g.fill(valuesPath[incr][i]);
++i;
}
}
public static int encode(boolean decr,int i){
if(decr){
i++;
i=-i;
}
return i;
}
/**
*
* @param xonjtf
* @param yonjtf
* @return values.length if not found<br>
* or the normal index if found on INCREASING array([1]) <br>
* or -1-index if found to DECREASING arra([0])
*/
public int getIndexOfPathContains(int xonjtf,int yonjtf){
int i=0,l=values.length;
while(i<l){
int j=0;
while(j<2){
if(valuesPath[j][i].contains(xonjtf, yonjtf)){
return encode(j==0, i);
}
++j;
}
++i;
}
return l;
}
private int steppingJ,steppingI;
private int buttonPressed;
private boolean isNowDragging;
private boolean isMultiplying;
private synchronized void setStepperJIAndUnpausedIfPaused(int j,int i){
steppingJ=j;
steppingI=i;
stepThread.setStepable(this);
stepThread.unpauseIfPaused();
}
public synchronized void executeNextStep(){
int i,j;
i=steppingI;//sync?
j=steppingJ;//sync?
double neo=values[i];
double dif=valuesDefAndDifs[buttonPressed][i];
if(j==0){//decreasingArrow
dif=-dif;
}
if(inverted[i]){
dif=-dif;
}
if(isMultiplying){
dif*=10;
}
neo+=dif;
setValueAtIndex(i, neo);
System.out.println(values[i]+" from stepping! ["+j+"]["+i+"]");
}
public boolean setValueAtIndex(int index,double neo){
if(neo>=valuesMin[index] && neo<=valuesMax[index]){
values[index]=neo;
resetTextFromCurrentValues();
return true;
}
else{
System.out.println("not accepted");
return false;
}
}
protected void jtfmouseClicked(MouseEvent e) {
//System.out.println(" clicked ");
}
protected void jtfmouseEntered(MouseEvent e) {
//System.out.println("entered");
}
protected void jtfmouseExited(MouseEvent e) {
//System.out.println("exited");
stepThread.setPaused();//in case arrows path are ...strange!
}
protected void jtfmouseMoved(MouseEvent e) {
}
protected void jtfmousePressed(MouseEvent e) {
//System.out.println("pressed "+e.getWhen());
int but=e.getButton();
if(but<valuesDefAndDifs.length && but >0){
buttonPressed=but;
isNowDragging=true;
int pathIndexEncodedPressed=getIndexOfPathContains(e.getX(),e.getY());
if(pathIndexEncodedPressed<values.length){
int pathJPressed=1;
int pathIPressed=pathIndexEncodedPressed;
if(pathIndexEncodedPressed<0){
pathJPressed=0;
pathIPressed=-(pathIndexEncodedPressed+1);
}
setStepperJIAndUnpausedIfPaused(pathJPressed, pathIPressed);
}//else{System.out.println("pressed outside of all paths");}
}//else{System.out.println("Not acceptable button "+but);}
}
protected void jtfmouseReleased(MouseEvent e) {
//System.out.println("released "+e.getWhen());
if(e.getButton()==buttonPressed){
isNowDragging=false;
stepThread.setPaused();
}
}
protected void jtfmouseDragged(MouseEvent e) {
if(isNowDragging){
int pathIndexEncodedDragged=getIndexOfPathContains(e.getX(),e.getY());
if(pathIndexEncodedDragged<values.length){
int pathJDragged=1;
int pathIDragged=pathIndexEncodedDragged;
if(pathIndexEncodedDragged<0){
pathJDragged=0;
pathIDragged=-(pathIndexEncodedDragged+1);
}
setStepperJIAndUnpausedIfPaused(pathJDragged, pathIDragged);
}
else{
stepThread.setPaused();
}
}
}
}
interface Stepable {
public void executeNextStep();
}
class Stepper extends Thread{
private Stepable src;
private long steptime;
private long pausedtime;
private boolean paused;
private final Object locker=new Object();
public Stepper(long sleepStep,long sleepPaused){
super();
super.setDaemon(true);
steptime=sleepStep;
pausedtime=sleepPaused;
paused=true;
}
public Stepper(long sleepStep){
this(sleepStep,3600000);
}
public Stepper(){
this(1000);
}
private boolean hasStarted=false;
public synchronized void checkToStart(){
if(!hasStarted){
start();
}
}
@Override
public synchronized void start() {
hasStarted=true;
super.start();
}
public void run(){
while(true){
if(paused){
try{
sleep(pausedtime);
}catch(InterruptedException inter){
//System.out.println("Stepper unpaused from big sleep "+inter);
}
}
else{
synchronized(locker){
if(src!=null){
src.executeNextStep();
try{
sleep(steptime);
}catch(InterruptedException inter){
//System.out.println("????? Stepper ???? interrupted on unpaused ?");
//means slept after step,made paused ,and unpaused before wake from sleep after step
//inter.printStackTrace();
}
}
else{
paused=true;
}
}
}
}
}
public void setStepable(Stepable somesrc){
if(src!=somesrc){
synchronized(locker){
src=somesrc;
}
}
}
public void unpauseIfPaused(){
if(paused){
paused=false;
interrupt();
}
}
public void setPaused(){
paused=true;
}
}