This question already has answers here:
Clone JavaFX Node?
(2 answers)
Closed 3 years ago.
I'm trying to deep copy an array of my custom object "Space", which extends javafx Pane.
I've tried using Kryo libraries, and implementing clonable. I could use work arounds that don't actually deep copy, but that will make my code 100x more janky.
Currently I have the class Space:
public class Space extends Pane {
private boolean available = true;
private boolean light;
private int x;
private int y;
private Peice peice;
private Label peiceImage;
private Rectangle border;
public Space() {}
public Space(int x, int y, boolean light) {
border = new Rectangle(80,80);
if (!light) {
border.setFill(Color.DARKGREEN);
border.setStroke(Color.DARKGREEN);
} else {
border.setFill(null);
border.setStroke(null);
}
peiceImage = new Label();
peiceImage.setTranslateX(16);
peiceImage.setTranslateY(16);
getChildren().addAll(border,peiceImage);
this.x = x;
this.y = y;
this.peice = null;
this.light = light;
}
//other unimportant methods.
}
I then try to copy in another file:
public Space[][] copyBoard(Space[][] thisBoard) {
Kryo kryo = new Kryo();
Space[][] copy = new Space[8][8];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Space thisSpace = thisBoard[x][y];
try {
kryo.setRegistrationRequired(false);
copy[x][y] = kryo.copy(thisSpace); //TODO This causes exception, dosent work
} catch (Exception e) {
System.out.println(e);
}
}
}
return copy;
}
Trying to use the kryo library I get this error:
com.esotericsoftware.kryo.KryoException: Class cannot be created (missing no-arg constructor): javafx.scene.layout.Region$3
But I'm not in any way commited to using kryo.
Thanks.
You can do deep copy using serialization and afterward deserialization. There are nice utils to do so on the web. For example SerializationUtils from Apache.
You can do something like the following:
Space clonedSpace = SerializationUtils.clone(space);
Docs
Related
I have a base class named Train:
public abstract class Train {
String serialNo;
float weight;
final String label;
public Train(String serialNo, float weight, String label) {
this.serialNo = serialNo;
this.weight = weight;
this.label = label;
}
public abstract float getCapacity();
}
And I have 2 classes implementing the abstract class(I will not include getters and setters in the code):
public class FreightTrain extends Train implements Cloneable {
private float capacityKg;
Vector<String> freightVector = new Vector<String>();
public FreightTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.capacityKg;
}
}
And the PassengerTrain class:
public class PassengerTrain extends Train implements Cloneable {
private float seatNo;
Vector<String> passengerId = new Vector<String>();
public PassengerTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.seatNo;
}
}
Next I have an array list ArrayList<Train> arr; which contains both: the PassengerTrain and FreightTrain. I want to create methods to write the items from arr to a file and read the data from file
Here is my attempt:
public void writeObjectInTextFile(ArrayList<Train> array) {
Formatter f = null;
try {
f = new Formatter(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
for(Train train: array) {
if(train instanceof PassengerTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float seatNo = ((PassengerTrain) train).getSeatNo();
String passId = "";
for(String id:((PassengerTrain) train).getPassengerId()) {
passId += id;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacity, seatNo, passId);
} else if(train instanceof FreightTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float capacityKg = ((FreightTrain) train).getCapacityKg();
String freightVector = "";
for(String freight: ((FreightTrain) train).getFreightVector()) {
freightVector += freight;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacityKg, capacity, freightVector);
}
}
f.close();
}
But I have a problem: I am unable to create a function that will read this data from the file, and return the correct ArrayList with the initial data.
What is the best and fastest way to write the array of 2 different classes deriving from a single class to a file?
And how it could be recreated?
Thank you!
Please don't my question as duplicate. I have searched for similar questions and my question is different from the ones available.
I don't know how to convert back the objects from file to their respective types. What If I have n deriving classes?
Simply have your classes implement Serializable and you'll be ready to write your objects to files (and read them back, of course) whenever you want! This includes arrays of your objects, too.
That's the 10000-foot answer above. Implementing Serializable correctly (in a way that won't come back around to bite you) is a somewhat daunting subject. However, there is plenty of literature out there that can teach you how to do it and how to avoid common pitfalls. I recommend Joshua Bloch's "Effective Java" for this, personally; he's dedicated a whole chapter or two to the subject.
if(train instanceof PassengerTrain) This is bad. You are completely throwing the whole purpose of inheritance and polymorphism away. Your code shouldn't care about what type the trains are.
You should use the Object serialization features of Java. Implement Serializable in your Train class and use ObjectOutputStream to write and ObjectInputStream to read the objects.
Write:
public void writeTrainsToFile(ArrayList<Train> array, String file) {
FileOutputStream fileOutputStream = new FileOutputStream(file);
try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)){
objectOutputStream.writeInt(array.size());
for(Train train: array) {
objectOutputStream.writeObject(train);
}
}
}
Read:
public void readTrainsFromFile(ArrayList<Train> array, String file) {
FileInputStream fileInputStream = new FileInputStream(file);
try(ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)){
int trainCount = objectInputStream.readInt();
for (int i = 0; i < trainCount; i++) {
array.add((Train)objectInputStream.readObject());
}
}
}
I've been working on a cell evolution simulation in Java. Just so everyone knows, I'm a beginner/intermediate Java programmer. I know pretty much all the basics and then a little bit, but I don't quite have the skills to write code from scratch. The code I have here is roughly based on a source I found online, I added my own touches and some other pieces I found online as well. It seems to work just fine, except the screen flickers. It seems every time the repaint() is called it flickers, probably clearing and redrawing. It creates something that is practically impossible to look at. There are no errors in my code. I am new to using applets, so if there is a better way to do this, please let me know. How can I stop the screen from flickering? Is there an easy way to buffer the images to prevent that? Here's the class that draws the applet
/* <!-- Defines the applet element used by the appletviewer. -->
<applet code='CellLife.java' width='1920' height='1080'></applet> */
import java.applet.Applet;
import java.awt.Event;
import java.awt.Graphics;
import java.util.Enumeration;
import java.util.Vector;
public class CellLife extends Applet implements Runnable {
// ========================================================================
// VARIABLES
// ========================================================================
// Data
/** Thread object for CellLife applet */
private Thread m_cellLife = null;
// Static constants
/**
* the maximum number of creatures in the world. When the number of
* creatures alive drops below half this, a new one is created to bring the
* numbers back up.
*/
protected static final int MAX_CREATURES = 60;
// Data
/**
* A list of the creatures currently alive. Stores CLCreature references.
*/
protected Vector creatures;
/** The world is a rectangle from (0,0) to (limit.x,limit,y) */
protected CL2dVector limit;
/**
* The number of creatures that have been born since the simulation started
*/
protected long generations;
/** A test creature controllable by the user to allow response testing */
private CLCreature testCreature;
/** space-partitioning structure to speed collision detection */
protected CLBuckets buckets;
// ========================================================================
// METHODS
// ========================================================================
public CellLife() {
creatures = new Vector();
limit = new CL2dVector(500.0F, 500.0F);
generations = 0;
// initilaize our bucket structure
float bucketScale = CLCell.RADIUS; // could stretch to root-two times
// this
buckets = new CLBuckets(bucketScale, (int) Math.ceil(limit.x / bucketScale), (int) Math.ceil(limit.y / bucketScale));
}
public String getAppletInfo() {
return "Name: Cell Evolution\r\n" + "Author: Josh Marchand\r\n" + "Made in Eclipse";
}
// first time initialazion
public void init() {
resize((int) limit.x, (int) limit.y);
for (int i = 0; i < MAX_CREATURES; i++) {
CLCreature new_creature = new CLCreature();
new_creature.InitSimple(limit, buckets);
creatures.addElement(new_creature);
}
}
public void destroy() {
// TODO: Place applet cleanup code here
}
public void paint(Graphics g) {
g.drawString("No. creatures: " + creatures.size(), 0, 11);
g.drawString("Births: " + generations, 0, 22);
// draw cells
for (int i = 0; i < creatures.size(); i++) {
((CLCreature) creatures.elementAt(i)).Draw(g);
}
// DEBUG: also indicate the contents of the buckets
// buckets.Draw(g);
// get all creatures to do their stuff
CLCreature creature;
for (int i = 0; i < creatures.size(); i++) {
creature = (CLCreature) creatures.elementAt(i);
if (creature.DoTimeStep(g, buckets, limit) && creatures.size() < MAX_CREATURES) {
// inherit new creature from current
CLCreature newCreature = new CLCreature();
newCreature.InheritFrom(creature, buckets, limit);
creatures.addElement(newCreature);
generations++;
}
}
// delete the ones that died doing it
for (Enumeration e = creatures.elements(); e.hasMoreElements();) {
creature = (CLCreature) e.nextElement();
if (creature.hasDied) creatures.removeElement(creature);
}
// breed nwe creatures if pop. is low
if (creatures.size() < MAX_CREATURES / 2) {
// just add one for now,fix later
CLCreature newCreature = new CLCreature();
newCreature.InheritFrom((CLCreature) creatures.elementAt((int) Math.random() * creatures.size()), buckets, limit);
creatures.addElement(newCreature);
generations++;
}
}
public void start() {
if (m_cellLife == null) {
m_cellLife = new Thread(this);
m_cellLife.start();
}
// TODO: place any additional startup code here
}
public void stop() {
if (m_cellLife != null) {
m_cellLife.stop();
m_cellLife = null;
}
}
public void run() {
while (true) {
try {
repaint();
// quick nap here to allow user interface to catch up
Thread.sleep(100);
} catch (InterruptedException e) {
stop();
}
}
}
public boolean mouseDown(Event e, int x, int y) {
// create a single celled creature at specific loc
testCreature = new CLCreature();
testCreature.rootCell.location.x = x;
testCreature.rootCell.location.y = y;
testCreature.rootCell.type = CLGene.RED;
creatures.addElement(testCreature);
buckets.PutCell(testCreature.rootCell);
return true;
}
public boolean mouseDrag(Event e, int x, int y) {
testCreature.rootCell.location.x = x;
testCreature.rootCell.location.y = y;
return true;
}
public boolean mouseUp(Event evt, int x, int y) {
creatures.removeElement(testCreature);
buckets.RemoveCell(testCreature.rootCell);
return true;
}
}
Thank you all so much for the help, and I'm very sorry about my "noobiness", I am doing my best to teach myself!
I would consider using technique called double buffering, where you create an offscreen Graphics object bound to and Image, perform all the drawing on that then paint the result to screen.
You can find a handy tutorial on creating graphics from image here. More complete sample can be found here.
I'm following this sample in order to learn about RenderScript. I added the following at project.properties:
renderscript.target=19
renderscript.support.mode=true
sdk.buildtools=23.0.2
I wrote my .rs file, the ScriptC_myfilename was generated at gen folder but the android.support.v8.renderscript could not be resolved to a type, so I added the renderscript-v8.jar located at sdk/build-tools/android-4.4W/renderscript/lib as a library (configure Build Path >> Libraries >> add External JARs) and the problem was fixed.
After codding, I couldn't compile the code due to this error, found on ScriptC_filename.java at gen folder:
Mesh cannot be resolved to a Type
I search about the issue, trying to find the missing class and, I don't know, maybe manually implement this class as a part of my project, so Eclipse would be allowed to import it and fix the error, but I'm a bit confused since the Mesh class isn't cited even on android docs.
I also tried to import the renderscript-v8.jar at sdk\build-tools\android-4.4.2\renderscript\lib, as well as add import android.support.v8.renderscript.Mesh but with no success.
I don't know if this would help, but this is my ScriptC_Snow.java file (everything here was generated, I didn't edit it), The comments is the error showed on Eclipse
public class ScriptC_Snow extends ScriptC {
private static final String __rs_resource_name = "snow";
public ScriptC_Snow(RenderScript rs) {
this(rs,
rs.getApplicationContext().getResources(),
rs.getApplicationContext().getResources().getIdentifier(
__rs_resource_name, "raw",
rs.getApplicationContext().getPackageName()));
}
public ScriptC_Snow(RenderScript rs, Resources resources, int id) {
super(rs, resources, id);
__MESH = Element.MESH(rs); //the method MESH(RenderScript) is undefined for the type Element
__F32_2 = Element.F32_2(rs);
}
private Element __F32_2;
private Element __MESH;
private FieldPacker __rs_fp_F32_2;
private FieldPacker __rs_fp_MESH;
private final static int mExportVarIdx_snowMesh = 0;
private Mesh mExportVar_snowMesh; // Mesh cannot be resolved to a type
public synchronized void set_snowMesh(Mesh v) { // Mesh cannot be resolved to a type
setVar(mExportVarIdx_snowMesh, v);
mExportVar_snowMesh = v; // Mesh cannot be resolved to a type
}
public Mesh get_snowMesh() { // Mesh cannot be resolved to a type
return mExportVar_snowMesh; // Mesh cannot be resolved to a type
}
public Script.FieldID getFieldID_snowMesh() {
return createFieldID(mExportVarIdx_snowMesh, null);
}
private final static int mExportVarIdx_snow = 1;
private ScriptField_Snow mExportVar_snow;
public void bind_snow(ScriptField_Snow v) {
mExportVar_snow = v;
if (v == null) bindAllocation(null, mExportVarIdx_snow);
else bindAllocation(v.getAllocation(), mExportVarIdx_snow);
}
public ScriptField_Snow get_snow() {
return mExportVar_snow;
}
private final static int mExportVarIdx_wind = 2;
private Float2 mExportVar_wind;
public synchronized void set_wind(Float2 v) {
mExportVar_wind = v;
FieldPacker fp = new FieldPacker(8);
fp.addF32(v);
int []__dimArr = new int[1];
__dimArr[0] = 4;
setVar(mExportVarIdx_wind, fp, __F32_2, __dimArr);
}
public Float2 get_wind() {
return mExportVar_wind;
}
public Script.FieldID getFieldID_wind() {
return createFieldID(mExportVarIdx_wind, null);
}
private final static int mExportVarIdx_grav = 3;
private Float2 mExportVar_grav;
public synchronized void set_grav(Float2 v) {
mExportVar_grav = v;
FieldPacker fp = new FieldPacker(8);
fp.addF32(v);
int []__dimArr = new int[1];
__dimArr[0] = 4;
setVar(mExportVarIdx_grav, fp, __F32_2, __dimArr);
}
public Float2 get_grav() {
return mExportVar_grav;
}
public Script.FieldID getFieldID_grav() {
return createFieldID(mExportVarIdx_grav, null);
}
private final static int mExportFuncIdx_initSnow = 0;
public void invoke_initSnow() {
invoke(mExportFuncIdx_initSnow);
}
}
This is my renderscript code (.rs file):
#pragma version(1)
#pragma rs java_package_name(com.mypackage.script)
#include "rs_graphics.rsh"
rs_mesh snowMesh;
typedef struct __attribute__((packed, aligned(4))) Snow {
enter code here
float2 velocity;
float2 position;
uchar4 color;
enter code here
} Snow_t;
Snow_t *snow;
float2 wind;
float2 grav;
int root() {
rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
rsgDrawMesh(snowMesh);
return 0;
}
void init() {
grav.x = 0;
grav.y = 18;
wind.x = rsRand(50)+20;
wind.y = rsRand(4) - 2;
}
void initSnow() {
enter code here
const float w = rsgGetWidth();
const float h = rsgGetHeight();
int snowCount = rsAllocationGetDimX(rsGetAllocation(snow));
Snow_t *pSnow = snow;
for (int i=0; i < snowCount; i++) {
pSnow->position.x = rsRand(w);
pSnow->position.y = rsRand(h);
pSnow->velocity.y = rsRand(60);
pSnow->velocity.x = rsRand(100);
pSnow->velocity.x -= 50;
uchar4 c = rsPackColorTo8888(255, 255, 255);
pSnow->color = c;
pSnow++;
}
}
I only used the SDK Manager to obtain the files, is there anything I'm missing? Anyone can give me a link to donwload the latest version of renderscript-v8.jar? Is there any link that I could use to see the missing class, in order to implement it in my project, so Eclipse'd be allowed to import and use it?
Thanks in advance.
You can't use the support library with rs_graphics.rsh. It doesn't support objects like rs_mesh, rs_font, or rs_program*. The support library is only for accessing RenderScript compute.
I am currently making a terrain generator, everything works fine in one class but I am going to be expanding my application.
Currently I have a JFrame class which holds everything, generating the terrain, painting the terrain, finding locations etc.
I want to add another class that will generate the terrain but when I create this class I need to access fields from the main JFrame class and when I do I get a stack overflow error - here is my code.
public class Simulator extends Applet
{
//fields
public Simulator()
{
grid = new int[100][100];
inhabGrid = new boolean[grid.length][grid.length];
gridSize = grid.length - 1;
dist = grid.length;
TerrainGenerator gen = new TerrainGenerator();
setSize(dist,dist);
seedGrid();
findInhabLocation();
printGridToConsole();
}
public void paint(Graphics g)
{
//panting the grid
}
public void seedGrid()
{
//seeding
}
public boolean generateTerrain(int x1,int y1, int x2, int y2)
{
//terrain generator
}
public boolean mouseUp(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public boolean keyEvents(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public void findInhabLocation()
{
//find best inhabitant location
}
public int locateWater(int x, int y)
{
//finding closest water
}
public int locateJungle(int x, int y)
{
//finding closest jungle
}
}
}
That works fine in its own class but when I create a class for example:
public class TerrainGenerator
{
Simulator sim = new Simulator();
}
I know this has something to do with the constructor and it's something silly I am doing, what would be the best way of splitting up this app into classes, for example terrain generator, inhabitants etc
For example I want to be able to call a method from the 'TerrainGenerator' class and call i.e. terrainGenerator.generateTerrain
Your TerrainGenerator creates a Simulator object and vice versa, hence you'll end up with infinitely many objects (but at some point the stack is full and a stack overflow exception is thrown instead...)
Instead of creating a new Simulator in your TerrainGenerator, you should pass a reference to your current Simulator (well, actually, that is not a great design either, but I'm not gonna confuse you with the problems of circular references).
Heuster answer is correct, furthermore, I think you could take look at MVC to help you organize your classes.
Depending which should be the parent, you can pass in the instantiated class to the other, ie;
private final TerrainGenerator gen; //if you need to save this.
public Simulator(TerrainGenerator terrainGenerator)
{
this.gen = terrainGenerator;
....etc
}
public class TerrainGenerator
{
Simulator sim = new Simulator(this);
}
or
private final TerrainGenerator gen; //if you need to save this.
public Simulator()
{
this.gen = new TerrainGenerator(this);
....etc
}
private final Simulator sim; //If you need to save it.
public class TerrainGenerator
{
public TerrainGenerator(Simulator simulator) {
this.sim = simulator;
}
}
I was wondering if there was an easy way to save arrays of objects, without having to go through and save each aspect of the the objects. In my example I have two arrays, one a single array and the other a 2D array, that contain objects referring to a custom class. Each object has specific details like x and y ints, booleans, strings, ect. attached to them (block[0].x, block[0].canWalk, block[0].name) and I was wondering if there is an easy way of saving these arrays to a file without having to use a for loop and save each part. The multidimensional array is simply an array of saved arrays identical to the first one (savedBlock[0][0].x ...)
What I have so far (throwing NotSerializableException):
public class Save
{
static File f;
static ObjectOutputStream os;
public static void openFile()
{
try
{
if(!new File("c:\\IDsGame").exists())
{
new File("c:\\IDsGame").mkdirs();
}
f = new File("c:\\IDsGame\\data.bin");
os = new ObjectOutputStream(new FileOutputStream(f));
writeFile();
}
catch(Exception e)
{
System.err.println("creating file");
}
}
public static void writeFile()
{
try
{
ArrayList<Object> map = new ArrayList<Object>(Arrays.asList(Map.block));
ArrayList<Object> savedMaps = new ArrayList<Object>(Arrays.asList(Map.savedMaps));
os.writeObject(map);
os.writeObject(savedMaps);
os.close();
}
catch (IOException e) {System.out.println(e);}
}
}
Within my map class I initialize block (Blocks[]) and savedMaps(Blocks[][]). My Blocks class holds this:
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public Image img = null, imgBack = null;
public final Image (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Obviously I change the certain parts different arrays within the Map class, and I was wondering if there was any easier way (at all) to save the arrays of Blocks Objects.
Thanks for taking your time to help and if you need any more specific just let me know.
I.D.
Image is not serializable, so you receive a NotSerializableException when the Blocks class is serialized. ImageIcon can be serialized, so wrapping Image instances in ImageIcons will solve that issue.
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public ImageIcon img = null, imgBack = null;
public final ImageIcon (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
// img = new ImageIcon(someImageInstance)
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Just making a class implement Serializable is not enough: All the fields must be Serializable too.
Your Block class may have a problem. All the usual java classes are Serializable, but Block also has fields of type Image. If Image isn't Serializable, then attempting to serialize Block will throw NotSerializableException.