I've got a slight problem, I'm writing a gps tracking app to track several objects at once. The data comes in over a serial interface, this is coming in fine from what I can tell. The issue is that I need to continually update the JPanel where the map is created and displayed.
public JPanel mapDisplay(){
JPanel mapPanel = new JPanel();
mapPanel.setSize(560, 540);
Coordinate start = new Coordinate (-34.9286, 138.6);
trackMap.addMapMarker(new MapMarkerDot(1Lat, 1Lon));
trackMap.setDisplayPosition(start,8);
System.out.println(1Lat);
mapPanel.add(trackMap);
mapPanel.setVisible(true);
return mapPanel;
}
This is what I have and it's happy to display the point once but won't update. If I print out the 1Lat variable in the serial method it continually prints, however it only does it once here.
A lot of the answers I've found refer to setting markers by arrays, however that won't work in this case as the objects I'm tracking could be anywhere.
Any help would be greatly appreciated :)
Is it possible to use a worker thread and not use an ArrayList? I would run the risk of missing data if I do.
Not necessarily. In a SwingWorker, your implementation of the doInBackground() method can publish() results as they become available. Note in particular that "Results from multiple invocations of publish() are often accumulated for a single invocation of process()." In your process(), simply loop through the List<Coordinate>, update the route and repaint() the map.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
/**
* #see http://stackoverflow.com/a/37193636/230513
*/
public class MapWorkerTest {
private final List<Coordinate> route = new ArrayList<>();
private void display() {
JFrame f = new JFrame("MapWorker");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMapViewer map = new JMapViewer() {
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
#Override
public String getToolTipText(MouseEvent e) {
Coordinate c = (Coordinate) getPosition(e.getX(), e.getY());
return c.getLat() + " " + c.getLon();
}
};
map.setToolTipText("");
Coordinate start = new Coordinate(-34.9286, 138.6);
route.add(start);
MapPolygonImpl poly = new MapPolygonImpl(route);
poly.setColor(Color.blue);
map.addMapPolygon(poly);
map.setDisplayPosition(start, 10);
f.add(map);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
new MapWorker(map, start).execute();
}
private class MapWorker extends SwingWorker<Void, Coordinate> {
private final JMapViewer map;
private Coordinate last;
public MapWorker(JMapViewer map, Coordinate start) {
this.map = map;
this.last = start;
}
#Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
last = new Coordinate(last.getLat() + 0.0025, last.getLon() + 0.01);
publish(last);
Thread.sleep(1000);
}
return null;
}
#Override
protected void process(List<Coordinate> chunks) {
for (Coordinate c : chunks) {
route.add(c);
}
map.repaint();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new MapWorkerTest()::display);
}
}
Multiple route management left as a exercise.
Related
So i am new to JMapViewer (and StackOverFlow). What I am currently trying to do is to develop a real time graphical representation of a network, where the background is a map of the area. So far it's been going well, however one issue is bugging me. When I create a MapMarkerCircle, and set the name, I want to create a new line, to show information below it.
I've tried "\n", but this won't work. I've tried enclosing it in html format
and using <br> to break the line, but again, it just prints the entire thing as if it was a string.
If anyone has come across this issue before, I would really appreciate any help.
Here is a small bit of code where the problem is occuring. Note that "RateCircle" extends "MapMarkerCircle".
Coordinate dataPoint= new Coordinate((pmpLinks[i].getRecieverSite().getLat()+pmpLinks[i].getTransmitter().getLat())/2, (pmpLinks[i].getRecieverSite().getLon()+pmpLinks[i].getTransmitter().getLon())/2);
String rateStringName="<html>"+inRateAsString+"<br>kb/s</html>";
pmpCanopyRatePoints[i]=new RateCircle(allPMPrateLayer[i],rateStringName, dataPoint);
map().addMapMarker(pmpCanopyRatePoints[i]);
MapMarkerCircle::paint calls MapMarkerCircle::paintText, which calls Graphics::drawString, which accords no special meaning to control characters or markup. Starting from this example, the implementation of paintText() below draws a second line beneath the first.
I've updated the example to suggest a way to associate the marker's name and value. It uses a Map<String, Integer>, passing a Map.Entry<String, Integer> as a parameter to the RateCircle constructor.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.openstreetmap.gui.jmapviewer.JMapViewer;
import org.openstreetmap.gui.jmapviewer.MapMarkerCircle;
import org.openstreetmap.gui.jmapviewer.Style;
/**
* #see https://stackoverflow.com/a/38265252/230513
* #see https://stackoverflow.com/a/33857113/230513
*/
public class RateCircleTest {
private void display() {
JFrame f = new JFrame("London");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMapViewer map = new JMapViewer() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
Coordinate london = new Coordinate(51.5072, -0.1275);
map.setDisplayPosition(london, 16);
Map<String, Integer> rates = new HashMap<>();
rates.put("London", 42);
for (Map.Entry<String, Integer> entry : rates.entrySet()) {
map.addMapMarker(new RateCircle(entry, london));
}
f.add(map);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class RateCircle extends MapMarkerCircle {
private static final int R = 12;
private Map.Entry<String, Integer> entry;
public RateCircle(Map.Entry<String, Integer> entry, Coordinate coord) {
super(null, "", coord, R, STYLE.FIXED, getDefaultStyle());
this.entry = entry;
Style style = getStyle();
style.setBackColor(Color.cyan);
style.setColor(Color.red);
}
#Override
public void paintText(Graphics g, Point position) {
super.paintText(g, position);
g.drawString(entry.getKey(), position.x + R + 2, position.y + R);
g.drawString(entry.getValue() + " kb/s", position.x + R + 2,
position.y + R + g.getFontMetrics().getHeight());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new RateCircleTest()::display);
}
}
You can use System.lineSeparator():
String rateStringName = inRateAsString + System.lineSeparator() + "kb/s";
I recently have implemented clipping in my VTK Java program. I used BoxWidget to control what should be clipped. However, i'm having an issue with vtkRenderWindowInteractor that attached to BoxWidget. The program freezes at the renderWindowInteractor.Start() statement (I've remarked it in my code).
This is my re-simulate code :
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import vtk.*;
public class VTKWindowInteractor extends JPanel {
static {
if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {
if (!lib.IsLoaded()) {
System.out.println(lib.GetLibraryName() + " not loaded");
}
}
System.out.println("Make sure the search path is correct: ");
System.out.println(System.getProperty("java.library.path"));
}
vtkNativeLibrary.DisableOutputWindow(null);
}
private vtkPanel renWin;
private vtkRenderWindowInteractor renderWindowInteractor;
private vtkPolyDataMapper mapper;
private vtkActor coneActor;
private vtkPlanes planes;
private vtkBoxWidget boxWidget;
public VTKWindowInteractor() {
setLayout(new BorderLayout());
renWin = new vtkPanel();
add(renWin, BorderLayout.CENTER);
renWin.setMinimumSize(new Dimension(50, 50));
renWin.GetRenderer().SetBackground(0, 0, 0); // black
renWin.GetRenderWindow().AddRenderer(renWin.GetRenderer());
}
public void render() {
mapper = new vtkPolyDataMapper();
vtkConeSource cone = new vtkConeSource();
cone.SetHeight(3.0);
cone.SetRadius(1.0);
cone.SetResolution(10);
mapper.SetInputConnection(cone.GetOutputPort());
coneActor = new vtkActor();
coneActor.SetMapper(mapper);
renWin.GetRenderer().AddActor(coneActor);
planes = new vtkPlanes();
renderWindowInteractor = new vtkRenderWindowInteractor();
renderWindowInteractor.SetRenderWindow(renWin.GetRenderWindow());
boxWidget = new vtkBoxWidget();
boxWidget.SetInteractor(renderWindowInteractor);
boxWidget.SetPlaceFactor(1.25);
boxWidget.PlaceWidget(coneActor.GetBounds());
boxWidget.AddObserver("InteractionEvent", this, "executeClipping");
renderWindowInteractor.Initialize();
boxWidget.On();
renWin.Render();
renWin.resetCamera();
/**************************************/
// This is where the freeze come from //
// //
/************************************/
renderWindowInteractor.Start(); // if i comment out this line, the program works but the boxWidget cannot be resized or rescale or moved
}
public void executeClipping() {
planes = new vtkPlanes();
boxWidget.GetPlanes(planes);
mapper.SetClippingPlanes(planes);
planes.Delete();
}
public static final int WINDOW_WIDTH = 1000;
public static final int WINDOW_HEIGHT = 500;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
VTKWindowInteractor _vtkRendererPanel = new VTKWindowInteractor();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("......");
frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
frame.setVisible(true);
frame.setLayout(new BorderLayout());
frame.add(_vtkRendererPanel);
_vtkRendererPanel.render();
}
});
}
}
I have been finding my mistake for hours and hours and frustrated hence come here to seek for help. If anyone have experienced this or know what did I do wrong please correct me. Thanks !!!
VTK version : 6.2.0
OK. I finally solved the problem. The follows is the quote from vtkPanel.java
/*
*
* Java AWT component that encapsulate vtkRenderWindow, vtkRenderer, vtkCamera,
* vtkLight.
*
* If a vtkInteractor is needed, use vtkCanvas instead. This is necessary when
* Widget and Picker are used.
*
* #author Kitware */
so I changed my
vtkPanel
to
vtkCanvas
&
renderWindowInteractor = new vtkRenderWindowInteractor();
to
renderWindowInteractor = renWin.getRenderWindowInteractor();
and it solves the problem.
Thanks and this is for anyone who are going to face similiar problem as me in the future.
EDIT: Everything displays correctly when either field or hunterField hold no objects in any location. field and hunterField both exclusively hold objects which extend the same class, so I guess it may have something to do with inheritance...?
I have created a simple Agent-Based Model using MASON. The back-end works find, but when I try displaying my agents only "wall" agents are displayed. (Wall Portrayal) My code is below... Any idea?
package sim.app.celai;
import java.awt.Color;
import javax.swing.JFrame;
import sim.app.tutorial3.Tutorial3WithUI;
import sim.display.Controller;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.portrayal.grid.SparseGridPortrayal2D;
import sim.util.Bag;
public class FieldWithGUI extends GUIState {
public Display2D display;
public JFrame frame;
SparseGridPortrayal2D hunterPortrayal = new SparseGridPortrayal2D();
SparseGridPortrayal2D wallPortrayal = new SparseGridPortrayal2D();
SparseGridPortrayal2D childPortrayal = new SparseGridPortrayal2D();
public FieldWithGUI() {
super(new Field(System.currentTimeMillis()));
}
public void setupPortrayals() {
childPortrayal.setField(((Field) state).field);
hunterPortrayal.setField(((Field) state).hunterField);
wallPortrayal.setField(((Field) state).wallField);
childPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.blue));
hunterPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.red));
wallPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.green));
display.reset();
display.repaint();
}
public void quit()
{
super.quit();
if (frame!=null) frame.dispose();
frame = null; // let gc
display = null; // let gc
}
public static void main(String[] args)
{
new FieldWithGUI().createController();
}
public void start()
{
super.start();
// set up our portrayals
setupPortrayals();
}
public void init(Controller c)
{
super.init(c);
// Make the Display2D. We'll have it display stuff later.
display = new Display2D(400,400,this); // at 400x400, we've got 4x4 per array position
frame = display.createFrame();
c.registerFrame(frame); // register the frame so it appears in the "Display" list
frame.setVisible(true);
// specify the backdrop color -- what gets painted behind the displays
display.setBackdrop(Color.black);
// attach the portrayals
display.attach(childPortrayal, "children");
display.attach(hunterPortrayal, "hunter");
display.attach(wallPortrayal, "wall");
}
}
I am working on a Java program that takes in a large amount of files (3000 max) with an associated array of 1/0's. Currently I have a visualization of the array where there is a grid where each box is filled black for 1 or white for 0. When drawn it runs well but takes around a minute to fully load (and potentially locks the computer up in the meantime.) Is there a way I can: 1, not display the window till it is done
(i.e JFrame create,
//draw window
frame.setVisible(true))
and 2, track the progress of the process so that I can use a progress bar with it?
edit: Can I run a thread to draw it and then simply make a while loop to only display it once the thread is completed?
In the example below, a SwingWorker sets pixels in a BufferedImage based on the data read from a random file. Note that Thread.sleep() is used to simulate latency; it is otherwise not required. You can add a JProgressBar as shown here.
Is there a better way to get simple colored boxes?
Yes. In the example below, each pixel represents one cell. For larger boxes, return a multiple of the image size, e.g.
#Override
public Dimension getPreferredSize() {
return new Dimension(2 * N, 2 * N);
}
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
/**
* #see https://stackoverflow.com/a/25043676/230513
*/
public class WorkerTest {
private static final int N = 256;
private final BooleanPanel panel = new BooleanPanel();
private class BooleanPanel extends JPanel {
private BufferedImage image;
public void setImage(BufferedImage bi) {
this.image = bi;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(N, N);
}
}
private class BufferedImageWorker extends SwingWorker<BufferedImage, BufferedImage> {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage image = new BufferedImage(N, N, BufferedImage.TYPE_INT_ARGB);
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream("/dev/random")))) {
for (int row = 0; row < N; row++) {
for (int col = 0; col < N; col++) {
image.setRGB(col, row, dis.readByte() < 0 ? 0xffffffff : 0xff000000);
}
Thread.sleep(40); // ~25 Hz
publish(image);
}
return image;
}
}
#Override
protected void process(List<BufferedImage> list) {
for (BufferedImage bi : list) {
panel.setImage(bi);
panel.repaint();
}
}
}
private void display() {
JFrame f = new JFrame("WorkerTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
new BufferedImageWorker().execute();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new WorkerTest().display();
});
}
}
I would definitely use a SwingWorker in this case. Basically, maybe something along these lines (I'm not sure what type of object your 'visualization' is, so for simplicity, I'll just say it's an Image). You can add this at the bottom of your class. You'll obviously have to edit it to make it work for you.
protected class DrawGridTask extends SwingWorker<Image, Object> {
ObjectToPutImageOn imageObject;
public DrawGridTask(ObjectToPutImageOn obj) {
this.imageObject = obj;
}
protected Image doInBackground() {
// generate your Image or graphic or whatever here
return Image;
}
protected void done() {
imageObject.drawThisCompletedImage(get());
}
}
To call this method, you would run (new DrawGridTask(objectToPutImageOn)).execute();
All the code in doInBackground() will run on it's own worker thread. Done() runs on the event dispatch thread, and gets the reference doInBackground() returns when it calls get().
There is more information here, including how to do progress updates at: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
Since I mentioned Images, if you do work with them, you might also want to take a look at the MediaTracker class, this can be very useful for blocking until an image is ready.
I was wondering if there was a function like void draw() which Processing programming language uses that gets called every frame. Or even just a function that loops infinitely when it gets called but only runs through it every time there is a new frame. I heard of something called a runnable in java how do i go about using this? also is there a better way then having a runnable with a delay like a function that is hardcoded to run every frame. Oh and also what is the function call that will allow me to see how much time (in milliseconds preferably) since the application has started running that way i can make my runnables / frame calls much more precise so that the game runs about the same speed on every computer regardless of the frame rate.
Perhaps you need something like this
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Repainter extends JPanel {
private Point topLeft;
private int increamentX = 5;
public Repainter() {
topLeft = new Point(100, 100);
}
public void move() {
topLeft.x += increamentX;
if (topLeft.x >= 200 || topLeft.x <= 100) {
increamentX = -increamentX;
}
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(topLeft.x, topLeft.y, 100, 100);
}
public void startAnimation() {
SwingWorker<Object, Object> sw = new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
while (true) {
move();
Thread.sleep(100);
}
}
};
sw.execute();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Repaint Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
Repainter repainter = new Repainter();
frame.add(repainter);
repainter.startAnimation();
frame.setVisible(true);
}
});
}
}