Chander,
This sounds like a school assignment. What have you tried so far?
We can help, but can't do your assignment for you. Jurtle has a
"Flower.java" example that might give you some ideas, but it does use
Jurtle's turtle graphics library.
Bill
On Jun 22, 2005, at 3:14 PM, chander2010 wrote:
> Hi
>
> I need to draw a flower or something, which looks like beauty.
> with different radius and degrees in Applet,
>
> the no of petals varies, so each petal shouldnot overlap on other
> petal.
>
> please help me.
>
> thanks in advance
> Chander
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Hi
I need to draw a flower or something, which looks like beauty.
with different radius and degrees in Applet,
the no of petals varies, so each petal shouldnot overlap on other
petal.
please help me.
thanks in advance
Chander
Now that Jurtle 1.8 is out, I am thinking about the next version. I
would like to revamp the lessons/tutorial that comes with Jurtle.
I'd appreciate any feedback you could give me on the current lessons.
1. Did you successfully complete them?
2. Too hard or too easy?
3. Any concepts that seemed particularly difficult for you to
understand from the lessons?
4. Anything you'd like to see added to the lessons?
5. Any further comments?
I really would appreciate your taking the time to respond.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Otherwise has released version 1.8 of Jurtle, its educational IDE for
learning to program using Java.
With this release, Jurtle integrates with the LeJOS API for
programming the LEGO Mindstorms Robotic system using Java. You can
write, compile and download your Java code for the Mindstorms robots
all from within the Jurtle IDE.
This is a free update for registered users.
Release Notes: <http://www.otherwise.com/Jurtle/ReleaseNotes.html>
Download: <http://www.otherwise.com/Jurtle/Download.html>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
If you are a Mac user and have a problem running Jurtle after the
10.3.9 Mac OS X update, this is known problem that is affecting some
people. It looks like Apple really messed something up with this
update. The problem affects all Java applications, not just Jurtle.
So, If you upgrade to 10.3.9, and Java stops working, then you should
download and install the following security update:
http://www.apple.com/support/downloads/
securityupdate2005002macosx1034orlater.html
It has been reported on numerous mailing lists that this should fix
things again. I have at least one customer that has verified it worked
for him.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Good suggestion John. I will put it on the list for the next release.
Bill
On Feb 22, 2005, at 3:37 AM, John Kirkilis wrote:
>
> It would be helpful to be able to have a "Save Display As..." menu item
> under the file menu with the option to save it in a common graphics
> format or to have a toolbar button to copy the display panel to the
> system clipboard. The student could then paste it into their word
> processor or any other software for that matter.
>
> Thanks,
>
> John Kirkilis
> Austin Waldorf School
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
It would be helpful to be able to have a "Save Display As..." menu item
under the file menu with the option to save it in a common graphics
format or to have a toolbar button to copy the display panel to the
system clipboard. The student could then paste it into their word
processor or any other software for that matter.
Thanks,
John Kirkilis
Austin Waldorf School
Bill,
You're darn right it's annoying... when it works. I'd love to experience
the annoyance at this point. This incarnation is a harness for learning
and testing. I intend to provide my students with an easy way to load
sounds and images, in moderation of course, and play them on certain
events, such as when a Turtle smacks into another Turtle, a wall, or
some other object, which means collision detection is in the offing. Yikes!
I wrote another version that uses the javax.audio.sampled code, even in
separate threads, and I still encounter problems. I stumbled across this
bug report which resonates with my experience:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5085008
I'll need to test my code on 1.4.x. I'm finding that 1.5 on Win2K or
WinXP only play some encodings.
The annoying bong.wav file is WAVE (.wav) file, byte length: 12490, data
format: ULAW 8000.0 Hz, 8 bit, mono, 1 bytes/frame, , frame length: 12446
The other files I'm trying are WAVE (.wav) file, byte length: 276592,
data format: PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame,
little-endian, frame length: 138274
I'll convert some of these sounds in a sound editor to ULAW 8-bit, 8kHz
and see what happens. By the way, do I just need to change the JAVA_HOME
environment variable to make Jurtle use a different version of the JDK
and JRE?
If you want to see the hideous development version that this has become,
check out the enclosed file. It uses a file chooser dialog to pick a
couple "annoying" sounds.
As always, thanks for taking the time. I'm having a blast and am
probably experiencing a relapse JurtleMania.
John
Bill Tschumy wrote:
> John,
>
> On Mac OS X, the sounds appear to play to completion assuming they are
> not preempted by another sound. I didn't try it on Windows. Despite
> the fact that the JavaDoc for AudioClip says:
>
> "Multiple AudioClip items can be playing at the same time, and the
> resulting sound is mixed together to produce a composite.",
>
> I don't think this is true. It has been my experience in the past that
> attempting to play a second sound will preempt the first.
>
> I even tried starting the sounds in different threads, but that didn't
> help.
>
> BTW: that is one annoying little program when both the movement sound
> and the turning sound are being played <g>.
>
> Bill
>
> On Feb 19, 2005, at 8:19 PM, John Kirkilis wrote:
>
> > Hi folks,
> >
> > I need some help figuring out why my MediaTurtle class is having
> > trouble
> > playing sounds. I did some searching and found references to platform
> > specific problems with the AudioClip class and JDKv5. If any Jurtle
> > users out there are so inclined, could you download the enclosed files
> > into a Jurtle folder and try to run the MediaTurtle class. If you look
> > at the test runTurtle method, there are several method calls to tell
> > the
> > MediaTurtle the names of the files containing the replacement Turtle
> > image as well as sounds for movement, turning, and creation. You can
> > use
> > your own sounds as well, but it appears that only certain resolutions
> > and sample rates are allowed. I'm trying to avoid getting into the
> > javax.sound.sampled classes right now and get by with AudioClips.
> >
> > Do you here sound when you run MediaTurtle? Do the sounds appear to
> > play
> > to completion or are they getting cut-off?
> >
> > Thanks,
> >
> > John Kirkilis
> > Austin Waldorf School
> --
> Bill Tschumy
> Otherwise -- Austin, TX
> http://www.otherwise.com
>
>
> *Yahoo! Groups Sponsor*
>
<http://us.ard.yahoo.com/SIG=1296lhn3o/M=324658.6070095.7083352.3001176/D=groups\
/S=1705006905:HM/EXP=1108956966/A=2343726/R=0/SIG=12i5vnmh2/*http://clk.atdmt.co\
m/VON/go/yhxxxvon01900091von/direct/01/&time=1108870566063041>
>
>
> Get unlimited calls to
>
> U.S./Canada
>
>
<http://us.ard.yahoo.com/SIG=1296lhn3o/M=324658.6070095.7083352.3001176/D=groups\
/S=1705006905:HM/EXP=1108956966/A=2343726/R=1/SIG=12i5vnmh2/*http://clk.atdmt.co\
m/VON/go/yhxxxvon01900091von/direct/01/&time=1108870566063041>
>
>
>
> ------------------------------------------------------------------------
> *Yahoo! Groups Links*
>
> * To visit your group on the web, go to:
> http://groups.yahoo.com/group/jurtle-users/
>
> * To unsubscribe from this group, send an email to:
> jurtle-users-unsubscribe@yahoogroups.com
> <mailto:jurtle-users-unsubscribe@yahoogroups.com?subject=Unsubscribe>
>
> * Your use of Yahoo! Groups is subject to the Yahoo! Terms of
> Service <http://docs.yahoo.com/info/terms/>.
>
>
/*
* File: MediaTurtle3chooser.java
* Original Author: John Kirkilis -- Austin Waldorf School
*
* This Turtle provides additional capabilities for Jurtle programmers.
* A subclass can set the turtleImage by specifying the name of the image file.
* In addition a turtle creation sound, movement sound, and turning sound can be
* set as well. The image and sounds can be changed at runtime as the programmer
* desires.
*/
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import com.otherwise.jurtle.*;
import java.util.Random;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.awt.geom.AffineTransform;
import javax.sound.sampled.*;
import java.io.*;
public class MediaTurtle3chooser extends Turtle
{
boolean verbose = true;
boolean beepMode = false;
Image turtleImage = null;
Clip turtleCreationSound, turtleMovementSound, turtleTurnSound;
private BufferedImage bi;
private Graphics2D biContext;
int imgWidth;
int imgHeight;
ClassLoader loader = getClass().getClassLoader();
Toolkit tk = Toolkit.getDefaultToolkit();
public void setTurtleImage ( String theFileName )
{
turtleImage = null;
if ( verbose )
Console.println( "In setTurtleImage, fname=" + theFileName );
if ( theFileName != null )
{
// grab our Turtle image
if ( verbose )
Console.println( "Pre image load..." );
URL imageURL = loader.getResource( theFileName );
if ( imageURL != null )
{
turtleImage = Toolkit.getDefaultToolkit().getImage( imageURL );
JPanel disp = getDisplay();
MediaTracker mt = new MediaTracker( disp );
if ( verbose )
Console.println( "After mediatracker..." );
try
{
mt.addImage( turtleImage, 0 );
mt.waitForID( 0 );
}
catch ( InterruptedException e )
{
turtleImage = null;
if ( verbose )
Console.println( "In catch" );
}
if ( verbose )
Console.println( "After catch" );
imgWidth = turtleImage.getWidth( disp );
imgHeight = turtleImage.getHeight( disp );
bi = new BufferedImage( imgWidth, imgHeight,
BufferedImage.TYPE_INT_ARGB );
biContext = bi.createGraphics();
if ( verbose )
Console.println( "After biContext" );
}
}
}
public void playSound ( Clip clip )
{
// Start playing
if ( clip == null )
Console.println( "playSound: clip is null" );
else
{
PlayThread pThread = new PlayThread( clip );
pThread.start();
// clip.setFramePosition( 0 );
// clip.start();
}
}
public Clip loadSound()
{
Container frame = getDisplayContainer();
try
{
// From file
JFileChooser fc = new JFileChooser( new File( ".wav" ) ); // Show
open dialog; this method does not return until the dialog is closed
fc.showOpenDialog( frame );
File selFile = fc.getSelectedFile();
AudioInputStream stream = AudioSystem.getAudioInputStream( selFile
);
// From URL
// stream = AudioSystem.getAudioInputStream( new URL(
"http://hostname/audiofile" ) );
// At present, ALAW and ULAW encodings must be converted
// to PCM_SIGNED before it can be played
AudioFormat format = stream.getFormat();
// Console.println(format);
Console.println(AudioSystem.getAudioFileFormat(selFile));
if ( format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED )
{
format = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate(),
format.getSampleSizeInBits() * 2,
format.getChannels(),
format.getFrameSize() * 2,
format.getFrameRate(),
true ); // big endian
stream = AudioSystem.getAudioInputStream( format, stream );
}
// Create the clip
DataLine.Info info = new DataLine.Info(
Clip.class, stream.getFormat(), ( ( int )
stream.getFrameLength() * format.getFrameSize() ) );
Clip clip = ( Clip ) AudioSystem.getLine( info );
// This method does not return until the audio file is completely
loaded
clip.open( stream );
if ( verbose )
Console.println( "LoadSound: clip loaded: " + clip );
return ( clip );
}
catch ( Exception e )
{
Console.println( "Exception Raised in loadSound: " + e );
return null;
}
}
public Clip loadSound ( String filename )
{
try
{
// From file
AudioInputStream stream = AudioSystem.getAudioInputStream( new File(
filename ) );
// From URL
// stream = AudioSystem.getAudioInputStream( new URL(
"http://hostname/audiofile" ) );
// At present, ALAW and ULAW encodings must be converted
// to PCM_SIGNED before it can be played
AudioFormat format = stream.getFormat();
if ( format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED )
{
format = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate(),
format.getSampleSizeInBits() * 2,
format.getChannels(),
format.getFrameSize() * 2,
format.getFrameRate(),
true ); // big endian
stream = AudioSystem.getAudioInputStream( format, stream );
}
// Create the clip
DataLine.Info info = new DataLine.Info(
Clip.class, stream.getFormat(), ( ( int )
stream.getFrameLength() * format.getFrameSize() ) );
Clip clip = ( Clip ) AudioSystem.getLine( info );
// This method does not return until the audio file is completely
loaded
clip.open( stream );
if ( verbose )
Console.println( "LoadSound: clip loaded: " + clip );
return ( clip );
}
catch ( Exception e )
{
Console.println( "Exception Raised in loadSound: " + e );
return null;
}
}
public void setTurtleCreationSound ( String fileName )
{
if ( fileName != null )
{
turtleCreationSound = loadSound ( fileName );
if ( verbose )
Console.println( "turtleCreationSound loaded, filename = " +
fileName );
}
}
public void setTurtleMovementSound ( String fileName )
{
if ( fileName != null )
{
turtleMovementSound = loadSound ( fileName );
if ( verbose )
Console.println( "turtleMovementSound loaded, filename = " +
fileName );
}
}
public void setTurtleTurnSound ( String fileName )
{
if ( fileName != null )
{
turtleTurnSound = loadSound ( fileName );
if ( verbose )
Console.println( "turtleTurnSound loaded, filename = " +
fileName );
}
}
public void paintTurtle( Graphics g )
{
if ( turtleImage == null )
{
super.paintTurtle( g );
if ( verbose )
Console.println( "TurtleImage is null, called
super.paintTurtle..." );
return ;
}
else
{
if ( verbose )
Console.println( "In paintTurtle, turtleImage= " + turtleImage
);
if ( biContext == null )
{
if ( verbose )
Console.println( "In paintTurtle, biContext is null..." );
return ;
}
else
{
Point pt = getPosition();
double heading = getHeading();
Component disp = getDisplay();
Graphics2D g2 = ( Graphics2D ) g;
Color transparent = new Color( 255, 255, 255, 0 );
biContext.setBackground( transparent );
biContext.clearRect( 0, 0, imgWidth, imgHeight );
AffineTransform af = new AffineTransform();
af.setToRotation( Math.toRadians( heading ), imgWidth / 2,
imgHeight / 2 );
biContext.drawImage( turtleImage, af, null );
g2.drawImage( bi, pt.x - imgWidth / 2, pt.y - imgHeight / 2,
null );
if ( verbose )
Console.println( "Painting Turtle..." );
}
}
}
private class PlayThread extends Thread
{
String filename;
AudioInputStream din = null;
AudioFormat decodedFormat;
AudioInputStream in;
SourceDataLine line;
Clip threadClip;
boolean running = true;
public PlayThread ( Clip clip )
{
if ( clip == null )
Console.println( "playSound: clip is null" );
else
{
threadClip = clip;
}
}
public void run()
{
threadClip.setFramePosition( 0 );
threadClip.start();
}
}
public void playTurnSound()
{
if ( verbose )
Console.println( System.currentTimeMillis() + "In playTurnSound: " +
turtleTurnSound );
if ( turtleTurnSound != null )
{
turtleTurnSound.setFramePosition( 0 );
turtleTurnSound.start();
}
}
public void playMovementSound()
{
if ( verbose )
Console.println( "In playMovementSound: " + turtleMovementSound );
if ( turtleMovementSound != null )
{
turtleMovementSound.setFramePosition( 0 );
turtleMovementSound.start();
}
}
public void playCreationSound()
{
if ( verbose )
Console.println( "In playCreationSound: " + turtleCreationSound );
if ( turtleCreationSound != null )
{
turtleCreationSound.setFramePosition( 0 );
turtleCreationSound.start();
}
}
public void right( double angle )
{
super.right( angle );
playTurnSound();
}
public void left( double angle )
{
super.left( angle );
playTurnSound();
}
public void setHeading ( double angle )
{
super.setHeading ( angle );
playTurnSound();
}
public void forward ( double pixels )
{
super.forward ( pixels );
playMovementSound();
}
public void backward ( double pixels )
{
super.backward ( pixels );
playMovementSound();
}
public void setPosition ( int x, int y )
{
super.setPosition ( x, y );
playMovementSound();
}
public void runTurtle()
{
// test code which draws polygons
setTurtleImage ( "turtletop2.gif" );
setTurtleMovementSound ( null );
setTurtleTurnSound ( null );
// Clip sideTurnSound = loadSound( "start.wav" );
// Clip polyTurnSound = loadSound( "chimes.wav" );
Clip sideTurnSound = loadSound( );
Clip polyTurnSound = loadSound( );
// playJavaxSound( "bong.wav" );
setAutoUpdatePause( 500 );
setPenWidth( 4 );
setHeading( 270 );
setPenColor ( Color.red );
int numberOfSides = 5;
int numPolygons = 25;
int lengthOfSides = 150;
int theWidth = 5;
int sidesCounter;
int polygonCounter = 1;
double amountToTurn = 360.0 / numPolygons;
float myHue = 0.0f;
while ( polygonCounter <= numPolygons )
{
sidesCounter = 1;
myHue = ( float ) polygonCounter / numPolygons;
setPenColor( Color.getHSBColor( myHue, 1.0f, 1.0f ) );
while ( sidesCounter <= numberOfSides )
{
forward( lengthOfSides );
right( 360.0 / numberOfSides );
playSound( sideTurnSound );
sidesCounter++;
}
right( amountToTurn );
playSound ( polyTurnSound );
polygonCounter++;
}
}
}
John,
On Mac OS X, the sounds appear to play to completion assuming they are
not preempted by another sound. I didn't try it on Windows. Despite
the fact that the JavaDoc for AudioClip says:
"Multiple AudioClip items can be playing at the same time, and the
resulting sound is mixed together to produce a composite.",
I don't think this is true. It has been my experience in the past that
attempting to play a second sound will preempt the first.
I even tried starting the sounds in different threads, but that didn't
help.
BTW: that is one annoying little program when both the movement sound
and the turning sound are being played <g>.
Bill
On Feb 19, 2005, at 8:19 PM, John Kirkilis wrote:
> Hi folks,
>
> I need some help figuring out why my MediaTurtle class is having
> trouble
> playing sounds. I did some searching and found references to platform
> specific problems with the AudioClip class and JDKv5. If any Jurtle
> users out there are so inclined, could you download the enclosed files
> into a Jurtle folder and try to run the MediaTurtle class. If you look
> at the test runTurtle method, there are several method calls to tell
> the
> MediaTurtle the names of the files containing the replacement Turtle
> image as well as sounds for movement, turning, and creation. You can
> use
> your own sounds as well, but it appears that only certain resolutions
> and sample rates are allowed. I'm trying to avoid getting into the
> javax.sound.sampled classes right now and get by with AudioClips.
>
> Do you here sound when you run MediaTurtle? Do the sounds appear to
> play
> to completion or are they getting cut-off?
>
> Thanks,
>
> John Kirkilis
> Austin Waldorf School
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Hi folks,
I need some help figuring out why my MediaTurtle class is having trouble
playing sounds. I did some searching and found references to platform
specific problems with the AudioClip class and JDKv5. If any Jurtle
users out there are so inclined, could you download the enclosed files
into a Jurtle folder and try to run the MediaTurtle class. If you look
at the test runTurtle method, there are several method calls to tell the
MediaTurtle the names of the files containing the replacement Turtle
image as well as sounds for movement, turning, and creation. You can use
your own sounds as well, but it appears that only certain resolutions
and sample rates are allowed. I'm trying to avoid getting into the
javax.sound.sampled classes right now and get by with AudioClips.
Do you here sound when you run MediaTurtle? Do the sounds appear to play
to completion or are they getting cut-off?
Thanks,
John Kirkilis
Austin Waldorf School
/*
* File: MediaTurtle.java
* Original Author: John Kirkilis -- Austin Waldorf School
*
* This Turtle provides additional capabilities for Jurtle programmers.
* A subclass can set the turtleImage by specifying the name of the image file.
* In addition a turtle creation sound, movement sound, and turning sound can be
* set as well. The image and sounds can be changed at runtime as the programmer
* desires.
*/
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import com.otherwise.jurtle.*;
import java.util.Random;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.awt.geom.AffineTransform;
public class MediaTurtle extends Turtle
{
boolean customTurtle = true;
boolean verbose = false;
boolean beepMode = false;
Image turtleImage = null;
AudioClip turtleCreationSound, turtleMovementSound, turtleTurnSound;
private BufferedImage bi;
private Graphics2D biContext;
int imgWidth;
int imgHeight;
ClassLoader loader = getClass().getClassLoader();
Toolkit tk = Toolkit.getDefaultToolkit();
public void setTurtleImage ( String theFileName )
{
turtleImage = null;
if ( verbose )
Console.println( "In setTurtleImage, fname=" + theFileName );
if ( theFileName != null )
{
// grab our Turtle image
if ( verbose )
Console.println( "Pre image load..." );
URL imageURL = loader.getResource( theFileName );
if ( imageURL != null )
{
turtleImage = Toolkit.getDefaultToolkit().getImage( imageURL );
JPanel disp = getDisplay();
MediaTracker mt = new MediaTracker( disp );
if ( verbose )
Console.println( "After mediatracker..." );
try
{
mt.addImage( turtleImage, 0 );
mt.waitForID( 0 );
}
catch ( InterruptedException e )
{
turtleImage = null;
if ( verbose )
Console.println( "In catch" );
}
if ( verbose )
Console.println( "After catch" );
imgWidth = turtleImage.getWidth( disp );
imgHeight = turtleImage.getHeight( disp );
bi = new BufferedImage( imgWidth, imgHeight,
BufferedImage.TYPE_INT_ARGB );
biContext = bi.createGraphics();
if ( verbose )
Console.println( "After biContext" );
}
}
}
public void setTurtleCreationSound ( String fileName )
{
if ( fileName != null )
{
URL turtleCreationSoundURL = loader.getResource( fileName );
if ( verbose )
Console.println( "turtleCreationSoundURL = " +
turtleCreationSoundURL );
turtleCreationSound = Applet.newAudioClip( turtleCreationSoundURL );
}
}
public void setTurtleMovementSound ( String fileName )
{
if ( fileName != null )
{
URL turtleMovementSoundURL = loader.getResource( fileName );
if ( verbose )
Console.println( "turtleMovementSoundURL = " +
turtleMovementSoundURL );
turtleMovementSound = Applet.newAudioClip( turtleMovementSoundURL );
}
}
public void setTurtleTurnSound ( String fileName )
{
if ( fileName != null )
{
URL turtleTurnSoundURL = loader.getResource( fileName );
if ( verbose )
Console.println( "turtleTurnSoundURL = " + turtleTurnSoundURL );
turtleTurnSound = Applet.newAudioClip( turtleTurnSoundURL );
}
}
public void paintTurtle( Graphics g )
{
if ( turtleImage == null )
{
super.paintTurtle( g );
if ( verbose )
Console.println( "TurtleImage is null, called
super.paintTurtle..." );
return ;
}
else
{
if ( verbose )
Console.println( "In paintTurtle, turtleImage= " + turtleImage
);
if ( biContext == null )
{
if ( verbose )
Console.println( "In paintTurtle, biContext is null..." );
return ;
}
else
{
Point pt = getPosition();
double heading = getHeading();
Component disp = getDisplay();
Graphics2D g2 = ( Graphics2D ) g;
Color transparent = new Color( 255, 255, 255, 0 );
biContext.setBackground( transparent );
biContext.clearRect( 0, 0, imgWidth, imgHeight );
AffineTransform af = new AffineTransform();
af.setToRotation( Math.toRadians( heading ), imgWidth / 2,
imgHeight / 2 );
biContext.drawImage( turtleImage, af, null );
g2.drawImage( bi, pt.x - imgWidth / 2, pt.y - imgHeight / 2,
null );
if ( verbose )
Console.println( "Painting Turtle..." );
}
}
}
public void playTurnSound()
{
if ( verbose )
Console.println( "In playTurnSound: " + turtleTurnSound );
if ( beepMode )
tk.beep();
else if ( turtleTurnSound != null )
turtleTurnSound.play();
}
public void playMovementSound()
{
if ( verbose )
Console.println( "In playMovementSound: " + turtleMovementSound );
if ( beepMode )
tk.beep();
else if ( turtleMovementSound != null )
turtleMovementSound.play();
}
public void playCreationSound()
{
if ( verbose )
Console.println( "In playCreationSound: " + turtleCreationSound );
if ( beepMode )
tk.beep();
else if ( turtleCreationSound != null )
turtleCreationSound.play();
}
public void right( double angle )
{
playTurnSound();
super.right( angle );
}
public void left( double angle )
{
playTurnSound();
super.left( angle );
}
public void setHeading ( double angle )
{
playTurnSound();
super.setHeading ( angle );
}
public void forward ( double pixels )
{
playMovementSound();
super.forward ( pixels );
}
public void backward ( double pixels )
{
playMovementSound();
super.backward ( pixels );
}
public void setPosition ( int x, int y )
{
playMovementSound();
super.setPosition ( x, y );
}
public void runTurtle()
{
// test code which draws polygons
setTurtleImage ( "turtletop2.gif" );
// setTurtleMovementSound ( "woof2.wav" );
// setTurtleTurnSound ( "bong.wav" );
setAutoUpdatePause( 200 );
setPenWidth( 4 );
setHeading( 270 );
setPenColor ( Color.red );
int numberOfSides = 5;
int numPolygons = 25;
int lengthOfSides = 150;
int theWidth = 5;
int sidesCounter;
int polygonCounter = 1;
double amountToTurn = 360.0 / numPolygons;
float myHue = 0.0f;
while ( polygonCounter <= numPolygons )
{
sidesCounter = 1;
myHue = ( float ) polygonCounter / numPolygons;
setPenColor( Color.getHSBColor( myHue, 1.0f, 1.0f ) );
while ( sidesCounter <= numberOfSides )
{
forward( lengthOfSides );
right( 360.0 / numberOfSides );
sidesCounter++;
}
right( amountToTurn );
polygonCounter++;
}
}
}
If I enable my debugging print statements, it indicates that I'm getting
multiple executions per slider event, but I do only get one execution
when changing the corresponding text field; so it's working just fine.
I'm testing slider events by just clicking once somewhere on the slider.
Dragging the slider will obviously trigger multiple executions to create
the animation.
This version also TRIES to use the GridBagLayout manager, which is a
royal pain to understand. For some reason my X-coordinate label is not
being displayed in the control panel. It's supposed to show up in gridx
location 6 (zero based) in the second row. If I set its gridx attribute
to 7 or set its gridy attribute to 2, it shows up.
Anyway, I'm a bit surprised at how much code is necessary to manage the
GUI. This is my first experience delving this deeply into it. I'm
thinking that I'll try to put all the labels, sliders, and textfields
into arrays so that I don't have to repeat the same code for each
parameter. Is there some reason that this could not be done?
I'll include code comments as soon as this stabilizes.
Later,
John Kirkilis
Austin Waldorf School
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.awt.event.*;
import com.otherwise.jurtle.*;
// Documentation to follow once this is stable
public class PolyPartySlider3e extends Turtle
{
JSlider slider1, slider2, slider3, slider4, slider5, slider6, slider7;
JTextField field1, field2, field3, field4, field5, field6, field7;
static final int DEFAULT_NUM_POLYGONS = 1;
static final int DEFAULT_NUM_SIDES = 5;
static final int DEFAULT_LENGTH = 100;
static final int DEFAULT_WIDTH = 4;
static final int DEFAULT_HEADING = 270;
int numPolygons = DEFAULT_NUM_POLYGONS;
int numberOfSides = DEFAULT_NUM_SIDES;
int lengthOfSides = DEFAULT_LENGTH;
int theWidth = DEFAULT_WIDTH;
int theHeading = DEFAULT_HEADING;
int totalSidesDrawn = 0;
long startTime = System.currentTimeMillis();
boolean debug = false;
boolean timing = true;
Container displayContainer = getDisplayContainer();
JPanel controlsPanel = new JPanel();
Dimension displaySize = getDisplaySize();
int displayWidth = displaySize.width;
int displayHeight = displaySize.height;
final int DEFAULT_X = displayWidth / 2;
int DEFAULT_Y = displayHeight / 2;
int theXCoordinate = DEFAULT_X;
int theYCoordinate = DEFAULT_Y;
// Main entry point of execution
public void runTurtle()
{
setUpGUI();
setAutoUpdate( false );
hideTurtle();
drawPolygons( numPolygons, numberOfSides, lengthOfSides, theWidth,
theHeading, theXCoordinate, theYCoordinate );
waitForStop();
}
// Method to do the actual work of drawing polygons
public void drawPolygons( int numPolygonThingy, int numSideThingy, int
lengthThingy,
int widthThingy, int headingThingy, int xGuy, int
yGal )
{
if ( debug )
Console.println( "Drawing Polygon Cluster: numPolygons=" +
numPolygonThingy + ", numSides=" + numSideThingy +
", length=" + lengthThingy + ", width=" +
widthThingy + ", heading=" + headingThingy +
", x= " + xGuy + ", y=" + yGal );
setHeading( headingThingy );
setDisplayColor ( Color.black );
setPenWidth ( widthThingy );
penUp();
setPosition ( xGuy, yGal );
penDown();
int polygonCounter = 1;
int sidesCounter = 1;
double amountToTurn = 360.0 / numPolygonThingy;
float myHue = 0.0f;
while ( polygonCounter <= numPolygonThingy )
{
sidesCounter = 1;
myHue = ( float ) polygonCounter / numPolygonThingy;
setPenColor( Color.getHSBColor ( myHue, 1.0f, 1.0f ) );
while ( sidesCounter <= numSideThingy )
{
forward( lengthThingy );
right( 360.0 / numSideThingy );
sidesCounter++;
totalSidesDrawn++;
}
right( amountToTurn );
polygonCounter++;
}
updateDisplay();
long runTime = System.currentTimeMillis() - startTime;
float avgSideTime = (float)runTime / totalSidesDrawn;
if ( ! ( slider1.getValueIsAdjusting() || slider2.getValueIsAdjusting()
|| slider3.getValueIsAdjusting() ||
slider4.getValueIsAdjusting() || slider5.getValueIsAdjusting()
|| slider6.getValueIsAdjusting() ||
slider7.getValueIsAdjusting() ) && timing )
{
Console.println( totalSidesDrawn + " total sides in " + runTime + "
milliseconds. Time per side = " + avgSideTime + " milliseconds or " +
(int)(avgSideTime*1000) + " microseconds");
totalSidesDrawn = 0;
startTime = System.currentTimeMillis();
}
}
// A ridiculous amount of code to set up the graphic user interface
public void setUpGUI()
{
displayContainer.setLayout( new BorderLayout() );
displayContainer.add( controlsPanel, BorderLayout.NORTH );
displayContainer.add( getDisplay(), BorderLayout.CENTER );
controlsPanel.setBorder( BorderFactory.createEtchedBorder(
EtchedBorder.LOWERED ) );
GridBagLayout gbl = new GridBagLayout();
controlsPanel.setLayout ( gbl );
GridBagConstraints gbc = new GridBagConstraints();
gbc.ipadx = 35;
gbc.fill = GridBagConstraints.HORIZONTAL;
// Create GUI to input the number of polygons
JLabel label1 = new JLabel( "NumPolygons: " );
label1.setHorizontalAlignment ( JLabel.RIGHT );
controlsPanel.add( label1 );
gbc.gridx = 0;
gbc.gridy = 0;
gbl.setConstraints ( label1, gbc );
slider1 = new JSlider( JSlider.HORIZONTAL, 1, 100, DEFAULT_NUM_POLYGONS
);
slider1.setPreferredSize ( new Dimension ( 100, 10 ) );
field1 = new JTextField( 4 );
field1.setPreferredSize( new Dimension( 10, 10 ) ); //doesn't work with
GridLayout
slider1.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
numPolygons = slider1.getValue();
if ( debug )
Console.println( "In stateChanged
for numPolygons =" + numPolygons );
field1.setText( String.valueOf(
numPolygons ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 1;
gbc.gridy = 0;
gbl.setConstraints ( slider1, gbc );
controlsPanel.add( slider1 );
field1.setText( String.valueOf( DEFAULT_NUM_POLYGONS ) );
field1.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
numPolygons = Integer.parseInt(
field1.getText() );
if ( debug )
Console.println( "In
actionPerformed for numPolygons =" + numPolygons );
slider1.setValue( numPolygons );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field1.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 2;
gbc.gridy = 0;
gbl.setConstraints ( field1, gbc );
controlsPanel.add( field1 );
// Create GUI to input the number of sides in each regular polygon
JLabel label2 = new JLabel( "NumSides: " );
label2.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 3;
gbc.gridy = 0;
gbl.setConstraints ( label2, gbc );
controlsPanel.add( label2 );
slider2 = new JSlider( JSlider.HORIZONTAL, 0, 100, DEFAULT_NUM_SIDES );
field2 = new JTextField( 4 );
slider2.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
numberOfSides = slider2.getValue();
if ( debug )
Console.println( "In stateChanged
for numSides =" + numberOfSides );
field2.setText( String.valueOf(
numberOfSides ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 4;
gbc.gridy = 0;
gbl.setConstraints ( slider2, gbc );
controlsPanel.add( slider2 );
field2.setText( String.valueOf( DEFAULT_NUM_SIDES ) );
field2.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
numberOfSides = Integer.parseInt(
field2.getText() );
if ( debug )
Console.println( "In
actionPerformed for numSides =" + numberOfSides );
slider2.setValue( numberOfSides );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field1.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 5;
gbc.gridy = 0;
gbl.setConstraints ( field2, gbc );
controlsPanel.add( field2 );
// Create GUI to input the side length of each polygon
JLabel label3 = new JLabel( "Length: " );
label3.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 6;
gbc.gridy = 0;
gbl.setConstraints ( label3, gbc );
controlsPanel.add( label3 );
slider3 = new JSlider( JSlider.HORIZONTAL, 10, 300, DEFAULT_LENGTH );
field3 = new JTextField( 4 );
slider3.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
lengthOfSides = slider3.getValue();
if ( debug )
Console.println( "In stateChanged
for side length =" + lengthOfSides );
field3.setText( String.valueOf(
lengthOfSides ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 7;
gbc.gridy = 0;
gbl.setConstraints ( slider3, gbc );
controlsPanel.add( slider3 );
field3.setText( String.valueOf( DEFAULT_LENGTH ) );
field3.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
lengthOfSides = Integer.parseInt(
field3.getText() );
if ( debug )
Console.println( "In
actionPerformed for side length =" + lengthOfSides );
slider3.setValue( lengthOfSides );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field3.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 8;
gbc.gridy = 0;
gbl.setConstraints ( field3, gbc );
controlsPanel.add( field3 );
// Create GUI to input the pen width
JLabel label4 = new JLabel( "Pen Width: " );
label4.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 0;
gbc.gridy = 1;
gbl.setConstraints ( label4, gbc );
controlsPanel.add( label4 );
slider4 = new JSlider( JSlider.HORIZONTAL, 1, 50, DEFAULT_WIDTH );
field4 = new JTextField( 4 );
slider4.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
theWidth = slider4.getValue();
if ( debug )
Console.println( "In stateChanged
for pen width =" + theWidth );
field4.setText( String.valueOf(
theWidth ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 1;
gbc.gridy = 1;
gbl.setConstraints ( slider4, gbc );
controlsPanel.add( slider4 );
field4.setText( String.valueOf( DEFAULT_WIDTH ) );
field4.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
theWidth = Integer.parseInt(
field4.getText() );
if ( debug )
Console.println( "In
actionPerformed for pen width =" + theWidth );
slider4.setValue( theWidth );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field4.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 2;
gbc.gridy = 1;
gbl.setConstraints ( field4, gbc );
controlsPanel.add( field4 );
// Create GUI to input the initial heading
JLabel label5 = new JLabel( "Rotation: " );
label5.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 3;
gbc.gridy = 1;
gbl.setConstraints ( label5, gbc );
controlsPanel.add( label5 );
slider5 = new JSlider( JSlider.HORIZONTAL, 1, 360, DEFAULT_HEADING );
field5 = new JTextField( 4 );
gbl.setConstraints ( field5, gbc );
slider5.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
theHeading = slider5.getValue();
if ( debug )
Console.println( "In stateChanged
for heading =" + theHeading );
field5.setText( String.valueOf(
theHeading ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 4;
gbc.gridy = 1;
gbl.setConstraints ( slider5, gbc );
controlsPanel.add( slider5 );
field5.setText( String.valueOf( DEFAULT_HEADING ) );
field5.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
theHeading = Integer.parseInt(
field5.getText() );
if ( debug )
Console.println( "In
actionPerformed for heading =" + theHeading );
slider5.setValue( theHeading );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field5.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 5;
gbc.gridy = 1;
gbl.setConstraints ( field5, gbc );
controlsPanel.add( field5 );
// Create GUI to input the x coordinate
JLabel label6 = new JLabel( "X: " );
label6.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 6;
gbc.gridy = 1;
gbc.weightx = 2.0;
gbl.setConstraints ( label6, gbc );
controlsPanel.add( label6 );
slider6 = new JSlider( JSlider.HORIZONTAL, 1, displayWidth, DEFAULT_X );
field6 = new JTextField( 4 );
slider6.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
theXCoordinate = slider6.getValue();
if ( debug )
Console.println( "In stateChanged
for x =" + theXCoordinate );
field6.setText( String.valueOf(
theXCoordinate ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbl.setConstraints ( slider6, gbc );
gbc.gridx = 7;
gbc.gridy = 1;
controlsPanel.add( slider6 );
field6.setText( String.valueOf( DEFAULT_X ) );
field6.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
theXCoordinate = Integer.parseInt(
field6.getText() );
if ( debug )
Console.println( "In
actionPerformed for x =" + theXCoordinate );
slider6.setValue( theXCoordinate
);
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field6.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 8;
gbc.gridy = 1;
gbl.setConstraints ( field6, gbc );
controlsPanel.add( field6 );
// Create GUI to input the Y Coordinate
JLabel label7 = new JLabel( "Y: " );
label7.setHorizontalAlignment ( JLabel.RIGHT );
gbc.gridx = 9;
gbc.gridy = 1;
gbl.setConstraints ( label7, gbc );
controlsPanel.add( label7 );
slider7 = new JSlider( JSlider.HORIZONTAL, 0, displayHeight, DEFAULT_Y
);
field7 = new JTextField( 4 );
slider7.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
theYCoordinate = slider7.getValue();
if ( debug )
Console.println( "In stateChanged
for y =" + theHeading );
field7.setText( String.valueOf(
theYCoordinate ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth, theHeading, theXCoordinate,
theYCoordinate );
}
}
);
gbc.gridx = 10;
gbc.gridy = 1;
gbl.setConstraints ( slider7, gbc );
controlsPanel.add( slider7 );
field7.setText( String.valueOf( DEFAULT_Y ) );
field7.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
try
{
theYCoordinate = Integer.parseInt(
field7.getText() );
if ( debug )
Console.println( "In
actionPerformed for Y =" + theYCoordinate );
slider7.setValue( theYCoordinate
);
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field7.getText() + " is not an integer." );
}
}
}
);
gbc.gridx = 11;
gbc.gridy = 1;
gbl.setConstraints ( field7, gbc );
controlsPanel.add( field7 );
displayContainer.validate();
}
}
Wow, John. You have found a bug in Sun's Swing code. It took me a
while to locate it by searching through the Swing source code.
The code for the JSlider constructor that takes a BoundedRangeModel is:
public JSlider(BoundedRangeModel brm)
{
this.orientation = JSlider.HORIZONTAL;
setModel(brm);
sliderModel.addChangeListener(changeListener);
updateUI();
}
Note that they are adding a ChangeListener after calling setModel().
The problem is that setModel adds a ChangeListener itself. That is why
setting the value of the JSlider calls your Change listener twice. I
will report this bug to Sun.
Fortunately there is an easy fix in this case. Rather than calling the
constructor that takes a BoundedRangeModel, call the one that takes a
min, max and value. Here is the code for that constructor:
public JSlider(int orientation, int min, int max, int value)
{
checkOrientation(orientation);
this.orientation = orientation;
sliderModel = new DefaultBoundedRangeModel(value, 0, min, max);
sliderModel.addChangeListener(changeListener);
updateUI();
}
Note that rather than calling setModel, this code just assigns a new
BoundedRangeModel to the sliderModel variable directly. You don't end
up with two change listeners installed.
Just goes to show that even experienced engineers make stupid errors
also.
One other comment I notice looking at your code. You call
drawPolygons() from the ActionLister of the text fields. This is
unnecessary since you also set the value of the slider and this in turn
will end up calling drawPolygons. With you extra call the polygons are
being drawn twice.
By the way, this is a really pretty Turtle when dragging the "number of
polygon" slider around.
On Feb 15, 2005, at 10:26 AM, John Kirkilis wrote:
> I haven't solved the sound playing issue from my last posting to the
> group, but I have a more time-sensitive Turtle to get working for my
> students.
>
> I took the PolySpiral example that came with Jurtle and adapted it to
> provide GUI controls to a polygon drawing Turtle my students had built
> using Console I/O for certain parameters. The drawings seem to be
> working just fine, but I noticed that some early debugging statements
> were indicating that change events were firing multiple times for each
> change, causing each image to be redrawn 2 to 4 times instead of once!
>
> Am I in some kind of feedback loop where a slider change event updates
> the text field, which raises an actionPerformed event which raises a
> stateChanged event and so on. If so, why does it stop after 2 to 4
> ricochets?
>
> See the enclosed source file and look at the Console output for event
> tracing.
>
> Cheers,
>
> John
>
>
>
> Yahoo! Groups Links
>
>
>
>
> import java.awt.*;
> import javax.swing.*;
> import javax.swing.border.*;
> import javax.swing.event.*;
> import java.awt.event.*;
> import com.otherwise.jurtle.*;
>
> public class PolyPartySlider3 extends Turtle
> {
> JSlider slider1, slider2, slider3, slider4;
> JTextField field1, field2, field3, field4;
>
> static final int DEFAULT_NUM_POLYGONS = 1;
> static final int DEFAULT_NUM_SIDES = 5;
> static final int DEFAULT_LENGTH = 100;
> static final int DEFAULT_WIDTH = 4;
>
> int numPolygons = DEFAULT_NUM_POLYGONS;
> int numberOfSides = DEFAULT_NUM_SIDES;
> int lengthOfSides = DEFAULT_LENGTH;
> int theWidth = DEFAULT_WIDTH;
>
> boolean debug = true;
>
> public void runTurtle()
> {
> setAutoUpdate( false );
> hideTurtle();
>
> Container displayContainer = getDisplayContainer();
>
> JPanel controlsPanel = new JPanel();
> controlsPanel.setBorder( BorderFactory.createEtchedBorder(
> EtchedBorder.LOWERED ) );
> controlsPanel.setLayout( new GridLayout(1,12) );
>
>
> JLabel label1 = new JLabel( "NumPolygons: " );
> controlsPanel.add( label1);
>
> slider1 = new JSlider( new DefaultBoundedRangeModel( 1, 1, 1,
> 100 ) );
> field1 = new JTextField( 4 );
>
> slider1.addChangeListener( new ChangeListener()
> {
> public void stateChanged(
> ChangeEvent evt )
> {
> if ( debug )
> Console.println( "In
> stateChanged" );
> numPolygons =
> slider1.getValue();
> field1.setText(
> String.valueOf( numPolygons ) );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> }
> );
> controlsPanel.add( slider1);
>
> field1.setText( String.valueOf( DEFAULT_NUM_POLYGONS ) );
> field1.addActionListener( new ActionListener ()
> {
> public void actionPerformed(
> ActionEvent evt )
> {
> if ( debug )
> Console.println( "In
> actionPerformed" );
> try
> {
> numPolygons =
> Integer.parseInt( field1.getText() );
> slider1.setValue(
> numPolygons );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> catch (
> NumberFormatException e )
> {
> Console.println( "Your
> entry: " + field1.getText() + " is not an integer." );
> }
> }
> }
> );
> controlsPanel.add( field1);
>
> JLabel label2 = new JLabel( "NumSides: " );
> controlsPanel.add( label2);
>
> slider2 = new JSlider( new DefaultBoundedRangeModel( 3, 0, 3,
> 100 ) );
> field2 = new JTextField( 4 );
>
> slider2.addChangeListener( new ChangeListener()
> {
> public void stateChanged(
> ChangeEvent evt )
> {
> if ( debug )
> Console.println( "In
> stateChanged" );
> numberOfSides =
> slider2.getValue();
> field2.setText(
> String.valueOf( numberOfSides ) );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> }
> );
> controlsPanel.add( slider2);
>
> field2.setText( String.valueOf( DEFAULT_NUM_SIDES ) );
> field2.addActionListener( new ActionListener ()
> {
> public void actionPerformed(
> ActionEvent evt )
> {
> if ( debug )
> Console.println( "In
> actionPerformed" );
> try
> {
> numberOfSides =
> Integer.parseInt( field2.getText() );
> slider2.setValue(
> numberOfSides );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> catch (
> NumberFormatException e )
> {
> Console.println( "Your
> entry: " + field1.getText() + " is not an integer." );
> }
> }
> }
> );
> controlsPanel.add( field2);
>
> JLabel label3 = new JLabel( "Length: " );
> controlsPanel.add( label3);
>
> slider3 = new JSlider( new DefaultBoundedRangeModel( 100, 0,
> 1, 300 ) );
> field3 = new JTextField( 4 );
>
> slider3.addChangeListener( new ChangeListener()
> {
> public void stateChanged(
> ChangeEvent evt )
> {
> if ( debug )
> Console.println( "In
> stateChanged" );
> lengthOfSides =
> slider3.getValue();
> field3.setText(
> String.valueOf( lengthOfSides ) );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> }
> );
> controlsPanel.add( slider3);
>
> field3.setText( String.valueOf( DEFAULT_LENGTH ) );
> field3.addActionListener( new ActionListener ()
> {
> public void actionPerformed(
> ActionEvent evt )
> {
> if ( debug )
> Console.println( "In
> actionPerformed" );
> try
> {
> lengthOfSides =
> Integer.parseInt( field3.getText() );
> slider3.setValue(
> lengthOfSides );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> catch (
> NumberFormatException e )
> {
> Console.println( "Your
> entry: " + field3.getText() + " is not an integer." );
> }
> }
> }
> );
> controlsPanel.add( field3);
>
> JLabel label4 = new JLabel( "Pen Width: " );
> controlsPanel.add( label4);
>
> slider4 = new JSlider( new DefaultBoundedRangeModel( 4, 0, 1,
> 50 ) );
> field4 = new JTextField( 8 );
>
> slider4.addChangeListener( new ChangeListener()
> {
> public void stateChanged(
> ChangeEvent evt )
> {
> if ( debug )
> Console.println( "In
> stateChanged" );
> theWidth =
> slider4.getValue();
> field4.setText(
> String.valueOf( theWidth ) );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> }
> );
> controlsPanel.add( slider4);
>
> field4.setText( String.valueOf( DEFAULT_WIDTH ) );
> field4.addActionListener( new ActionListener ()
> {
> public void actionPerformed(
> ActionEvent evt )
> {
> if ( debug )
> Console.println( "In
> actionPerformed" );
> try
> {
> theWidth =
> Integer.parseInt( field4.getText() );
> slider4.setValue(
> theWidth );
> drawPolygons( numPolygons,
> numberOfSides, lengthOfSides, theWidth );
> }
> catch (
> NumberFormatException e )
> {
> Console.println( "Your
> entry: " + field4.getText() + " is not an integer." );
> }
> }
> }
> );
>
> controlsPanel.add( field4);
>
> displayContainer.setLayout( new BorderLayout() );
> displayContainer.add( controlsPanel, BorderLayout.NORTH );
> displayContainer.add( getDisplay(), BorderLayout.CENTER );
>
> displayContainer.validate();
> drawPolygons( numPolygons, numberOfSides, lengthOfSides,
> theWidth );
> waitForStop();
> }
>
>
>
> public void drawPolygons( int numPolygonThingies, int
> numSideThingies, int lengthThingies, int widthThingy )
> {
> setHeading( 270 );
> setDisplayColor ( Color.black );
> setPenWidth ( widthThingy );
>
> int polygonCounter = 1;
> int sidesCounter = 1;
> double amountToTurn = 360.0 / numPolygonThingies;
>
> float myHue = 0.0f;
> if ( debug )
> Console.println( "numPolygonThingies=" +
> numPolygonThingies );
>
> while ( polygonCounter <= numPolygonThingies )
> {
> sidesCounter = 1;
> myHue = ( float ) polygonCounter / numPolygonThingies;
> setPenColor( Color.getHSBColor ( myHue, 1.0f, 1.0f ) );
>
> while ( sidesCounter <= numSideThingies )
> {
> forward( lengthThingies );
> right( 360.0 / numSideThingies );
> sidesCounter++;
> }
> right( amountToTurn );
>
> polygonCounter++;
> }
> updateDisplay();
> }
>
> }
>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
I haven't solved the sound playing issue from my last posting to the
group, but I have a more time-sensitive Turtle to get working for my
students.
I took the PolySpiral example that came with Jurtle and adapted it to
provide GUI controls to a polygon drawing Turtle my students had built
using Console I/O for certain parameters. The drawings seem to be
working just fine, but I noticed that some early debugging statements
were indicating that change events were firing multiple times for each
change, causing each image to be redrawn 2 to 4 times instead of once!
Am I in some kind of feedback loop where a slider change event updates
the text field, which raises an actionPerformed event which raises a
stateChanged event and so on. If so, why does it stop after 2 to 4
ricochets?
See the enclosed source file and look at the Console output for event
tracing.
Cheers,
John
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.awt.event.*;
import com.otherwise.jurtle.*;
public class PolyPartySlider3 extends Turtle
{
JSlider slider1, slider2, slider3, slider4;
JTextField field1, field2, field3, field4;
static final int DEFAULT_NUM_POLYGONS = 1;
static final int DEFAULT_NUM_SIDES = 5;
static final int DEFAULT_LENGTH = 100;
static final int DEFAULT_WIDTH = 4;
int numPolygons = DEFAULT_NUM_POLYGONS;
int numberOfSides = DEFAULT_NUM_SIDES;
int lengthOfSides = DEFAULT_LENGTH;
int theWidth = DEFAULT_WIDTH;
boolean debug = true;
public void runTurtle()
{
setAutoUpdate( false );
hideTurtle();
Container displayContainer = getDisplayContainer();
JPanel controlsPanel = new JPanel();
controlsPanel.setBorder( BorderFactory.createEtchedBorder(
EtchedBorder.LOWERED ) );
controlsPanel.setLayout( new GridLayout(1,12) );
JLabel label1 = new JLabel( "NumPolygons: " );
controlsPanel.add( label1);
slider1 = new JSlider( new DefaultBoundedRangeModel( 1, 1, 1, 100 ) );
field1 = new JTextField( 4 );
slider1.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
if ( debug )
Console.println( "In
stateChanged" );
numPolygons = slider1.getValue();
field1.setText( String.valueOf(
numPolygons ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
}
);
controlsPanel.add( slider1);
field1.setText( String.valueOf( DEFAULT_NUM_POLYGONS ) );
field1.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
if ( debug )
Console.println( "In
actionPerformed" );
try
{
numPolygons = Integer.parseInt(
field1.getText() );
slider1.setValue( numPolygons );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field1.getText() + " is not an integer." );
}
}
}
);
controlsPanel.add( field1);
JLabel label2 = new JLabel( "NumSides: " );
controlsPanel.add( label2);
slider2 = new JSlider( new DefaultBoundedRangeModel( 3, 0, 3, 100 ) );
field2 = new JTextField( 4 );
slider2.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
if ( debug )
Console.println( "In
stateChanged" );
numberOfSides = slider2.getValue();
field2.setText( String.valueOf(
numberOfSides ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
}
);
controlsPanel.add( slider2);
field2.setText( String.valueOf( DEFAULT_NUM_SIDES ) );
field2.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
if ( debug )
Console.println( "In
actionPerformed" );
try
{
numberOfSides = Integer.parseInt(
field2.getText() );
slider2.setValue( numberOfSides );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field1.getText() + " is not an integer." );
}
}
}
);
controlsPanel.add( field2);
JLabel label3 = new JLabel( "Length: " );
controlsPanel.add( label3);
slider3 = new JSlider( new DefaultBoundedRangeModel( 100, 0, 1, 300 ) );
field3 = new JTextField( 4 );
slider3.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
if ( debug )
Console.println( "In
stateChanged" );
lengthOfSides = slider3.getValue();
field3.setText( String.valueOf(
lengthOfSides ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
}
);
controlsPanel.add( slider3);
field3.setText( String.valueOf( DEFAULT_LENGTH ) );
field3.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
if ( debug )
Console.println( "In
actionPerformed" );
try
{
lengthOfSides = Integer.parseInt(
field3.getText() );
slider3.setValue( lengthOfSides );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field3.getText() + " is not an integer." );
}
}
}
);
controlsPanel.add( field3);
JLabel label4 = new JLabel( "Pen Width: " );
controlsPanel.add( label4);
slider4 = new JSlider( new DefaultBoundedRangeModel( 4, 0, 1, 50 ) );
field4 = new JTextField( 8 );
slider4.addChangeListener( new ChangeListener()
{
public void stateChanged( ChangeEvent evt
)
{
if ( debug )
Console.println( "In
stateChanged" );
theWidth = slider4.getValue();
field4.setText( String.valueOf(
theWidth ) );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
}
);
controlsPanel.add( slider4);
field4.setText( String.valueOf( DEFAULT_WIDTH ) );
field4.addActionListener( new ActionListener ()
{
public void actionPerformed( ActionEvent
evt )
{
if ( debug )
Console.println( "In
actionPerformed" );
try
{
theWidth = Integer.parseInt(
field4.getText() );
slider4.setValue( theWidth );
drawPolygons( numPolygons,
numberOfSides, lengthOfSides, theWidth );
}
catch ( NumberFormatException e )
{
Console.println( "Your entry: " +
field4.getText() + " is not an integer." );
}
}
}
);
controlsPanel.add( field4);
displayContainer.setLayout( new BorderLayout() );
displayContainer.add( controlsPanel, BorderLayout.NORTH );
displayContainer.add( getDisplay(), BorderLayout.CENTER );
displayContainer.validate();
drawPolygons( numPolygons, numberOfSides, lengthOfSides, theWidth );
waitForStop();
}
public void drawPolygons( int numPolygonThingies, int numSideThingies, int
lengthThingies, int widthThingy )
{
setHeading( 270 );
setDisplayColor ( Color.black );
setPenWidth ( widthThingy );
int polygonCounter = 1;
int sidesCounter = 1;
double amountToTurn = 360.0 / numPolygonThingies;
float myHue = 0.0f;
if ( debug )
Console.println( "numPolygonThingies=" + numPolygonThingies );
while ( polygonCounter <= numPolygonThingies )
{
sidesCounter = 1;
myHue = ( float ) polygonCounter / numPolygonThingies;
setPenColor( Color.getHSBColor ( myHue, 1.0f, 1.0f ) );
while ( sidesCounter <= numSideThingies )
{
forward( lengthThingies );
right( 360.0 / numSideThingies );
sidesCounter++;
}
right( amountToTurn );
polygonCounter++;
}
updateDisplay();
}
}
Hi all,
Iam pradeep. iam interested in learning java in effective
way.please suggest me good approaches to follow to learn java in
quick and efficient manner.thanking you.,....
John,
The basic Java classes do not have the most sophisticated sound
capabilities. You might also look at the java.sound.* packages to see
if there is something there that would work better.
However, you can probably use AudioClip, to do what you want. I think
that when you call
myAudioClipObj.play();
it does automatically spawn another thread. I believe control is
returned to your program almost immediately (otherwise why would there
be a stop() method). Nevertheless, you can try calling this in a
separate thread to see it it helps. To do so you would create an inner
class as you suggest. Looking at you code, it would be best to create
a playAudioClip() method to encapsulate my code below. This is the way
I like to use inner classes:
// Define the inner class
Thread playThread = new Thread
{
AudioClip clip;
public void run()
{
clip.play();
}
};
// Set the clip you want to play in the thread
playThread.clip = myAudioClip;
// Start the thread.
playThread.start();
You could even play around with setting the thread's priority in the
run method using:
Thread.currentThread().setPriority(MAX_PRIORITY);
This might make the sound play with less interruption.
Hope this helps
Bill
On Feb 9, 2005, at 7:58 PM, John Kirkilis wrote:
> I'm creating a sub-class of Turtle which includes methods for setting a
> custom turtle image instead of the default triangle. It also has
> options
> for setting sounds for turning and moving.
>
> I'm having trouble getting the sounds (1 to 3 seconds) to start quickly
> and play to completion. The play() method of the AudioClip class is
> what
> I'm using. I load the sounds into an AudioClip variable first, and then
> just play() thereafter with no reloading. It should just play from RAM.
>
> I've done some digging and noticed that other Java programmers have
> encountered a similar problem depending on the platform and other
> environmental considerations as well.
>
> Some have solved it by playing the sound in a separate thread. Is there
> any reason this wouldn't work in a subclass of Turtle? I haven't done
> any multi-threading programming in Java yet, so I'm not sure where to
> go
> next. Would I create an inner class that extends Thread and include a
> play method which takes an AudioClip parameter and invoke the play()
> method on it?
>
> See my MediaTurtle class enclosed for background.
>
> Thanks,
>
> John Kirkilis
> Austin Waldorf School
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
> /*
> * File: MediaTurtle.java
> * Original Author: John Kirkilis -- Austin Waldorf School
> *
> * This Turtle provides additional capabilities for Jurtle programmers.
> * A subclass can set the turtleImage by specifying the name of the
> image file.
> * In addition a turtle creation sound, movement sound, and turning
> sound can be
> * loaded as well. The image and sounds can be changed at runtime as
> the programmer
> * desires.
> */
>
> import java.awt.*;
> import java.awt.image.*;
> import java.awt.event.*;
> import javax.swing.*;
> import com.otherwise.jurtle.*;
> import java.util.Random;
> import java.applet.*;
> import java.io.*;
> import java.net.*;
> import java.awt.geom.AffineTransform;
>
> public class MediaTurtle extends Turtle
> {
> boolean customTurtle = true;
> boolean verbose = true;
>
> Image turtleImage;
> AudioClip turtleCreationSound, turtleMovementSound,
> turtleTurnSound;
> private BufferedImage bi;
> private Graphics2D biContext;
> int imgWidth;
> int imgHeight;
> ClassLoader loader = getClass().getClassLoader();
>
> public void setTurtleImage ( String theFileName )
> {
> JPanel disp = getDisplay();
> if ( verbose )
> Console.println( "In setTurtleImage, fname=" + theFileName
> );
> if ( theFileName != null )
> {
> // grab our Turtle image
> if ( verbose )
> Console.println( "Pre image load..." );
> URL imageURL = loader.getResource( theFileName );
> turtleImage = Toolkit.getDefaultToolkit().getImage(
> imageURL );
> MediaTracker mt = new MediaTracker( disp );
> if ( verbose )
> Console.println( "After mediatracker..." );
> try
> {
> mt.addImage( turtleImage, 0 );
> mt.waitForID( 0 );
> }
> catch ( InterruptedException e )
> {
> if ( verbose )
> Console.println( "In catch" );
> }
>
> if ( verbose )
> Console.println( "After catch" );
> imgWidth = turtleImage.getWidth( disp );
> imgHeight = turtleImage.getHeight( disp );
> bi = new BufferedImage( imgWidth, imgHeight,
> BufferedImage.TYPE_INT_ARGB );
> biContext = bi.createGraphics();
> if ( verbose )
> Console.println( "After biContext" );
> }
> }
>
> public void setTurtleCreationSound ( String fileName )
> {
> if ( fileName != null )
> {
> URL turtleCreationSoundURL = loader.getResource( fileName
> );
> turtleCreationSound = Applet.newAudioClip(
> turtleCreationSoundURL );
> }
> }
>
> public void setTurtleMovementSound ( String fileName )
> {
> if ( fileName != null )
> {
> URL turtleMovementSoundURL = loader.getResource( fileName
> );
> if ( verbose )
> Console.println( "turtleMovementSoundURL = " +
> turtleMovementSoundURL );
> turtleMovementSound = Applet.newAudioClip(
> turtleMovementSoundURL );
> }
> }
>
> public void setTurtleTurnSound ( String fileName )
> {
> if ( fileName != null )
> {
> URL turtleTurnSoundURL = loader.getResource( fileName );
> turtleTurnSound = Applet.newAudioClip( turtleTurnSoundURL
> );
> }
> }
>
> public void paintTurtle( Graphics g )
> {
> if ( biContext == null )
> return ;
>
> if ( turtleImage == null )
> super.paintTurtle( g );
> else
> {
> Point pt = getPosition();
> double heading = getHeading();
> Component disp = getDisplay();
> Graphics2D g2 = ( Graphics2D ) g;
>
> Color transparent = new Color( 255, 255, 255, 0 );
> biContext.setBackground( transparent );
> biContext.clearRect( 0, 0, imgWidth, imgHeight );
>
> AffineTransform af = new AffineTransform();
> af.setToRotation( Math.toRadians( heading ), imgWidth / 2,
> imgHeight / 2 );
> biContext.drawImage( turtleImage, af, null );
>
> g2.drawImage( bi, pt.x - imgWidth / 2, pt.y - imgHeight /
> 2, null );
> if ( verbose )
> Console.println( "Painting Turtle..." );
> }
> }
>
> public void playTurnSound()
> {
> if ( verbose )
> Console.println( "In playTurnSound: " + turtleTurnSound );
> if ( turtleTurnSound != null )
> turtleTurnSound.play();
> }
>
> public void playMovementSound()
> {
> if ( verbose )
> Console.println( "In playMovementSound: " +
> turtleMovementSound );
> if ( turtleMovementSound != null )
> turtleMovementSound.play();
> }
>
> public void playCreationSound()
> {
> if ( verbose )
> Console.println( "In playCreationSound: " +
> turtleCreationSound );
> if ( turtleCreationSound != null )
> turtleCreationSound.play();
> }
>
> public void right( double angle )
> {
> playTurnSound();
> super.right( angle );
> }
>
> public void left( double angle )
> {
> playTurnSound();
> super.left( angle );
> }
>
> public void setHeading ( double angle )
> {
> playTurnSound();
> super.setHeading ( angle );
> }
>
> public void forward ( double pixels )
> {
> playMovementSound();
> super.forward ( pixels );
> }
>
> public void backward ( double pixels )
> {
> playMovementSound();
> super.backward ( pixels );
> }
>
> public void setPosition ( int x, int y )
> {
> playMovementSound();
> super.setPosition ( x, y );
> }
>
> public void runTurtle()
> {
> // test code which draws polygons
>
> setTurtleImage ( "turtletop2.gif" );
> setTurtleMovementSound ( "ladylaf3c.wav" );
> // setTurtleTurnSound ( "meow.wav" );
>
> setAutoUpdatePause( 2000 );
> setPenWidth( 4 );
>
> setHeading( 270 );
> setPenColor ( Color.red );
>
> int numberOfSides = 5;
> int numPolygons = 25;
> int lengthOfSides = 150;
> int theWidth = 5;
>
> int sidesCounter;
> int polygonCounter = 1;
> double amountToTurn = 360.0 / numPolygons;
>
> float myHue = 0.0f;
>
> while ( polygonCounter <= numPolygons )
> {
> sidesCounter = 1;
> myHue = ( float ) polygonCounter / numPolygons;
> setPenColor( Color.getHSBColor( myHue, 1.0f, 1.0f ) );
>
> while ( sidesCounter <= numberOfSides )
> {
> forward( lengthOfSides );
> right( 360.0 / numberOfSides );
> sidesCounter++;
> }
> right( amountToTurn );
>
> polygonCounter++;
> }
>
>
> }
>
> }
>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Anand,
An interface is often thought of as a "contract" between two classes.
If a class declares that it implements a specific interface, then it is
guaranteeing that it implements the body of the methods specified in
the interface. This is useful to a class that wants to call those
methods.
Suppose there is an interface SoundPlayer declared as:
public Interface SoundPlayer
{
public void playSound();
}
Now if another class is passed an object that is a SoundPlayer, that
class knows the object implememnts the playSound() method. It does not
have to know anything more about the object to call that method. The
object could actually be a subclass of Window, it could be a subclass
of Turtle, it really doesn't matter. The object is "under contract" to
implement the method specified in the Interface.
I don't really talk about Interfaces in the Jurtle tutorial because
they are an unnecessary confusion when starting to learn Java.
However, they are very important when you begin to write larger
programs.
You might also look at the section of Sun's online tutorial that deals
with Interfaces
<http://java.sun.com/docs/books/tutorial/java/interpack/
interfaceDef.html>
Write back if this is still unclear to you.
Bill
On Feb 12, 2005, at 4:22 AM, anand hungund wrote:
>
> Hello Sir
> I need answers regarding Interfaces in core
> java.
> My question is if we r not implementing any method in
> a interface then what is the use of it?
> if the class implementing a interface has to define
> all the methods declared in interfce,whats the use,we
> directly define the methods without implementing a
> interface?
> Please tell me the use or advantage of using a
> interface in the program by concept wise and by
> example?
> and alo if a class want to implement a interface how
> should i come to know what are the methods declared in
> it?
> please send me convincing answers and examples that
> demonstrates the usefullness of interface in core
> java?
> Thank You
> Anand.R.Hungund
>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Hello Sir
I need answers regarding Interfaces in core
java.
My question is if we r not implementing any method in
a interface then what is the use of it?
if the class implementing a interface has to define
all the methods declared in interfce,whats the use,we
directly define the methods without implementing a
interface?
Please tell me the use or advantage of using a
interface in the program by concept wise and by
example?
and alo if a class want to implement a interface how
should i come to know what are the methods declared in
it?
please send me convincing answers and examples that
demonstrates the usefullness of interface in core
java?
Thank You
Anand.R.Hungund
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
I'm creating a sub-class of Turtle which includes methods for setting a
custom turtle image instead of the default triangle. It also has options
for setting sounds for turning and moving.
I'm having trouble getting the sounds (1 to 3 seconds) to start quickly
and play to completion. The play() method of the AudioClip class is what
I'm using. I load the sounds into an AudioClip variable first, and then
just play() thereafter with no reloading. It should just play from RAM.
I've done some digging and noticed that other Java programmers have
encountered a similar problem depending on the platform and other
environmental considerations as well.
Some have solved it by playing the sound in a separate thread. Is there
any reason this wouldn't work in a subclass of Turtle? I haven't done
any multi-threading programming in Java yet, so I'm not sure where to go
next. Would I create an inner class that extends Thread and include a
play method which takes an AudioClip parameter and invoke the play()
method on it?
See my MediaTurtle class enclosed for background.
Thanks,
John Kirkilis
Austin Waldorf School
/*
* File: MediaTurtle.java
* Original Author: John Kirkilis -- Austin Waldorf School
*
* This Turtle provides additional capabilities for Jurtle programmers.
* A subclass can set the turtleImage by specifying the name of the image file.
* In addition a turtle creation sound, movement sound, and turning sound can be
* loaded as well. The image and sounds can be changed at runtime as the
programmer
* desires.
*/
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import com.otherwise.jurtle.*;
import java.util.Random;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.awt.geom.AffineTransform;
public class MediaTurtle extends Turtle
{
boolean customTurtle = true;
boolean verbose = true;
Image turtleImage;
AudioClip turtleCreationSound, turtleMovementSound, turtleTurnSound;
private BufferedImage bi;
private Graphics2D biContext;
int imgWidth;
int imgHeight;
ClassLoader loader = getClass().getClassLoader();
public void setTurtleImage ( String theFileName )
{
JPanel disp = getDisplay();
if ( verbose )
Console.println( "In setTurtleImage, fname=" + theFileName );
if ( theFileName != null )
{
// grab our Turtle image
if ( verbose )
Console.println( "Pre image load..." );
URL imageURL = loader.getResource( theFileName );
turtleImage = Toolkit.getDefaultToolkit().getImage( imageURL );
MediaTracker mt = new MediaTracker( disp );
if ( verbose )
Console.println( "After mediatracker..." );
try
{
mt.addImage( turtleImage, 0 );
mt.waitForID( 0 );
}
catch ( InterruptedException e )
{
if ( verbose )
Console.println( "In catch" );
}
if ( verbose )
Console.println( "After catch" );
imgWidth = turtleImage.getWidth( disp );
imgHeight = turtleImage.getHeight( disp );
bi = new BufferedImage( imgWidth, imgHeight,
BufferedImage.TYPE_INT_ARGB );
biContext = bi.createGraphics();
if ( verbose )
Console.println( "After biContext" );
}
}
public void setTurtleCreationSound ( String fileName )
{
if ( fileName != null )
{
URL turtleCreationSoundURL = loader.getResource( fileName );
turtleCreationSound = Applet.newAudioClip( turtleCreationSoundURL );
}
}
public void setTurtleMovementSound ( String fileName )
{
if ( fileName != null )
{
URL turtleMovementSoundURL = loader.getResource( fileName );
if ( verbose )
Console.println( "turtleMovementSoundURL = " +
turtleMovementSoundURL );
turtleMovementSound = Applet.newAudioClip( turtleMovementSoundURL );
}
}
public void setTurtleTurnSound ( String fileName )
{
if ( fileName != null )
{
URL turtleTurnSoundURL = loader.getResource( fileName );
turtleTurnSound = Applet.newAudioClip( turtleTurnSoundURL );
}
}
public void paintTurtle( Graphics g )
{
if ( biContext == null )
return ;
if ( turtleImage == null )
super.paintTurtle( g );
else
{
Point pt = getPosition();
double heading = getHeading();
Component disp = getDisplay();
Graphics2D g2 = ( Graphics2D ) g;
Color transparent = new Color( 255, 255, 255, 0 );
biContext.setBackground( transparent );
biContext.clearRect( 0, 0, imgWidth, imgHeight );
AffineTransform af = new AffineTransform();
af.setToRotation( Math.toRadians( heading ), imgWidth / 2, imgHeight
/ 2 );
biContext.drawImage( turtleImage, af, null );
g2.drawImage( bi, pt.x - imgWidth / 2, pt.y - imgHeight / 2, null );
if ( verbose )
Console.println( "Painting Turtle..." );
}
}
public void playTurnSound()
{
if ( verbose )
Console.println( "In playTurnSound: " + turtleTurnSound );
if ( turtleTurnSound != null )
turtleTurnSound.play();
}
public void playMovementSound()
{
if ( verbose )
Console.println( "In playMovementSound: " + turtleMovementSound );
if ( turtleMovementSound != null )
turtleMovementSound.play();
}
public void playCreationSound()
{
if ( verbose )
Console.println( "In playCreationSound: " + turtleCreationSound );
if ( turtleCreationSound != null )
turtleCreationSound.play();
}
public void right( double angle )
{
playTurnSound();
super.right( angle );
}
public void left( double angle )
{
playTurnSound();
super.left( angle );
}
public void setHeading ( double angle )
{
playTurnSound();
super.setHeading ( angle );
}
public void forward ( double pixels )
{
playMovementSound();
super.forward ( pixels );
}
public void backward ( double pixels )
{
playMovementSound();
super.backward ( pixels );
}
public void setPosition ( int x, int y )
{
playMovementSound();
super.setPosition ( x, y );
}
public void runTurtle()
{
// test code which draws polygons
setTurtleImage ( "turtletop2.gif" );
setTurtleMovementSound ( "ladylaf3c.wav" );
// setTurtleTurnSound ( "meow.wav" );
setAutoUpdatePause( 2000 );
setPenWidth( 4 );
setHeading( 270 );
setPenColor ( Color.red );
int numberOfSides = 5;
int numPolygons = 25;
int lengthOfSides = 150;
int theWidth = 5;
int sidesCounter;
int polygonCounter = 1;
double amountToTurn = 360.0 / numPolygons;
float myHue = 0.0f;
while ( polygonCounter <= numPolygons )
{
sidesCounter = 1;
myHue = ( float ) polygonCounter / numPolygons;
setPenColor( Color.getHSBColor( myHue, 1.0f, 1.0f ) );
while ( sidesCounter <= numberOfSides )
{
forward( lengthOfSides );
right( 360.0 / numberOfSides );
sidesCounter++;
}
right( amountToTurn );
polygonCounter++;
}
}
}
This group has languished a bit while I been focusing on my new product
Parsnips <http://www.otherwise.com/Parsnips.html>. However, I'm now
ready to start work on a new Jurtle release and you like to hear from
you about what enhancements you would like to see. Remember that this
program is primarily for someone with no programming experience so that
would probably rule out any really advanced features (e.g.
refactoring).
What do people think of the lessons? They were designed to introduce
the just basics of the language and get you started programming as soon
as possible. Hopefully they pave the way for graduating to more
advanced texts.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Well, I hate having known bugs in my software, so I rolled 1.6.2 to fix
a display corruption problem that happened if you created a new class
while on the display tab. While I was at it I rolled in John's
suggestion to display the full stack trace in the console when a
runtime error occurs.
Get it on the web site at: <www.otherwise.com/Download.html>
I hope this will be the last bug fix release for a while.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
On Jun 23, 2004, at 8:50 AM, John Kirkilis wrote:
> Bill,
>
> Thanks for 1.6.1 update.
>
> In the food for thought category, it might be useful to have a stack
> trace
> show up either in the console or in a separate tab so that a student
> could
> figure out where the problem is. It might also be interesting to make
> the
> stack trace clickable so that it navigates to the offending line in the
> student's code just like it does for compile-time errors.
>
> - John
Good suggestion. I have changed the Turtle code to print the entire
stack trace rather than just the error. For non-Turtles the full stack
trace is already printed.
Making the stack trace clickable will take a bit more work. I'll give
it some thought.
Keep those suggestions pouring in.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Bill,
Thanks for 1.6.1 update.
In the food for thought category, it might be useful to have a stack trace
show up either in the console or in a separate tab so that a student could
figure out where the problem is. It might also be interesting to make the
stack trace clickable so that it navigates to the offending line in the
student's code just like it does for compile-time errors.
- John
I have placed Jurtle 1.6.1 on the web site. It fixes:
1) The problem on Windows where a newly populated Examples directory
sometimes shows the classes as not being initially compiled.
2) Removes the bogus text field in the Preferences dialog where you
would think you could set the location of the Jurtle workspace.
3) Added code to the version checker so it can deal with three-part
version numbers (like 1.6.1). Note that 1.6 (and earlier) will not
recognize 1.6.1 as a new version.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
On Jun 22, 2004, at 4:31 PM, John Kirkilis wrote:
> Bill,
>
> It might be useful to have a few methods in the Console class to
> control the
> visibility of the Console panel. If a student is running a class which
> has
> no text output, they may want to hide the console programmatically at
> the
> outset to have the maximum drawing area. I guess Jurtle would still
> need a
> way to display runtime errors and such. Perhaps Jurtle can force the
> visibility to "true" if output is being routed to the Console.
>
> I suppose a console-only class would like to have to ability to
> maximize the
> console panel and hide the graphics panel. Anyway, no big deal. Just
> food
> for thought.
>
> John Kirkilis
> Austin Waldorf School
Good suggestions. I'll put those on my list of things to think about
for the next release.
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Bill,
It might be useful to have a few methods in the Console class to control the
visibility of the Console panel. If a student is running a class which has
no text output, they may want to hide the console programmatically at the
outset to have the maximum drawing area. I guess Jurtle would still need a
way to display runtime errors and such. Perhaps Jurtle can force the
visibility to "true" if output is being routed to the Console.
I suppose a console-only class would like to have to ability to maximize the
console panel and hide the graphics panel. Anyway, no big deal. Just food
for thought.
John Kirkilis
Austin Waldorf School
On Jun 21, 2004, at 1:50 PM, Annalisa Ragatz wrote:
> Deleting Jurtle_Workspace seems to have no effect on the menu item
> options for me - it just makes a new one next time Jurtle starts up,
> same appearance as before.
I will fix this in a new point release.
>
> Though setting a new Workspace path in the Preferences never seems to
> be remembered - even after simply hitting OK and then opening up the
> Preferences again, it is once more blank.
How embarrassing! That preferences field never actually got hooked up
to anything. I had intended to remove the field from the GUI before
shipping, but it fell through the cracks. Another thing for the next
point release. Thanks for pointing out my error.
>
>
> On Jun 17, 2004, at 1:36 PM, Bill Tschumy wrote:
>>
>> I would be curious to know if any others are seeing this. Try
>> quitting
>> Jurtle, deleting (or renaming) Jurtle_Workspace and then starting
>> Jurtle again. If you go to the Examples directory (First menu item in
>> Tutorials) are any of the items italicized?
>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
Deleting Jurtle_Workspace seems to have no effect on the menu item
options for me - it just makes a new one next time Jurtle starts up,
same appearance as before.
Though setting a new Workspace path in the Preferences never seems to
be remembered - even after simply hitting OK and then opening up the
Preferences again, it is once more blank.
On Jun 17, 2004, at 1:36 PM, Bill Tschumy wrote:
>
> I would be curious to know if any others are seeing this. Try quitting
> Jurtle, deleting (or renaming) Jurtle_Workspace and then starting
> Jurtle again. If you go to the Examples directory (First menu item in
> Tutorials) are any of the items italicized?
I think the problem here is that when the Jurtle_Workspace is being
populated, the .java files are getting copied after their .class
counterparts giving them a newer modification time. I haven't seen
this happen myself, but as I think about it, there is no guarantee this
can't happen.
I will look into a different way of copying the Examples so this
doesn't happen.
I would be curious to know if any others are seeing this. Try quitting
Jurtle, deleting (or renaming) Jurtle_Workspace and then starting
Jurtle again. If you go to the Examples directory (First menu item in
Tutorials) are any of the item italicized?
Bill
On Jun 17, 2004, at 9:12 AM, John Kirkilis wrote:
> See enclosed screen shots from yesterday...
> -----Original Message-----
> From: Bill Tschumy [mailto:bill@...]
> Sent: Wednesday, December 31, 1969 9:05 PM
> To: jurtle-users@yahoogroups.com
> Subject: Re: [jurtle-users] Minor Cosmetic Weirdness
>
> That's strange. I just tried it and it worked for me. I wonder if it
> was some temporary glitch. You might try quiting Jurtle, deleting the
> workspace and restarting Jurtle. See if it happens again. If so, are
> the class files missing or is it just the modification times that are
> off?
>
> On Jun 15, 2004, at 4:35 PM, John Kirkilis wrote:
>
> > Bill,
> >
> > When I installed v1.6, I went to the new workspace directory in
> Jurtle
> > and
> > it indicated that most of the classes were not compiled (italic
> > style). When
> > I looked at the directory listing, all the class files were there.
> When
> > they're recompiled, the italics go away.
> >
> > It's no big deal as they all run and can be easily recompiled.
> >
> > I can't wait until I'm done with my grade reports, so I can really
> > start
> > playing and preparing for the fall.
> >
> > Thanks for the upgrade,
> >
> > John Kirkilis
> > Digital Arts & Sciences
> > Austin Waldorf School
> >
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com
That's strange. I just tried it and it worked for me. I wonder if it
was some temporary glitch. You might try quiting Jurtle, deleting the
workspace and restarting Jurtle. See if it happens again. If so, are
the class files missing or is it just the modification times that are
off?
On Jun 15, 2004, at 4:35 PM, John Kirkilis wrote:
> Bill,
>
> When I installed v1.6, I went to the new workspace directory in Jurtle
> and
> it indicated that most of the classes were not compiled (italic
> style). When
> I looked at the directory listing, all the class files were there. When
> they're recompiled, the italics go away.
>
> It's no big deal as they all run and can be easily recompiled.
>
> I can't wait until I'm done with my grade reports, so I can really
> start
> playing and preparing for the fall.
>
> Thanks for the upgrade,
>
> John Kirkilis
> Digital Arts & Sciences
> Austin Waldorf School
>
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
--
Bill Tschumy
Otherwise -- Austin, TX
http://www.otherwise.com