I am using java and trying to write a simple sudo mouse recorder that will store the mouse position when the space key is pressed. The only key I need to detect is the space key (Although if another key is easier, that will work).
I need the whole mouse recorder to be written in java, but it is OK if the function for the keypress is in another language. And I will be runing this in Windows 7.
What is the simplest way to do what has been described? All of the methods I have found require at minimum 20 lines of code. This is OK, except I don't understand how to implement them. I have an example source below:
import java.awt.MouseInfo;
import javax.swing.JOptionPane;
public class MouseRecorder {
public static void main (String[] args)
{
int slot = 0;
int xLoc[10];
int yLoc[10];
while (slot <= 10)
{
if (keyPressed(KEY_SPACE)) //<<<<This obviously won't work, but I'm looking for the simplest way to code this
{
xLoc[slot] = MouseInfo.getPointerInfo().getLocation().x;
yLoc[slot] = MouseInfo.getPointerInfo().getLocation().y;
slot++;
}
}
//The mouse information can now be utilized
}
}
Again your question is not clear since you have not addressed my comment:
It smells like to me that you might want a system-wide key logger that only responds to one key press, and that doesn't need a GUI. If this is so, then your best solution is to not use Java to create your application but to use a tool that can get closer to the OS. AutoIt comes to mind if this is for a Windows project. Please define your needs better.
and this forces us to guess at the problem and its solution.
If you are interested in creating a Swing GUI, having it take focus, and have it listen to key events, then the solution is to do this:
Create your Swing GUI and display it, leaving it as the active windowed application while your application is running.
Using Key Bindings have it listen for space bar presses
And then log the mouse location when the space bar is pressed.
As noted, this will not be achievable in 5 lines of code, so put that idea to the side.
If on the other hand your desire is to not have a GUI but rather listen for hot-key presses while any and all applications are running, then
The possible platforms used will be critical since your solution will require OS-specific code since creating a hot-key means having to create a keyboard handler routine, often in C, and doing this for each platform, and then linking it in to Java using JNI or JNA.
Or as noted another way is to link your Java program with an OS specific utility program or script such as AutoIt.
If you need more specific help, then please clarify your question.
Edit
You state:
Thank you for the answer, but as I have described above: "Changing languages is out of the question although it seems like that might be easier." and "I dont want a gui, if I can avoid it"
Then my second answer is what you're looking for. How adept are you at C/C++, JNI or JNA, and how good is your knowledge of operating system libraries? If you want a Java only solution, I would consider your requirements far above beginner or intermediate Java and into the realm of advanced -- or at least beyond my abilities at the moment, although I am sure that I could come up with some solutions after several days to a week or two of study.
... or consider getting rid of your "changing languages" requirement and instead allow at least meshing Java together with a scripting utility, like AutoIt. That could allow creation of solutions in a shorter period of time, at least for me. A limitation though is that these would be platform specific solutions. What is your purpose behind all of this? Could this be an XY problem in disguise?
Edit 2
I decided to try to solve this with a small AutoIt utility that I meshed with Java, and this is what I came up with.
My AutoIt program is called CaptureHotKey.au3, and it is compiled to an exe before use:
$key = $CmdLine[1]
HotKeySet($key, "hotKeyFunction")
While 1
Sleep(100)
WEnd
Func hotKeyFunction()
ConsoleWrite(#CRLF)
EndFunc
There's not much to it. All it does is set a hot-key from the first command line parameter, provides an endless while loop so that it will continue to run, and a hotkey function that is quite simple and only sends a carriage-return/line-feed to the console (which will be the standard output).
Then a Java class to help interact with this. It uses SwingPropertyLanguageSupport to allow addition of PropertyChangeListeners that respond on the Swing thread (in case I want to use this with a GUI).
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.event.SwingPropertyChangeSupport;
public class CaptureHotKey implements Runnable {
public static final String HOT_KEY = "hot key";
private String hotKey;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private Scanner scanner;
private CaptureHotKeyFromAutoIt capture;
public CaptureHotKey(final String hotKey) throws IOException {
this.hotKey = hotKey;
capture = new CaptureHotKeyFromAutoIt(hotKey);
scanner = new Scanner(capture.getReadable());
}
public void startCapturing() {
new Thread(this).start();
}
public void exit() {
if (capture != null) {
capture.exit();
}
if (scanner != null) {
scanner.close();
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public String getHotKey() {
return hotKey;
}
#Override
public void run() {
while (scanner != null && scanner.hasNextLine()) {
scanner.nextLine();
pcSupport.firePropertyChange(HOT_KEY, true, false);
}
}
private static class CaptureHotKeyFromAutoIt {
public static final String AUTO_IT_APP_PATH = "CaptureHotKey.exe";
private Process process = null;
private ProcessBuilder pb;
public CaptureHotKeyFromAutoIt(String hotKey) throws IOException {
List<String> cmdList = new ArrayList<>();
cmdList.add(AUTO_IT_APP_PATH);
cmdList.add(hotKey);
pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
process = pb.start();
}
public void exit() {
if (process != null) {
process.destroy();
}
}
public Readable getReadable() {
if (process != null) {
return new InputStreamReader(process.getInputStream());
}
return null;
}
}
}
Finally a Java class to test this set up:;
This adds a PropertyChangeListener to the class above to allow it to be notified if the hot-key is pressed:
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Scanner;
public class CaptureHotKeyTest {
public static final String CTRL_R = "^r"; // "{SPACE}" works for spacebar
private static final String EXIT = "exit";
private CaptureHotKey capture;
public CaptureHotKeyTest() {
try {
capture = new CaptureHotKey(CTRL_R);
capture.addPropertyChangeListener(new HotKeyPropertyChngListener());
capture.startCapturing();
Scanner scan = new Scanner(System.in);
System.out.println("Press control-r to get mouse position.");
System.out.println("Type \"exit\" to exit program");
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.equalsIgnoreCase(EXIT)) {
scan.close();
capture.exit();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class HotKeyPropertyChngListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(CaptureHotKey.HOT_KEY)) {
System.out.println("hot key pressed");
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
System.out.println("Mouse: " + pointerInfo.getLocation());
}
}
}
public static void main(String[] args) {
new CaptureHotKeyTest();
}
}
You should use KeyListener: http://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html
It works fine with Swing
Related
I hope someone here can help. I am just trying to wrap my head around the Observer Design Pattern, Threading and how I can use both for a project I am doing.
I currently need to implement the both of them on a Media Player I am building using Java FX.
I need to use both of them to update my listView(Populated by a getNames function of files in my directory. I need any changes to my folder of songs to reflect straight away on the GUI.
Is it possible, to have a running thread constantly calling my getNames function(returns an items variable), and if there are any changes to the items variable then I can use the Observer pattern to notify my GUI class to update its list.
I know it's possible to have a thread constantly hitting the function, but I just need some advice on if its then possible to use the Observer pattern to notify on if the items have changed!
I have no code to show, as I am still trying to figure out how to implement this.
Any ideas?
Appreciate any advice at all! Thanks :)
UPDATE
After quite a long time, Got this working with threads and observer patterm. Didn't need WatchService. Used my thread to constantly call a check for change method, then if method returned through then Observer kicked in to update GUI.
Its possible to use this pattern , you need to run a thread to keep watch on folder for files update and to make this thread safe use eventQueue to run your thread
e.g.
java.awt.EventQueue.invokeLater or invokeAndWait
Once change is detected by the thread, then your observer pattern will update GUI
Hope this helps!!
The best approach to this (IMO) would be:
Consider this Oracle tutorial on the WatchService.
As you are using JavaFX, wrap "the basic steps required to implement a watch service" from that tutorial in a JavaFX Task.
Perhaps following the pattern from the Task javadoc "A Task Which Returns Partial Results" to feedback into your view any changes detected by the watch service.
As you note "unfortunately our lecturer won't let us use WatchService", then you can use a method like in the sample code below which is an active poll of the FileSystem. The use of the WatchService is definitely preferred as it can, internally within the JDK implementation, make use of OS provided file watch services. Those OS services can provide a notification of a file change event, so that the Java code does not need to actively poll the file system for changes. Nevertheless, the following inefficient job will likely suffice to do the job in this case...
What the code does is spawn a JavaFX task on a thread which polls the file system and modifies the observable list backing the ListView to match the files on the file system. The list modification is done within a Platform.runLater call to ensure that the modifications to the list backing the list view occur on the JavaFX application thread, so that the active scene graph is not modified off of the JavaFX application thread.
import javafx.application.*;
import javafx.collections.*;
import javafx.collections.transformation.SortedList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
import java.io.File;
import java.nio.file.*;
import java.util.Arrays;
import java.util.Comparator;
public class FileWatcher extends Application {
private static final Path WATCH_DIR = Paths.get(System.getProperty("user.dir"));
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
ObservableList<File> songFileList = FXCollections.observableArrayList();
SortedList<File> sortedSongFileList = new SortedList<>(
songFileList,
Comparator.comparing(File::getName)
);
ListView<File> songListView = new ListView<>();
songListView.setItems(sortedSongFileList);
songListView.setCellFactory(param -> new ListCell<File>() {
#Override
protected void updateItem(File item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
return;
}
setText(item.getName());
}
});
SongWatcher watcher = new SongWatcher(
WATCH_DIR, songFileList
);
Thread watcherThread = new Thread(watcher, "song-watcher");
watcherThread.setDaemon(true);
watcherThread.start();
Scene scene = new Scene(songListView);
stage.setScene(scene);
stage.show();
}
class SongWatcher extends Task<Void> {
private static final String SONG_EXTENSION = "mp3";
private static final long POLL_INTERVAL_MILLIS = 200;
private final Path directory;
private final ObservableList<File> songFiles;
SongWatcher(Path directory, ObservableList<File> songFiles) {
this.directory = directory;
this.songFiles = songFiles;
}
#Override
protected Void call() {
System.out.println("Started watching " + directory + " for song file changes.");
while (!isCancelled()) {
try {
Thread.sleep(POLL_INTERVAL_MILLIS);
} catch (InterruptedException e) {
if (isCancelled()) {
break;
}
Thread.currentThread().interrupt();
}
try {
if (!Files.isDirectory(directory)) {
throw new Exception("Watched directory " + directory + " is not a directory.");
}
File[] foundFiles =
directory
.toFile()
.listFiles(
(dir, name) -> name.endsWith(SONG_EXTENSION)
);
if (foundFiles == null) {
throw new Exception("Watched directory " + directory + " find files returned null (this is not expected).");
}
Platform.runLater(() -> {
// remove files from the song list which are no longer on the disk.
songFiles.removeIf(checkedFile ->
Arrays.binarySearch(foundFiles, checkedFile) < 0
);
// add any files which are on the disk which are not in the song list.
for (File file: foundFiles) {
if (!songFiles.contains(file)) {
songFiles.add(file);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void succeeded() {
System.out.println("Stopped watching " + directory + " for song file changes.");
}
#Override
protected void cancelled() {
System.out.println("Cancelled watching " + directory + " for song file changes.");
}
#Override
protected void failed() {
System.out.println("Failed watching " + directory + " for song file changes.");
if (getException() != null) {
getException().printStackTrace();
}
}
}
}
I am moving from SSIS to Pentaho, also new in java. What I would like to do is to show a simple message box in Pentaho using the Defined Java Class step (or another one).
First I tried with this code:
import javax.swing.JOptionPane;
public class MyClass
{
public static void main(String args[]){
JOptionPane.showMessageDialog(null,"Hello, this message is in a message type box." );
System.exit(0);
}
}
But I got this error:
Non-abstract class "Processor" must implement method "boolean org.pentaho.di.trans.steps.userdefinedjavaclass.TransformClassBase.processRow
I modified the code:
import javax.swing.JOptionPane;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
JOptionPane.showMessageDialog(null,"Hello world!");
System.exit(0);
return true;
}
I tested the class, I did not receive any error message, but I could not see the message box that I was expecting.
So, my question is, what else do I need to import, specify or modify in order to achieve what I want to do.
Regards.
In pdi transformations most steps require some input. Your processRow() method is called for each row, received by your User Defined Java Class step. So, if you don't have input row - the method is not called.
You may want to place some step, producing one row before and pass the output to the java step. You may use "Detect empty stream" step - it will output exactly one row without any columns. However, your java code would still require some adjustments (not sure what exactly you need to do it in java, but it seems, like you need to create some ).
So, the easiest option for you would be to use "Modified Java Script Value" (it uses Rhino javascript, not java) step and call Alert("Hello world!") function inside. But nevertheless you would still need an input row.
If you still want to do it java way, you may try following code (but I am not a java developer, so I am not sure how good that code is):
import javax.swing.*;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
Object[] r = getRow();
if (r == null) {
setOutputDone();
return false;
}
if (first)
{
first = false;
myFrame = new MyFrame();
// myFrame.setVisible(true);
JOptionPane.showMessageDialog(myFrame, "Hello world");
myFrame.dispose();
}
return true;
}
private MyFrame myFrame;
private class MyFrame extends JFrame {
public MyFrame() {
super();
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Also, please keep in mind, that kettle jobs/transformations usually are not supposed to be interactive. They may be executed on linux systems, which may have no windowing system.
So displaying such messages is usually used only for debugging and is disabled in production versions.
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//Return the string "stats" to gameLoop() as cmd
}
});
public void gameLoop(){
Scanner lineScanner = new Scanner(System.in);
cmd = "";
System.out.print(getBoard().printBoard(false));
while (!cmd.equals("quit")) {
System.out.print(">");
Scanner wordScanner = new Scanner(lineScanner.nextLine());
if (wordScanner.hasNext()) {
cmd = wordScanner.next();
if (cmd.equals("board")) {
System.out.print(getBoard().printBoard(false));
} else if (cmd.equals("ships")) {
System.out.print(getBoard().printBoard(true));
} else if (cmd.equals("help")) {
printHelp();
} else if (cmd.equals("stats")) {
printStats();
} else if (cmd.equals("fire")) {
if(fire(wordScanner)) {
printStats();
cmd = "quit";
}
} else if (cmd.equals("quit")) {
} else if (!cmd.equals("")) {
System.out.println(ILLEGAL_COMMAND);
}
}
}
}
What I'm trying to do is that when the user clicks the statsButton, the String cmd in the gameLoop would be changed to "stats". The statsButton and the gameLoop() are located in two different classes. Anyone can give me an idea how to do it? (I've attempted pipedreader/pipedwriter) and I just can't seem to get it right.
*I'm basically trying to make my console application into a GUI application without changing the original console application.
Edit: What I've tried
Class textBased
PipedInputStream in = new PipedInputStream()
public void gameLoop(){
try{
in.connect(GUIclass.out);
Scanner lineScanner = new Scanner(in);`
Class GUIclass
PipedOutputStream out = new PipedOutputStream();
PrintWriter writer;
public GUIclass(){
final PrintWriter writer = new PrintWriter(out);
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
writer.println("stats");
}
});
that's what I tried writing but it doesn't seem to work.
Regarding
I'm basically trying to make my console application into a GUI application without changing the original console application..."
My advice is simple: "don't do it".
The two applications have completely different structure, one being linear, the other being event-driven, and are not directly translatable to each other. Better to make a new GUI program from the ground up. Now if your non-GUI application contains some well-structured and behaved object-oriented classes, then by all means use those classes in your GUI's "model" or logic section, but don't try to directly translate the program flow of one type of application to the other.
Edit
Based on your posted requirements:
"You should be able to play your Battleship game through your GUI interface. In addition, the text-based front-end you wrote for project 1 should still "work" and be playable."
Correct me if I'm wrong, but I'm betting that you have several classes involved here, and only one of them is the "text-based front-end". If so, then use the non front-end classes as the model of your GUI as I suggested above, but do not use the text-based front-end for anything GUI related, and do not try to emulate it in your GUI.
Have the console application instantiate the button ActionListener and pass it to the UI. When the action event is fired, the listener will tell the console app that it happened. The method in the ActionListener will tell it what to do.
I agree with Hovercrafts comment (changed to a reply).
But in general for problems like this I would change the method signature of your gameLoop(). I would use:
public void gameLoop(Reader reader)
Then you can pass different types of readers to the loop depending on the requirement.
For a console you might do something like:
gameloop( new InputStreamReader( System.in ) );
For a GUI you could do something like:
gameLoop ( new StringReader("some text") );
Edit:
Without changing the method signature you can redirect System.in to come from the String retrieved by the ActionListener:
public class Test
{
public static void main(String args[]) throws Exception
{
String text = "some text";
System.setIn( new ByteArrayInputStream( text.getBytes() ) );
// gameloop();
Scanner lineScanner = new Scanner(System.in);
System.out.println( lineScanner.nextLine() );
}
}
If you have something like this :
class B {
public void gameLoop(){
..
}
}
and
class A{
statsButton.addActionListener(new ActionListener() {
...
});
}
You can declare reference to B in A with final . In that case it's will be visible in inner class ActionListener.
class A{
final B b = ...; //final variable is visible in inner class
statsButton.addActionListener(new ActionListener() {
b.gameLoop();
...
});
}
I have an application which updates a variable about between 5 to 50 times a second and I am looking for some way of drawing a continuous XY plot of this change in real-time.
Though JFreeChart is not recommended for such a high update rate, many users still say that it works for them. I've tried using this demo and modified it to display a random variable, but it seems to use up 100% CPU usage all the time. Even if I ignore that, I do not want to be restricted to JFreeChart's ui class for constructing forms (though I'm not sure what its capabilities are exactly). Would it be possible to integrate it with Java's "forms" and drop-down menus? (as are available in VB) Otherwise, are there any alternatives I could look into?
EDIT: I'm new to Swing, so I've put together a code just to test the functionality of JFreeChart with it (while avoiding the use of the ApplicationFrame class of JFree since I'm not sure how that will work with Swing's combo boxes and buttons). Right now, the graph is being updated immediately and CPU usage is high. Would it be possible to buffer the value with new Millisecond() and update it maybe twice a second? Also, can I add other components to the rest of the JFrame without disrupting JFreeChart? How would I do that? frame.getContentPane().add(new Button("Click")) seems to overwrite the graph.
package graphtest;
import java.util.Random;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
public class Main {
static TimeSeries ts = new TimeSeries("data", Millisecond.class);
public static void main(String[] args) throws InterruptedException {
gen myGen = new gen();
new Thread(myGen).start();
TimeSeriesCollection dataset = new TimeSeriesCollection(ts);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"GraphTest",
"Time",
"Value",
dataset,
true,
true,
false
);
final XYPlot plot = chart.getXYPlot();
ValueAxis axis = plot.getDomainAxis();
axis.setAutoRange(true);
axis.setFixedAutoRange(60000.0);
JFrame frame = new JFrame("GraphTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ChartPanel label = new ChartPanel(chart);
frame.getContentPane().add(label);
//Suppose I add combo boxes and buttons here later
frame.pack();
frame.setVisible(true);
}
static class gen implements Runnable {
private Random randGen = new Random();
public void run() {
while(true) {
int num = randGen.nextInt(1000);
System.out.println(num);
ts.addOrUpdate(new Millisecond(), num);
try {
Thread.sleep(20);
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
}
}
If your variable is updating that fast, there's no point in updating a chart every time.
Have you thought about buffering the variable changes, and refreshing the chart on a different thread, say, every 5s ? You should find that JFreeChart can handle such update rates well.
Since JFreeChart is a normal desktop library, you can integrate it with a standard Swing application very easily. Or, you can use it to chart via a web application (by rendering to a JPEG/PNG etc. JFreeChart can generate image maps automatically as well, so you can use mouseovers etc.)
In order to get your CPU well below 100% and allow your GUI to remain responsive, you have to throttle back your chart updating rate. A maximum update rate of around 24 frames per second makes sense for a real-time chart; any faster is more or less indistinguishable anyway. If your data is coming in faster than that rate, you just need to buffer it in the background and update your chart in the foreground at your desired update rate. In the following example, I use XChart along with a SwingWorker background thread. The data capture is simulated at a rate of one per every 5 ms and the chart is updated at 24 frames per second. This concept should work with JFreeCharts or any other charting library as well with slight modification. Disclaimer: I'm the lead developer of XChart.
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingWorker;
import org.knowm.xchart.QuickChart;
import org.knowm.xchart.SwingWrapper;
import org.knowm.xchart.XYChart;
/**
* Creates a real-time chart using SwingWorker
*/
public class SwingWorkerRealTime {
MySwingWorker mySwingWorker;
SwingWrapper<XYChart> sw;
XYChart chart;
public static void main(String[] args) throws Exception {
SwingWorkerRealTime swingWorkerRealTime = new SwingWorkerRealTime();
swingWorkerRealTime.go();
}
private void go() {
// Create Chart
chart = QuickChart.getChart("SwingWorker XChart Real-time Demo", "Time", "Value", "randomWalk", new double[] { 0 }, new double[] { 0 });
chart.getStyler().setLegendVisible(false);
chart.getStyler().setXAxisTicksVisible(false);
// Show it
sw = new SwingWrapper<XYChart>(chart);
sw.displayChart();
mySwingWorker = new MySwingWorker();
mySwingWorker.execute();
}
private class MySwingWorker extends SwingWorker<Boolean, double[]> {
LinkedList<Double> fifo = new LinkedList<Double>();
public MySwingWorker() {
fifo.add(0.0);
}
#Override
protected Boolean doInBackground() throws Exception {
while (!isCancelled()) {
fifo.add(fifo.get(fifo.size() - 1) + Math.random() - .5);
if (fifo.size() > 500) {
fifo.removeFirst();
}
double[] array = new double[fifo.size()];
for (int i = 0; i < fifo.size(); i++) {
array[i] = fifo.get(i);
}
publish(array);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// eat it. caught when interrupt is called
System.out.println("MySwingWorker shut down.");
}
}
return true;
}
#Override
protected void process(List<double[]> chunks) {
System.out.println("number of chunks: " + chunks.size());
double[] mostRecentDataSet = chunks.get(chunks.size() - 1);
chart.updateXYSeries("randomWalk", null, mostRecentDataSet, null);
sw.repaintChart();
long start = System.currentTimeMillis();
long duration = System.currentTimeMillis() - start;
try {
Thread.sleep(40 - duration); // 40 ms ==> 25fps
// Thread.sleep(400 - duration); // 40 ms ==> 2.5fps
} catch (InterruptedException e) {
}
}
}
}
According to this blog post:
http://jonathanwatmough.com/2008/02/prototyping-code-in-clojure/
its possible to implement 'real-ish time' display of audio spectrums using the KJ DSP library:
http://sirk.sytes.net/software/libs/kjdss/index.htm
so if you can get by with fairly simple charts it might be an alternative to JFreeChart.
If the data is updating more often than you can generate the chart, then you should have a task in a separate thread that regenerates the chart, and starts another regeneration when it's done. There's little point in running it ore often than that, but if it turns out to be too much of a cpu load, you can throttle back the frequency with which it restarts. If updates don't come in, you don't trigger the re-generate. I did something like that in my Zocalo project recently. It does everything but the throttling back.
package net.commerce.zocalo.freechart;
// Copyright 2009 Chris Hibbert. All rights reserved.
// This software is published under the terms of the MIT license, a copy
// of which has been included with this distribution in the LICENSE file.
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.Map;
import java.util.HashMap;
/** Schedule a task like generating a price history graph. Multiple requests may come
in sporadically. We want to ensure that only one is being processed at a time. If we're
busy processing when a request comes in, we'll remember to start another when this one is
done. Multiple requests that come in while processing will spur a single restart. */
public class ChartScheduler {
static private Logger log = Logger.getLogger(ChartScheduler.class);
static private Map<String, ChartScheduler> schedulers = new HashMap<String, ChartScheduler>();
private AtomicBoolean generating = new AtomicBoolean(false);
private AtomicBoolean requested = new AtomicBoolean(false);
private ExecutorService threads = Executors.newCachedThreadPool();
private Callable<Boolean> callable;
private int runs = 0;
private String name;
private ChartScheduler(String name, final Runnable worker) {
this.name = name;
callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
worker.run();
runs++;
restartIfNeeded();
return true;
}
};
}
public static ChartScheduler create(String name, Runnable worker) {
ChartScheduler sched = find(name);
if (sched == null) {
sched = new ChartScheduler(name, worker);
schedulers.put(name, sched);
}
return sched;
}
public static ChartScheduler find(String name) {
return schedulers.get(name);
}
public boolean generateNewChart() {
requested.set(true);
if (generating.compareAndSet(false, true)) {
startNewThread();
return true;
} else {
return false;
}
}
private Future<Boolean> startNewThread() {
generating.set(true);
requested.set(false);
return threads.submit(callable);
}
private boolean restartIfNeeded() {
generating.set(false);
if (requested.get()) {
return generateNewChart();
} else {
return false;
}
}
public boolean isBusy() {
return generating.get();
}
public int runs() {
return runs;
}
}
Answered before here. Your variable changes up to 50 times per second, but in most cases you won't need to update every time a change is made. Instead you could update the graph at regular intervals (every 100ms for instance).
Well I am also using JFreechart for high updates. JFreeChart updates up to 10 to 15 frame/second but using 100% CPU usage. But if I want to update it at a much higher frequency it wont be updated. If you find any any library which can be updated at abt 20 fps and can be used to develop a application in Java then please suggest me also. I have seen many library JFreeChart FAQ but I am not sure if anyone could be use for updates at about 20 fps.
You should try out charts from VisualVM (part of JDK).
Intro on it: http://java.dzone.com/news/real-time-charts-java-desktop
Maybe you can use two threads. One for the updating of your variable witch priority equals to 10.
And a second thread who paints so fast as posible witch priority equals to 5.
I had to do the same in a game I'm writing.
It's possible I didn't understand your question.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
Hey, I've been developing an application in the windows console with Java, and want to put it online in all of its console-graphics-glory.
Is there a simple web applet API I can use to port my app over?
I'm just using basic System.out and System.in functionality, but I'm happy to rebuild my I/O wrappers.
I think something along these lines would be a great asset to any beginning Java developers who want to put their work online.
Sure, just make into an applet, put a small swing UI on it with a JFrame with two components - one for writing output to, and one for entering inputs from. Embed the applet in the page.
I did as Lars suggested and wrote my own.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.awt.Font;
public class Applet extends JFrame {
static final long serialVersionUID = 1;
/** Text area for console output. */
protected JTextArea textArea;
/** Text box for user input. */
protected JTextField textBox;
/** "GO" button, in case they don't know to hit enter. */
protected JButton goButton;
protected PrintStream printStream;
protected BufferedReader bufferedReader;
/**
* This function is called when they hit ENTER or click GO.
*/
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
goButton.setEnabled(false);
SwingUtilities.invokeLater(
new Thread() {
public void run() {
String userInput = textBox.getText();
printStream.println("> "+userInput);
Input.inString = userInput;
textBox.setText("");
goButton.setEnabled(true);
}
}
);
}
};
public void println(final String string) {
SwingUtilities.invokeLater(
new Thread() {
public void run() {
printStream.println(string);
}
}
);
}
public void printmsg(final String string) {
SwingUtilities.invokeLater(
new Thread() {
public void run() {
printStream.print(string);
}
}
);
}
public Applet() throws IOException {
super("My Applet Title");
Container contentPane = getContentPane();
textArea = new JTextArea(30, 60);
JScrollPane jScrollPane = new JScrollPane(textArea);
final JScrollBar jScrollBar = jScrollPane.getVerticalScrollBar();
contentPane.add(BorderLayout.NORTH, jScrollPane);
textArea.setFocusable(false);
textArea.setAutoscrolls(true);
textArea.setFont(new Font("Comic Sans MS", Font.TRUETYPE_FONT, 14));
// TODO This might be overkill
new Thread() {
public void run() {
while(true) {
jScrollBar.setValue(jScrollBar.getMaximum());
try{
Thread.sleep(100);
} catch (Exception e) {}
}
}
}.start();
JPanel panel;
contentPane.add(BorderLayout.CENTER, panel = new JPanel());
panel.add(textBox = new JTextField(55));
textBox.addActionListener(actionListener);
panel.add(goButton = new JButton("GO"));
goButton.addActionListener(actionListener);
pack();
// End of GUI stuff
PipedInputStream inputStream;
PipedOutputStream outputStream;
inputStream = new PipedInputStream();
outputStream = new PipedOutputStream(inputStream);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "ISO8859_1"));
printStream = new PrintStream(outputStream);
new Thread() {
public void run() {
try {
String line;
while ((line = bufferedReader.readLine()) != null) {
textArea.append(line+"\n");
}
} catch (IOException ioException) {
textArea.append("ERROR");
}
}
}.start();
}
}
This below code was in a separate class, "Input", which has a static "inString" string.
public static String getString() {
inString = "";
// Wait for input
while (inString == "") {
try{
Thread.sleep(100);
} catch (Exception e) {}
}
return inString;
}
Through-out the lifespan of the project I will probably maintain this code some more, but at this point - it works :)
As a premier example of a glorious and incredibly useful cnsole-like webapp, please see goosh, the Google Shell. I cannot imagine browsing the Net without it anymore.
Granted, there's no source code, but you might get out a bit of its magic by using Firebug or so.
Using a TextArea might be a bug-prone approach. Remember that you'll need to do both input and output to this TextArea and that you must thus keep track of cursor position. I would suggest that, if you really do this approach, you abstract away over a plain TextArea (inheritance, maybe?) and use a component that has, e.g. a prompt() to show the prompt and enable input and a also follows the usual shell abstraction of having stdin (an InputStream, that reads from the prompt, but can be bound to, let's say files or so) and stdout and possibly stderr, OutputStreams, bound to the TextArea's text.
It's not an easy task, and I don't know of any library to do it.
I remember seenig telnet client applet implementationa around years ago (back when people used telnet). Maybe you could dig them out and modify them.
System.out and System.in are statics and therefore evil. You'll need to go through your program replacing them with non-statics ("parameterise from above"). From an applet you can't use System.setOut/setErr/setIn.
Then you're pretty much sorted. An applet. Add a TextArea (or equivalent). Append output to the text area. Write key strokes to the input. Job done.