Actors are getting lost when drop failed -libgdx - java

I am working on a rummikub game, I have a board which have tiles on it, and all positions on board are defined as TileActor. Some tile actors have actual tiles on them, some are empty. Problem is: when I drag a tile and drop it on an empty TileActor, it works fine but when I drop it on empty space, the actor is getting lost. How can I prevent the actors from getting lost?
This is my drag&drop code:
dragAndDrop.addSource(new Source(actor) {
#Override
public Payload dragStart(InputEvent event, float x, float y, int pointer) {
Payload payload = new Payload();
payload.setObject("Some payload!");
payload.setDragActor(getActor());
Label validLabel = new Label("Valid move!", skin);
validLabel.setColor(0, 1, 0, 1);
payload.setValidDragActor(validLabel);
Label invalidLabel = new Label("Invalid!", skin);
invalidLabel.setColor(1, 0, 0, 1);
payload.setInvalidDragActor(invalidLabel);
return payload;
}
dragAndDrop.addTarget(new Target(actor) {
public boolean drag (Source source, Payload payload, float x, float y, int pointer) {
getActor().setColor(Color.GREEN);
return true;
}
public void reset (Source source, Payload payload) {
getActor().setColor(Color.WHITE);
}
public void drop (Source source, Payload payload, float x, float y, int pointer) {
int movingTile =((TileActor)source.getActor()).getPosition();
if(movingTile!=-1){
int newPosition=player.moveTileOnBoard(movingTile, ((TileActor)getActor()).getPosition());
}
}
});

The problem is that you provide your own Actor to the Payload (so DragAndDrop take care about removing this actor):
payload.setDragActor(getActor());
Try to create the copy of the Actor instead:
Actor newActor = /* clone your actor from getActor() to newActor */;
payload.setDragActor(newActor);

Related

create image Hype Processing, processing.org

I am trying to create image using http://www.hypeframework.org/ and processing.org. I want to create the image and store in a folder then display it on the web using java spark. The following are the steps that I started with.
Create maven project using NetBeans
Added processing.org, spark libraries in maven
Downloaded hype processing jar added to my libraries
My question is how do I create image with then save it to the webapp folder? I am relatively new to hype and processing drawing shapes stuff. The following are my code that I put together:
Right now this cimg.setup() in the main spark controller throws java.lang.NumberFormatException: For input string: "#BC7A38,#996A37,#968063,#AB977C,#997949,#AE9162,#DFC597,#CAB790" error.
I searched google, but can't find any lead. Any help on how I should accomplish my task is greatly appreciated. Thanks!
//-- spark controller -
public class Main {
public static void main(String[] args) {
get("/", new TemplateViewRoute() {
#Override
public ModelAndView handle(Request req, Response res) throws Exception {
HashMap model = new HashMap();
HypeProcessing cimg = new HypeProcessing();
cimg.setup();
model.put("template", "templates/form.vtl");
return new ModelAndView(model, "templates/layout.vtl");
}
}, new VelocityTemplateEngine());
}
}
//--- HypeProcessing class ----
public class HypeProcessing extends PApplet
{
HDrawablePool pool;
HColorPool colors;
#Override
public void setup()
{
int h = 300;
int w = 300;
//size(w, h);
//H.init(this).background(Integer.parseInt("#202020"));
//smooth();
colors = new HColorPool(Integer.parseInt("#BC7A38,#996A37,#968063,#AB977C,#997949,#AE9162,#DFC597,#CAB790"));
pool = new HDrawablePool(121);
pool.autoAddToStage()
.add(new HShape("svg1.svg"))
.add(new HShape("svg2.svg"))
.add(new HShape("svg3.svg"))
.add(new HShape("svg4.svg"))
.add(new HShape("svg5.svg"))
.add(new HShape("svg6.svg"))
.layout(
new HGridLayout()
.startX(50)
.startY(50)
.spacing(50,50)
.cols(11)
)
.onCreate(
new HCallback() {
#Override
public void run(Object obj) {
HShape d = (HShape) obj;
d
.enableStyle(false)
.strokeJoin(ROUND)
.strokeCap(ROUND)
.strokeWeight(1)
.stroke(Integer.parseInt("#000000"))
// .anchorAt(H.CENTER)
.rotate( (int)random(4) * 90 )
.size( 50 + ( (int)random(4) * 50 ) ) // 50, 100, 150, 200
;
d.randomColors(colors.fillOnly());
}
}
)
.requestAll();
saveImage(w,h);
noLoop();
// ...
}
#Override
public void draw()
{
//rect(10, 10, 80, 80);
H.drawStage();
// ...
}
public void saveImage(int width, int height)
{
//Helper c = new Helper();
String p = "webapp/images/";
String fn = p+"image_"+Helper.generateRandomNumber();
PGraphics img = createGraphics(width, height);
img.beginDraw();
boolean use3D = false;
float alpha = 1;
H.stage().paintAll(img, use3D, alpha);
img.endDraw();
img.save(fn);
}
}
Processing uses a custom color type. You can use web notation like #ff00ff, and under the hood Processing stores that as an integer, so you can even do things like:
int c = #ff00ff;
However, Java functions like Integer.parseInt() have no idea how to handle web notation. Java has no way of mapping a String like "#ff00ff" to an int value. This is why you're getting your error.
Even if Java did know how to map web notation to an int value, you're passing in multiple values within a single String, which doesn't make a ton of sense.
But the point is, you can only use web notation if you're using the Processing editor. If you're writing this in something other than the Processing editor, you'll have to use the color() function.
HColorPool(color(0, 255, 0), color(255, 0, 255), ...);
There is java code for the translation:-
java.awt.Color.decode("ff00ff").getRGB();
Its a bit obscure is what I use in JRubyArt

JNA ClientToScreen?

Having issues figuring out how to use the ClientToScreen winapi function with JNA.
I'm still getting 0, 0 output for the coordinates of the window handle.
Am referencing this but im sure im not doing it right https://msdn.microsoft.com/en-us/library/windows/desktop/dd183434(v=vs.85).aspx
public interface User32Ex extends W32APIOptions {
User32Ex instance = (User32Ex) Native.loadLibrary("user32", User32Ex.class, DEFAULT_OPTIONS);
boolean GetCursorPos(long[] lpPoint);
WinDef.HWND WindowFromPoint(long point);
boolean GetClientRect(WinDef.HWND hWnd, WinDef.RECT rect);
boolean ClientToScreen(WinDef.HWND hWnd, int pt);
}
public void debug() throws InterruptedException {
while (true) {
long[] getPos = new long[1];
User32Ex.instance.GetCursorPos(getPos);
WinDef.HWND hwnd = User32Ex.instance.WindowFromPoint(getPos[0]);
WinDef.RECT rect = new WinDef.RECT();
User32Ex.instance.GetClientRect(hwnd, rect);
User32Ex.instance.ClientToScreen(hwnd, rect.left);
User32Ex.instance.ClientToScreen(hwnd, rect.right);
System.out.println(rect.toRectangle().toString());
Thread.sleep(1500);
}
}
#technomage is right. You need to use WinDef.POINT instead of int in your ClientToScreen() rect parameter.
If anyone looking for a working solution for the question, it's below.
In every 3rd sec, it's logging the window inner client coordinates desktop position.
Explanation.
In the User32ForClientRect interface, we load user32.dll with JNA and define a few methods.
The reason behind we not using the already implemented User32 methods from the JNA interface is simple. The methods that we need in our case are not implemented in JNA.
Methods:
FindWindow - it's included in JNA
Retreives the window handle HWND
GetClientRect
Retreives the window widht, height. to rect.right, rect.bottom
ClientToScreen
Retreives the window inner client desktop position. Left/Top corner coordinates
Example:
package application.playground;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import java.awt.*;
public class ClientRectExample {
interface User32ForClientRect extends StdCallLibrary {
User32ForClientRect INSTANCE = Native.loadLibrary("user32", User32ForClientRect.class,
W32APIOptions.DEFAULT_OPTIONS);
WinDef.HWND FindWindow(String lpClassName, String lpWindowName);
boolean GetClientRect(WinDef.HWND hWnd, WinDef.RECT rect);
boolean ClientToScreen(WinDef.HWND hWnd, WinDef.POINT lpPoint);
}
public static void main(String[] args) {
while (true) {
try {
Rectangle rectangle = ClientRectExample.getClientRect("WindowName");
System.out.println(rectangle);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static Rectangle getClientRect(String startOfWindowName) {
WinDef.HWND hWnd = User32ForClientRect.INSTANCE.FindWindow(null, startOfWindowName);
WinDef.POINT getPos = new WinDef.POINT();
WinDef.RECT rect = new WinDef.RECT();
User32ForClientRect.INSTANCE.GetClientRect(hWnd, rect);
User32ForClientRect.INSTANCE.ClientToScreen(hWnd, getPos);
return new Rectangle(getPos.x, getPos.y, rect.right, rect.bottom);
}
}
Instead of an int, you need to pass in LPPOINT to ClientToScreen(), or more specifically a pointer to a POINT structure (WinDef.POINT in JNA).

JavaFX Minimizing Undecorated Stage

I have an undecorated JavaFX Stage, and my own minimize, maximize & close buttons. But unfortunately clicking the taskbar icon in Windows 7 does not automatically minimize the stage - compared to the decorated behaviour.
Is there a way to minimize an undecorated stage with pure Java code, by clicking the taskbar icon? If not how can I do this with, say, JNA?
EDIT:
OK, I've been trying to solve this with JNA, but having done next to none C/C++/JNA, I have a bit trouble setting this up. I'd be grateful if someone helped me to put the pieces together..
Here's my code so far:
public final class Utils {
static {
if (PlatformUtil.isWin7OrLater()) {
Native.register("shell32");
Native.register("user32");
}
}
// Apparently, this is the event I am after
public static final int WM_ACTIVATEAPP = 0x1C;
public static void registerMinimizeHandler(Stage stage) {
// Hacky way to get a pointer to JavaFX Window
Pointer pointer = getWindowPointer(stage);
WinDef.HWND hwnd = new WinDef.HWND(pointer);
// Here's my minimize/activate handler
WinUser.WindowProc windowProc = new MinimizeHandler(stage);
Pointer magicPointer = ... set this to point to windowProc?
// This.. apparently, re-sets the WndProc? But how do I get the "magicPointer" that is "attached" to the windowProc?
User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, magicPointer);
}
}
private static class MinimizeHandler implements WinUser.WindowProc {
private Stage stage;
private MinimizeHandler(Stage stage) {
this.stage = stage;
}
#Override
public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
if (uMsg == WM_ACTIVATEAPP) {
System.out.println("ACTIVATE");
}
return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
private static Pointer getWindowPointer(Stage stage) {
try {
TKStage tkStage = stage.impl_getPeer();
Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow" );
getPlatformWindow.setAccessible(true);
Object platformWindow = getPlatformWindow.invoke(tkStage);
Method getNativeHandle = platformWindow.getClass().getMethod( "getNativeHandle" );
getNativeHandle.setAccessible(true);
Object nativeHandle = getNativeHandle.invoke(platformWindow);
return new Pointer((Long) nativeHandle);
} catch (Throwable e) {
System.err.println("Error getting Window Pointer");
return null;
}
}
EDIT 2: I eventually got further on with this one, but as soon as I re-set the WNDPROC, my undecorated window didn't respond to any events.. I'm offering a bounty of 100 reputation for a self-contained example with a working solution. Windows (7+) only is OK, I do not even know how this behaves on other platforms.
EDIT 3:
Well, I kind of gave up with this one.. I got everything set up correctly, and received the events, but had problems figuring out the correct event to listen for..
Since there's been some interest in the question, if anyone wants to attempt to continue with this, here's my final code (it hopefully should "work" out-of-box):
public final class Utils {
static interface ExtUser32 extends StdCallLibrary, User32 {
ExtUser32 INSTANCE = (ExtUser32) Native.loadLibrary(
"user32",
ExtUser32.class,
W32APIOptions.DEFAULT_OPTIONS);
WinDef.LRESULT CallWindowProcW(
Pointer lpWndProc,
Pointer hWnd,
int msg,
WinDef.WPARAM wParam,
WinDef.LPARAM lParam);
int SetWindowLong(HWND hWnd, int nIndex, com.sun.jna.Callback wndProc) throws LastErrorException;
}
// Some possible event types
public static final int WM_ACTIVATE = 0x0006;
public static final int WM_ACTIVATEAPP = 0x1C;
public static final int WM_NCACTIVATE = 0x0086;
public static void registerMinimizeHandler(Stage stage) {
Pointer pointer = getWindowPointer(stage);
WinDef.HWND hwnd = new WinDef.HWND(pointer);
long old = ExtUser32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC);
MinimizeHandler handler = new MinimizeHandler(stage, old);
ExtUser32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, handler);
}
private static Pointer getWindowPointer(Stage stage) {
try {
TKStage tkStage = stage.impl_getPeer();
Method getPlatformWindow = tkStage.getClass().getDeclaredMethod("getPlatformWindow" );
getPlatformWindow.setAccessible(true);
Object platformWindow = getPlatformWindow.invoke(tkStage);
Method getNativeHandle = platformWindow.getClass().getMethod( "getNativeHandle" );
getNativeHandle.setAccessible(true);
Object nativeHandle = getNativeHandle.invoke(platformWindow);
return new Pointer((Long) nativeHandle);
} catch (Throwable e) {
System.err.println("Error getting Window Pointer");
return null;
}
}
private static class MinimizeHandler implements WinUser.WindowProc, StdCallLibrary.StdCallCallback {
private Pointer mPrevWndProc32;
private Stage stage;
private MinimizeHandler(Stage stage, long oldPtr) {
this.stage = stage;
mPrevWndProc32 = new Pointer(oldPtr);
// Set up an event pump to deliver messages for JavaFX to handle
Thread thread = new Thread() {
#Override
public void run() {
int result;
WinUser.MSG msg = new WinUser.MSG();
while ((result = User32.INSTANCE.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
System.err.println("error in get message");
break;
}
else {
System.out.println("got message: " + result);
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
}
}
};
thread.start();
}
#Override
public WinDef.LRESULT callback(WinDef.HWND hWnd, int uMsg, WinDef.WPARAM wParam, WinDef.LPARAM lParam) {
if (uMsg == WM_ACTIVATEAPP) {
// Window deactivated (wParam == 0)... Here's where I got stuck and gave up,
// this is probably not the best event to listen to.. the app
// does indeed get iconified now by pressing the task-bar button, but it
// instantly restores afterwards..
if (wParam.intValue() == 0) {
stage.setIconified(true);
}
return new WinDef.LRESULT(0);
}
// Let JavaFX handle other events
return ExtUser32.INSTANCE.CallWindowProcW(
mPrevWndProc32,
hWnd.getPointer(),
uMsg,
wParam,
lParam);
}
}
}
You can just set the appropriate window style. It works in XP but should be ok in windows 7 32 bit.
I think (but can't test) if you use 64 bit then change to the Ptr windows functions, ie. GetWindowLongPtr.
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import static com.sun.jna.platform.win32.WinUser.GWL_STYLE;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class JNATest extends Application {
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage stage) {
TextArea ta = new TextArea("output\n");
VBox root = new VBox(5,ta);
Scene scene = new Scene(root,800,200);
stage.setTitle("Find this window");
stage.setScene(scene);
stage.show();
//gets this window (stage)
long lhwnd = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
Pointer lpVoid = new Pointer(lhwnd);
//gets the foreground (focused) window
final User32 user32 = User32.INSTANCE;
char[] windowText = new char[512];
HWND hwnd = user32.GetForegroundWindow();
//see what the title is
user32.GetWindowText(hwnd, windowText, 512);
//user32.GetWindowText(new HWND(lpVoid), windowText, 512);//to use the hwnd from stage
String text=(Native.toString(windowText));
//see if it's the same pointer
ta.appendText("HWND java:" + lpVoid + " HWND user32:"+hwnd+" text:"+text+"\n");
//change the window style if it's the right title
if (text.equals(stage.getTitle())){
//the style to change
int WS_DLGFRAME = 0x00400000;//s/b long I think
//not the same constant here??
ta.appendText("windows api:"+WS_DLGFRAME+" JNA: "+WinUser.SM_CXDLGFRAME);
int oldStyle = user32.GetWindowLong(hwnd, GWL_STYLE);
int newStyle = oldStyle & ~0x00400000; //bitwise not WS_DLGFRAME means remove the style
newStyle = newStyle & ~0x00040000;//WS_THICKFRAME
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
}
}
}
My guess is you replace the last 3 lines with
long oldStyleLong = user32.GetWindowLongPtr(hwnd, GWL_STYLE).longValue();
long newStyleLong = oldStyleLong & ~ 0x00400000l;
user32.SetWindowLongPtr(hwnd, GWL_STYLE, new BaseTSD.LONG_PTR(newStyleLong));
for 64 bit. I think I don't have those functions in my User32.dll, so I can't test it. There's lots of extraneous code in there, mainly for testing or teaching. Remove the unused lines once you figure out what you want to do.
ps. Don't add newStyle = newStyle & ~0x00020000;//WS_MINIMIZEBOX. That's one of the style flags JavaFX doesn't use for undecorated. That's why the minimize isn't available. Maybe if you try setting stage undecorated and adding (using |, not &~) the minimize box flag, you'll get the same result. There are tools to look up all the style flags from any window.
Here's the simplest amount of code that just changes an undecorated stage using the stage's HWND.
public void start(Stage stage) {
Scene scene = new Scene(new Pane(new Label("Hello World")));
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle("Find this window");
stage.setScene(scene);
stage.show();
long lhwnd = com.sun.glass.ui.Window.getWindows().get(0).getNativeWindow();
Pointer lpVoid = new Pointer(lhwnd);
HWND hwnd = new HWND(lpVoid);
final User32 user32 = User32.INSTANCE;
int oldStyle = user32.GetWindowLong(hwnd, GWL_STYLE);
System.out.println(Integer.toBinaryString(oldStyle));
int newStyle = oldStyle | 0x00020000;//WS_MINIMIZEBOX
System.out.println(Integer.toBinaryString(newStyle));
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
}
It prints out the style flags before and after so you can look up what styles are set.
Two things to note here.
First, it doesn't look like these libraries are in the latest version of JNA, 5.50 as of now, adding from the Maven repository. I had to add the 4.2.1 library instead.
Second, you may encounter this exception, like I did on Windows 10 and Java 11:
Error with package com.sun.glass.ui while learning Java Native Access
The solution is go to your VM options in your IDE (Run -> Edit Configurations..., in IntelliJ) and add this:
--add-exports
javafx.graphics/com.sun.glass.ui=ALL-UNNAMED
It should work after that.
I would like to see someone implement the native Windows animations for minimizing and un-minimizing an undecorated window, but I haven't searched too thoroughly yet to see if this has already been discussed. I'll update this if I come across a solution.
Edit:
Upon further research on the Windows animations, it looks like a solution could be hacked together, but I gave up at trying to implement this C# hack below. It seems to be more of an OS issue and not just JavaFX.
I was able to get the initial window to stay undecorated while minimizing and with the animation by modifying this in start():
int newStyle = oldStyle | 0x00020000 | 0x00C00000;
But, after minimizing and reopening, the Windows border appears oddly enough.
Then, I tried to use a ChangeListener to swap Windows styles when iconifying.
stage.iconifiedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t1.booleanValue() == true) {
int newStyle = oldStyle | 0x00020000 | 0x00C00000;
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
} else if (t1.booleanValue() == false) {
int newStyle = oldStyle | 0x00020000;
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
}
}
});
This successfully gets the windows un-minimize animation to work fine consistently, while leaving the (visible) stage borderless.
It looks like I can get minimization animations working once I find out the best way to re-apply:
int newStyle = oldStyle | 0x00020000 | 0x00C00000;
user32.SetWindowLong(hwnd, GWL_STYLE, newStyle);
just before the stage is iconified, and the border isn't visible to the user. Once implemented, this might work similarly to the C# solution in the first link below. Basically, what the above ChangeListener does in reverse.
Links to do with solving borderless/undecorated animations:
Use windows animations on borderless form
https://exceptionshub.com/borderless-window-using-areo-snap-shadow-minimize-animation-and-shake.html
http://pinvoke.net/default.aspx/Constants/Window%20styles.html
JavaFX Minimizing & Maximing undecorated stage with animations
Didn't get your question properly..but here's the solution
#FXML private void minimize()
{
Stage stage = (Stage) minimize.getScene().getWindow();
stage.setIconified(true);
}

Sending object, int and String via socket, serialisation

so I have a PrintWriter and a ObjectOutputStream trying to send an int, String and a Color[] from the client when the user clicks the list, where 'out' is the PrintWriter and outObject is the ObjectOutputStream.
private class MyMouseListener implements MouseListener{
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseClicked(MouseEvent e){
if(e.getSource() == list){
int index = list.locationToIndex(e.getPoint()); ///get the game that the player has selected
try{
out.println(index);
out.println("hel");
Color[] colors = new Color[5];
outObject.writeObject(colors)
}
}
Server, where 'in' is a scanner, 'objectIn' is an objectInputStream :
while(true)
if(in.nextLine().equals("hel")){
System.out.println("fee");
}
else if(in.hasNextInt()){
System.out.println("dee");
}
Object o = objectIn.readObject();
if(o instanceof Color[]){
System.out.println("ree");
}
If i try to send all three, on the first click the server only registers the String, and then all clicks after the server only registers the int, never registering the Color[], if i send the int first, then the Color[] and then the int like :`
out.println(index);
Color[] colors = new Color[5];
outObject.writeObject(colors);
out.println("hel");
Only the int and Object are registered first, on the second click only the String and then subsequent clicks only the int.
`
Object o = objectIn.readObject();
if(in.nextLine().equals("hel")){
System.out.println("fee");
}
//Object o = objectIn.readObject();
else if(in.hasNextInt()){
System.out.println("dee");
}
else if(o instanceof Color[]){
System.out.println("ree");
o = null;
}
If I use the above series of if statements nothing is registered
Using the first series of if statements, if i try to send the Color[] on it's own it's not registered, but if I send it with an int both are registered.
If i try to send the String and the Color[], sending the String first like so :
out.println("hel");
Color[] a = new Color[5];
outObject.writeObject(a);
both are registered once and then never again, also in the opposite way than was expected i.e the Color[] was registered first and then the String; if i send both but the Color[] first and then the String neither are registered.
I assume your out object (which is a PrintWriter) wraps the outObject object, which is the ObjectOutputStream. You should not use both a PrintWriter and a ObjectOutputStream for the same underlying connection. See this question for more details.

how to export a graph to svg/graphml

I am little bit stuck on how to export graphs to svg or graphml. Neither the api, examples or threads on forum.jgraph.com did help me until now.
I need to export graphs to both svg and graphml. I got svg to display the nodes and edges even with the correct layout, but I'm missing information like names of nodes and assigned colors.
With graphml I have no clue yet how to get the correct xml code to even display a functioning graph.
Is there any guideline/workflow somewhere which might help me with export in JGraphX?
Thanks in advance for any help,
Chris
In order to save your graph you have to call mxCellRendered to render your graph to a mxicanvas from which you get your Document (dom document).
From the Renderer it goes like this:
mxGraph.drawCell() -> mxGraph.drawState() -> mxICanvas.drawCell() -> mxICanvas.drawShape()
mxICanvas knows only the cell's geometry and style.
I wanted the cell id attribute added in the svg file as well, so I did the following
extended the mxGraph to override the drawCell() in order to add the cell id in the style of the cell, and
extended the mxSvgCanvas for adding the id attribute for the shapes that interested me
The function to save as svg graph goes like:
// use the extended svg canvas, where the cell id is added as attribute
public void createSVG(mxGraphExtended g) {
String filename = "\home\koula\graph.svg";
mxSvgCanvasExtended canvas = (mxSvgCanvasExtended) mxCellRenderer.drawCells(
g, null, 1, null, new CanvasFactory() {
public mxICanvas createCanvas(int width, int height) {
mxSvgCanvasExtended canvas = new mxSvgCanvasExtended(mxDomUtils
.createSvgDocument(width, height));
canvas.setEmbedded(true);
return canvas;
}
});
try {
mxUtils.writeFile(mxXmlUtils.getXml(canvas.getDocument()), filename);
} catch (IOException e) {
e.printStackTrace();
}
}
The overriden drawCell():
public class mxGraphExtended extends mxGraph {
#Override
public void drawCell(mxICanvas canvas, Object cell) {
// add the cell's id as a style attribute
// cause canvas only get the style and geometry
mxCellState state = this.getView().getState(cell);
state.getStyle().put("cellid", ((mxCell)cell).getId());
super.drawCell(canvas, cell);
}
}
The overridden drawShape() goes like:
public class mxSvgCanvasExtended extends mxSvgCanvas {
//... have coppied only the related code
#Override
public Element drawShape(int x, int y, int w, int h,
Map<String, Object> style)
{
//...
// Draws the shape
String shape = mxUtils.getString(style, mxConstants.STYLE_SHAPE, "");
String cellid = mxUtils.getString(style, "cellid", "");
Element elem = null;
// ...
// e.g. if image, add the cell id
if (shape.equals(mxConstants.SHAPE_IMAGE)) {
String img = getImageForStyle(style);
if (img != null) {
// Vertical and horizontal image flipping
boolean flipH = mxUtils.isTrue(style,
mxConstants.STYLE_IMAGE_FLIPH, false);
boolean flipV = mxUtils.isTrue(style,
mxConstants.STYLE_IMAGE_FLIPV, false);
elem = createImageElement(x, y, w, h, img,
PRESERVE_IMAGE_ASPECT, flipH, flipV, isEmbedded());
/* so here we are */
// add the cell id atribute
if(!cellid.equals("")) {
elem.setAttribute("id", cellid);
}
}
} else if (shape.equals(mxConstants.SHAPE_LINE))
// ...
}// end drawShape
} // end class
Hope this help.

Categories

Resources