Java Game Application Working in Eclipse, but not as a .jar (Slick2D + LWJGL) - jar

Today I was going to pack my game into a Jar to provide to a friend who codes and wanted to see a nice glitch I managed to create. When I went to make it a Runnable jar it would load up in the Command Prompt but throw Resource Not Found errors for Sounds (.ogg's), which was fine because they werent going to be used in the Debug mode it was set to. Then it threw a NullPointerException in TileHanlder.class at initTileMap() line 137.
I am at a loss so I came to StackOverflow because I have spent nearly my entire day on getting a working Jar. I have also tried JarSplice.
My main question is if there is any anomalies you notice or something I didnt do that is leading to resources not being found in the .jar.
ALL CODE AND RESOURCES WERE IN THE SAME JAR, ONE JAR FOR EVERYTHING there were not multiple jars
For ALL my code (it is OpenSource after all: Game Source Code)
Level.java (The class calling AssetHandler and TileHandler)
public class Level extends BasicGameState {
public MapHandler map = new MapHandler();
public AssetHandler asset = new AssetHandler();
static OutputHandler out = new OutputHandler();
public GameContainer container;
public StateBasedGame game;
public static float MouseX = 0;
public static float MouseY = 0;
public float RectX = 0;
public float RectY = 0;
public int tileAmount = 0;
public static int mapID = 1;
public static int delta;
public static int score = 0;
private static int EntityAmount = 0;
private static int ActiveEntityAmount = 0;
private int FPS = 0;
public static Image mapImage;
public static TileHandler Tile = new TileHandler();
public Point mousePoint;
public Circle mouseCirc;
public static Player p;
public static Enemy Blinky, Pinky, Inky, Clyde;
public static EntityAI AGGRESSIVE, AMBUSH, HIT_RUN, SORTOFRANDOM;
public Level(int id) {
}
#Override
public void init(GameContainer container, StateBasedGame game) throws SlickException {
MapHandler.mapRect();
mapID = MapHandler.getMapID();
MapHandler.deployMap(mapID);
try {
asset.initAssets();
OutputHandler.initFont();
} catch (AssetException e) {
e.printStackTrace();
}
TileHandler.initTileMap();
container.setUpdateOnlyWhenVisible(true);
container.setShowFPS(false);
container.setSmoothDeltas(false);
container.setVerbose(true);
this.container = container;
this.game = game;
AGGRESSIVE = new RedAI();
AMBUSH = new PinkAI();
HIT_RUN = new BlueAI();
SORTOFRANDOM = new OrangeAI();
p = new Player("Player1");
Blinky = new Enemy("Shadow", AGGRESSIVE);
Pinky = new Enemy("Speedy", AMBUSH);
Inky = new Enemy("Bashful", HIT_RUN);
Clyde = new Enemy("Pokey", SORTOFRANDOM);
}
#Override
public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
Tile.drawTileMap(TileHandler.tileLayer, TileHandler.tMapTiles, g);
if (Reference.debug) {
displayTileBounds(TileHandler.tileLayer, g);
}
drawEntities();
drawStrings(g);
}
#Override
public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException {
Input in = container.getInput();
MouseX = in.getMouseX();
MouseY = in.getMouseY();
RectX = MapHandler.Map32.getX();
RectY = MapHandler.Map32.getY();
EntityAmount = Entity.entityList.size();
ActiveEntityAmount = Enemy.enemyList.size() + Projectile.activeProjectiles.size() + 1;
Level.delta = delta;
Reference.defProjectileVelocity = .13f * Level.delta;
p.update(in);
updateNonPlayerEntities();
FPS = container.getFPS();
}
#Override
public int getID() {
return 2;
}
/** #deprecated **/
#Deprecated
protected void drawMap(Graphics g) {
g.drawImage(mapImage, Reference.MAP_X, Reference.MAP_Y);
}
protected void drawStrings(Graphics g) {
if (Reference.debug) {
OutputHandler.write("FPS: " + Integer.toString(FPS), 11, 10);
OutputHandler.write(String.format("Mouse X: %s, Mouse Y: %s", MouseX, MouseY), 11, 30);
OutputHandler.write(String.format("Rect X: %s, Y: %s", RectX, RectY), 11, 50);
OutputHandler.write("Amount of Tiles: " + (TileHandler.tileLayer.length * TileHandler.tileLayer[0].length), 11, 70);
OutputHandler.write(String.format("Amount of Entities = %s", Integer.toString(EntityAmount)), 11, 90);
OutputHandler.write(String.format("Active Entities = %s", Integer.toString(ActiveEntityAmount)), 11, 110);
out.write("Currently Loaded: " + p.isReloaded(), 11, 130);
OutputHandler.write("Amount of Entities is Accumulative", 11, 666);
} else {
String curTime = Reference.getTime();
String scoreStr = Reference.convertScore(score);
OutputHandler.write("Time: " + curTime, 11, 10);
OutputHandler.write("Score: " + scoreStr, 550, 10);
}
}
protected void displayTileBounds(Rectangle[][] tileLayer, Graphics g) {
g.setColor(Color.white);
for (int x = 0; x < tileLayer.length; x++) {
for (int y = 0; y < tileLayer[0].length; y++) {
g.fill(tileLayer[x][y]);
}
}
g.setColor(Color.magenta);
for (int s = 0; s < TileHandler.collisionTiles.size(); s++) {
Rectangle r = TileHandler.collisionTiles.get(s);
g.fill(r);
}
g.setColor(Color.orange);
g.fill(p.boundingBox);
for (int z = 0; z < Entity.teleportingTiles.length; z++) {
Rectangle r = Entity.teleportingTiles[z];
g.fill(r);
}
}
protected void drawEntities() {
ArrayList<Entity> list = Entity.entityList;
for (int i = 0; i < list.size(); i++) {
list.get(i).drawEntity(list.get(i));
}
}
protected void updateNonPlayerEntities() {
ArrayList<Enemy> list = Enemy.enemyList;
for (int i = 0; i < list.size(); i++) {
list.get(i).update();
}
ArrayList<Projectile> pList = Projectile.activeProjectiles;
for (int p = 0; p < pList.size(); p++) {
pList.get(p).update();
}
}
}
The AssetHandler (Game-Handlers-AssetHandler.java) Sounds are the THIRD TO LAST METHOD
public class AssetHandler {
public static boolean isComplete = false;
private static String musPath = "res/Sounds/";
static TileHandler tile;
private static int tsize = 32;
private static String spritesPath = "res/GameSprites/Maze Game/sprites.png";
private static String terrainPath = "res/GameSprites/Maze Game/terrain.png";
private static String twPath = "res/GameSprites/Maze Game/animation/tankToWest.png";
private static String tePath = "res/GameSprites/Maze Game/animation/tankToEast.png";
private static String tnPath = "res/GameSprites/Maze Game/animation/tankToNorth.png";
private static String tsPath = "res/GameSprites/Maze Game/animation/tankToSouth.png";
private static String bwPath = "res/GameSprites/Maze Game/animation/blueToWest.png";
private static String bePath = "res/GameSprites/Maze Game/animation/blueToEast.png";
private static String bnPath = "res/GameSprites/Maze Game/animation/blueToNorth.png";
private static String bsPath = "res/GameSprites/Maze Game/animation/blueToSouth.png";
private static String rePath, rwPath, rsPath, rnPath;
private static String pePath, pwPath, psPath, pnPath;
private static String oePath, owPath, osPath, onPath;
public static Music titleMus1, titleMus2, titleMus3, loadingScreenMus1, loadingScreenMus2, loadingScreenMus3;
public static Sound tankMove, tankFire, tankExplode, tankSurrender, tankRetreat;
public static void initSounds() {
System.out.println("Initializing Main Menu Music...");
try {
titleMus1 = new Music(musPath + "title/titlefirst.ogg");
titleMus2 = new Music(musPath + "title/titlesecond.ogg");
titleMus3 = new Music(musPath + "title/titlethird.ogg");
System.out.println("Initialized Main Menu Music!...");
} catch (SlickException e) {
e.printStackTrace();
System.out.println("ERROR: Initializing Main Menu Sounds at " + "com.treehouseelite.tank.game.handlers.AssetHandler" + " : initSounds() Method, First Try/Catch");
}
System.out.println("Initializing Loading Screen Music...");
try {
loadingScreenMus1 = new Music(musPath + "levels or loading screens/ActionBuilder.ogg");
loadingScreenMus2 = new Music(musPath + "levels or loading screens/StruggleforSurvival.ogg");
loadingScreenMus3 = new Music(musPath + "levels or loading screens/SurrealSomber.ogg");
} catch (SlickException e) {
e.printStackTrace();
System.out.println("ERROR: Initializing Loading Screen Sounds at " + "com.treehouseelite.tank.game.handlers.AssetHandler" + " : initSounds() Method, Second Try/Catch");
}
initSFX();
initsComplete();
}
private static void initsComplete() {
System.out.println("========================ALL ASSETS INITIALIZED========================");
}
public static void initSFX() {
try {
tankMove = new Sound("res/Sounds/SFX/tankMove.wav");
} catch (SlickException e) {
e.printStackTrace();
} finally {
System.out.println("All Sound Effects Initialized...");
}
}
}
TileHandler.java (Game-Handlers-TileHandler.java)
public class TileHandler {
public static String mapPath = "res/World/level_";
public static int bg, paths, collision;
public static Image[][] tMapTiles = new Image[25][20];
public static boolean[][] collidableTile = new boolean[25][20];
static Graphics g = new Graphics();
static AssetHandler asset = new AssetHandler();
// The Amount of Image is too damn high!
static TiledMap tMap;
public static int wFrame = 0;
private static int id;
public static Rectangle[][] tileLayer = new Rectangle[25][20];
public static ArrayList<Rectangle> collisionTiles = new ArrayList<Rectangle>(500);
public TileHandler() {
}
public TileHandler(int id, Rectangle rect) {
TileHandler.id = id;
try {
createTiles(id, rect);
} catch (SlickException e) {
e.printStackTrace();
}
}
protected void createTiles(int id, Rectangle layer) throws SlickException {
// Scans 0,0 to 0,20 of the tiles and then moves down the x line
// gettings tiles
// 0,0 = tileLayer[0][0]
mapPath = String.format("res/World/level_%s.tmx", id);
tMap = new TiledMap(mapPath);
bg = tMap.getLayerIndex("background");
paths = tMap.getLayerIndex("paths");
collision = tMap.getLayerIndex("collision");
// Constructs a Grid of Rectangles based on the Map's Top Left point
for (int i = 0; i < tileLayer.length; i++) {
for (int y = 0; y < tileLayer[0].length; y++) {
Rectangle tile = new Rectangle((i + Reference.MAP_X) + (i * Reference.TILE_SIZE), (y + Reference.MAP_Y) + (y * Reference.TILE_SIZE), 32, 32);
tileLayer[i][y] = tile;
}
}
/*
* for(int x = 0; x<collisionTiles.length; x++){ for(int y = 0;
* y<collisionTiles[0].length; y++){ Rectangle tile = new
* Rectangle((x+Reference.MAP_X) + (x*31),
* (y+Reference.MAP_Y+14)+(y*31),32,32); collisionTiles[x][y] = tile; }
* }
*/
}
/** #deprecated */
#Deprecated
public static void initSprites(Rectangle[][] layer) {
bg = tMap.getLayerIndex("background");
paths = tMap.getLayerIndex("paths");
collision = tMap.getLayerIndex("collision");
System.out.println("Initialized Sprites!");
}
// Initializes all tiles and put them into Image and Boolean Arrays
// Boolean Array for later use with determining whether the player or entity
// can be there. (collidableTile)
// Image array holds the tiles (tMapTiles)
public static void initTileMap() {
new Graphics();
// Getting Tiles based off Tile ID's
/** DIRT PATH MAPS (Dev Map, Level 1) **/
if ((id == 0) || (id == 1)) {
for (int x = 0; x < tileLayer.length; x++) {
for (int y = 0; y < tileLayer[0].length; y++) {
Rectangle r = new Rectangle(tileLayer[x][y].getX(), tileLayer[x][y].getY(), 32, 32);
if (tMap.getTileId(x, y, bg) == 1) {
tMapTiles[x][y] = AssetHandler.sparseGrass;
}
if (tMap.getTileId(x, y, collision) == 2) {
tMapTiles[x][y] = AssetHandler.water11;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, collision) == 57) {
tMapTiles[x][y] = AssetHandler.concrete1;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, collision) == 71) {
tMapTiles[x][y] = AssetHandler.concrete2;
// collisionTiles.add(new
// Rectangle(tileLayer[x][y].getX(),
// tileLayer[x][y].getY()+14, 32, 32)) ;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, collision) == 85) {
tMapTiles[x][y] = AssetHandler.concrete3;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, collision) == 72) {
tMapTiles[x][y] = AssetHandler.metal1;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, collision) == 58) {
tMapTiles[x][y] = AssetHandler.metal2;
collisionTiles.add(r);
}
if (tMap.getTileId(x, y, paths) == 50) {
tMapTiles[x][y] = AssetHandler.hDirtPath;
}
if (tMap.getTileId(x, y, paths) == 60) {
tMapTiles[x][y] = AssetHandler.dirtPath;
}
if (tMap.getTileId(x, y, paths) == 59) {
tMapTiles[x][y] = AssetHandler.dirtPathTurn4;
}
if (tMap.getTileId(x, y, paths) == 73) {
tMapTiles[x][y] = AssetHandler.dirtPathTurn3;
}
if (tMap.getTileId(x, y, paths) == 79) {
tMapTiles[x][y] = AssetHandler.dirtThreewayRight;
}
if (tMap.getTileId(x, y, paths) == 46) {
tMapTiles[x][y] = AssetHandler.dirtPathTurn1;
}
if (tMap.getTileId(x, y, paths) == 37) {
tMapTiles[x][y] = AssetHandler.hDirtCrossing1;
}
if ((tMap.getTileId(x, y, paths) == 80) || (tMap.getTileId(x, y, paths) == 88)) {
tMapTiles[x][y] = AssetHandler.dirtThreewayLeft;
}
if (tMap.getTileId(x, y, paths) == 102) {
tMapTiles[x][y] = AssetHandler.dirtThreewayDown;
}
if (tMap.getTileId(x, y, paths) == 74) {
tMapTiles[x][y] = AssetHandler.dirtPathTurn2;
}
if (tMap.getTileId(x, y, paths) == 107) {
tMapTiles[x][y] = AssetHandler.dirtThreewayUp;
}
if (tMap.getTileId(x, y, paths) == 88) {
tMapTiles[x][y] = AssetHandler.dirtCrossroads;
}
}
}
}
}
public void drawTileMap(Rectangle[][] layer, Image[][] tiles, Graphics g) {
// Loops through the Image array and places tile based on the Top Left
// corner of the Rectangle in the rectangle array
// Rectangle Array = layer (tileLayer was passed)
// Image Array = tiles (tMapTiles was passed)
// Asset Refers to Asset Handler
for (int x = 0; x < layer.length; x++) {
for (int y = 0; y < layer[0].length; y++) {
g.drawImage(tiles[x][y], layer[x][y].getX(), layer[x][y].getY());
// Below here is image detection for the placement of Animations
if (tiles[x][y] == AssetHandler.water11) {
AssetHandler.vRiver1.draw(layer[x][y].getX(), layer[x][y].getY());
AssetHandler.vRiver1.start();
AssetHandler.vRiver1.update(Level.delta);
} else if (tiles[x][y] == AssetHandler.hDirtCrossing1) {
AssetHandler.hDirtCrossing.draw(layer[x][y].getX(), layer[x][y].getY());
AssetHandler.hDirtCrossing.start();
AssetHandler.hDirtCrossing.update(Level.delta);
}
}
}
}
}
Finally, MapHandler.java -- Very Sparsely used, Main goal is to intialize a TileHandler object to construct the tile grid for constructing the TiledMap.
public class MapHandler {
public static AssetHandler asset = new AssetHandler();
static Image devMap;
Image map_1;
Image map_2;
Image map_3;
public static Rectangle Map32;
public MapHandler() {
}
// Sends a Rectangle set Around the Map Image to TileHandler
// to construct a grid of 32x32 Rectangles inside the Map's Rectangle
public static void deployMap(int id) {
if (id == 0) {
new TileHandler(id, Map32);
}
}
// Randomly Generates a Map ID corresponding to a Level_X.tmx
// Currently set to 0 for development purposes
public static int getMapID() {
new Random();
return 0;
// return id;
}
/* Create the Rectangle and Grid */
public static void mapRect() throws SlickException {
System.out.println("Initializing Rectangular Plane...");
Map32 = new Rectangle(Reference.GUI_WIDTH / 24, Reference.GUI_HEIGHT / 24, 800, 640);
System.out.println("Map32 Initialized!...");
}
}
If You need ANY other resources or information than please let me know and I will be happy to provide so I can get over this. I will also be thinking of other ways, Thank you for any responses!
THINGS WERE CUT OUT DUE TO THE 30k Char Limit on the question text box. Mostly in the insanely crowded AssetHandler.java, it is still there in the git repository though.

I had the very same problem. After searching for a while, I came across this neat solution. See this LWJGL forum post.
public static void main(String[] args) throws SlickException {
/* Set lwjgl library path so that LWJGL finds the natives depending on the OS. */
String osName = System.getProperty("os.name");
// Get .jar dir. new File(".") and property "user.dir" will not work if .jar is called from
// a different directory, e.g. java -jar /someOtherDirectory/myApp.jar
String nativeDir = "";
try {
nativeDir = new File(GameMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent();
} catch (URISyntaxException uriEx) {
try {
// Try to resort to current dir. May still fail later due to bad start dir.
uriEx.printStackTrace();
nativeDir = new File(".").getCanonicalPath();
} catch (IOException ioEx) {
// Completely failed
ioEx.printStackTrace();
JOptionPane.showMessageDialog(new JFrame(), "Failed to locate native library directory. " +
"Error:\n" + ioEx.toString(), "Error", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
}
// Append library subdir
nativeDir += File.separator + "lib" + File.separator + "native" + File.separator;
if (osName.startsWith("Windows")) {
nativeDir += "windows";
} else if (osName.startsWith("Linux") || osName.startsWith("FreeBSD")) {
nativeDir += "linux";
} else if (osName.startsWith("Mac OS X")) {
nativeDir += "macosx";
} else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
nativeDir += "solaris";
} else {
JOptionPane.showMessageDialog(new JFrame(), "Unsupported OS: " + osName + ". Exiting.",
"Error", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
System.setProperty("org.lwjgl.librarypath", nativeDir);
}
Bear in mind that you need a lib folder in the same directory. I have mine stored outside of the .jar, but it may be possible to have it inside as well. Also note that it needs to happen before you do any LWJGL stuff, so the main method is a good place.

Related

Get GraphicEdge at Mouse hovering in GraphStream

I want to show the weight of an edge when the mouse hovers over it.
So I use an MouseEvent.MOUSE_MOVED in my implemented MouseManager. With nodes, I just can call view.findGraphicElementAt(getManagedTypes(), event.getX(), event.getY()) to get the GraphicNode Object. Unfortunately, edges do not have one x and y value, and are thus not found by this method. Yes, I know getX()and getY() are implemented for a GraphicEdge but are just pointing at the center of the edge.
I need the Edge Object to get some further information stored at the edge (like weight). So how do I get the Edge Object using x,y or some other values I can retrieve from the received MouseEvent?
In fact, edge selection, mouseOver, and mouseLeft functions (which kind of includes hovering over edges) is already implemented in the MouseOverMouseManager or FxMouseOverMouseManager. This manager is automatically set when calling view.enableMouseOptions() but I already implemented an individual MouseManager for some other reasons plus hovering over an edge is only detected when hovering over the center of the edge. So my solution was to copy the code from MouseOverMouseManager into MyMousemanager and modify it.
Edit:
public class CompoundListNetworkMouseManager extends FxMouseManager {
private GraphicElement hoveredElement;
private long hoveredElementLastChanged;
private ReentrantLock hoverLock = new ReentrantLock();
private Timer hoverTimer = new Timer(true);
private HoverTimerTask latestHoverTimerTask;
/**
*(copied from the GraphsStream Library)
* The mouse needs to stay on an element for at least this amount of milliseconds,
* until the element gets the attribute "ui.mouseOver" assigned.
* A value smaller or equal to zero indicates, that the attribute is assigned without delay.
* */
private final long delayHover;
public CompoundListNetworkMouseManager(){
super(EnumSet.of(InteractiveElement.NODE, InteractiveElement.EDGE));
this.delayHover = 100;
}
#Override
public void init(GraphicGraph graph, View view) {
this.graph = graph;
this.view = view;
view.addListener(MouseEvent.MOUSE_MOVED, mouseMoved);
}
#Override
public void release() {
view.removeListener(MouseEvent.MOUSE_MOVED, mouseMoved);
}
#Override
public EnumSet<InteractiveElement> getManagedTypes() {
return super.getManagedTypes();
}
protected void mouseOverElement(GraphicElement element){
element.setAttribute("ui.mouseOver", true);
element.setAttribute("ui.class", "mouseOver"); //I defined a class/type for edges in the CSS styling sheet that is calles "mouseOver"
if(element instanceof GraphicEdge) {
mouseOverEdge((GraphicEdge) element);
}
else if(element instanceof GraphicNode){
mouseOverNode((GraphicNode) element);
}
protected void mouseOverEdge(GraphicEdge graphicEdge) {
view.freezeElement(graphicEdge, true);
Edge edge = graph.getEdge(graphicEdge.getId());
System.out.println("Mouse over edge " + edge.getId());
}
protected void mouseLeftElement(GraphicElement element) {
this.hoveredElement = null;
element.removeAttribute("ui.mouseOver");
element.removeAttribute("ui.class");
}
EventHandler<MouseEvent> mouseMoved = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
try {
hoverLock.lockInterruptibly();
boolean stayedOnElement = false;
curElement = view.findGraphicElementAt(getManagedTypes(), event.getX(), event.getY());
//adjusted implementation of search for edges
if(curElement == null && getManagedTypes().contains(InteractiveElement.EDGE)){
curElement = (GraphicElement) findEdgeAt(event.getX(), event.getY());
}
if(hoveredElement != null) {
//check if mouse stayed on the same element to avoid the mouseOverEvent being processed multiple times
stayedOnElement = curElement == null ? false : curElement.equals(hoveredElement);
if (!stayedOnElement && hoveredElement.hasAttribute("ui.mouseOver")) {
mouseLeftElement(hoveredElement);
}
}
if (!stayedOnElement && curElement != null) {
if (delayHover <= 0) {
mouseOverElement(curElement);
} else {
hoveredElement = curElement;
hoveredElementLastChanged = Calendar.getInstance().getTimeInMillis();
if (latestHoverTimerTask != null) {
latestHoverTimerTask.cancel();
}
latestHoverTimerTask = new HoverTimerTask(hoveredElementLastChanged, hoveredElement);
hoverTimer.schedule(latestHoverTimerTask, delayHover);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
hoverLock.unlock();
}
}
};
//copied from GraphStream Library
private final class HoverTimerTask extends TimerTask {
private final long lastChanged;
private final GraphicElement element;
public HoverTimerTask(long lastChanged, GraphicElement element) {
this.lastChanged = lastChanged;
this.element = element;
}
#Override
public void run() {
try {
hoverLock.lock();
if (hoveredElementLastChanged == lastChanged) {
mouseOverElement(element);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
hoverLock.unlock();
}
}
}
//findGraphicElement could be used but I wanted to implement the edgeContains method myself
private Edge findEdgeAt(double x, double y){
Camera cam = view.getCamera();
GraphMetrics metrics = cam.getMetrics();
//transform x and y
double xT = x + metrics.viewport[0];
double yT = y + metrics.viewport[0];
Edge edgeFound = null;
if (getManagedTypes().contains(InteractiveElement.EDGE)) {
Optional<Edge> edge = graph.edges().filter(e -> edgeContains((GraphicEdge) e, xT, yT)).findFirst();
if (edge.isPresent()) {
if (cam.isVisible((GraphicElement) edge.get())) {
edgeFound = edge.get();
}
}
}
return edgeFound;
}
//new edgeContains() method that finds edge at hovering not only when hovered over edge center
private boolean edgeContains(GraphicEdge edge, double x, double y) {
Camera cam = view.getCamera();
GraphMetrics metrics = cam.getMetrics();
Values size = edge.getStyle().getSize();
double deviation = metrics.lengthToPx(size, 0);
Point3 edgeNode0 = cam.transformGuToPx(edge.from.x, edge.from.y, 0);
Point3 edgeNode1 = cam.transformGuToPx(edge.to.x, edge.to.y, 0);
//check of point x,y is between nodes of the edge
boolean edgeContains = false;
//check x,y range
if(x > Math.min(edgeNode0.x, edgeNode1.x) - deviation
&& x < Math.max(edgeNode0.x, edgeNode1.x) + deviation
&& y > Math.min(edgeNode0.y, edgeNode1.y) - deviation
&& y < Math.max(edgeNode0.y, edgeNode1.y) + deviation){
//check deviation from edge
Vector2 vectorNode0To1 = new Vector2(edgeNode0, edgeNode1);
Point2 point = new Point2(x, y);
Vector2 vectorNode0ToPoint = new Vector2(edgeNode0, point);
//cross product of vectorNode0ToPoint and vectorNode0to1
double crossProduct = vectorNode0ToPoint.x() * vectorNode0To1.y() - vectorNode0To1.x() * vectorNode0ToPoint.y();
//distance of point to the line extending the edge
double d = Math.abs(crossProduct) / vectorNode0To1.length();
if(d <= deviation){
edgeContains = true;
}
}
return edgeContains;
}
}
CSS Stylesheet:
...
edge{
fill-color: black;
size: 2px;
arrow-shape: none;
shape: line;
text-mode: hidden;
}
edge.mouseOver {
fill-color: red;
stroke-color: red;
text-mode: normal;
text-background-mode: plain; /*plain or none*/
text-background-color: rgba(255, 255, 255, 200);
text-alignment: along;
}

Using pinch to zoomin and zoomout some unwanted background should copied color appeared and pixel quality low android below 9 version Xamarin android

Whenever i using wo fingers pinch to zoomin and zoomout some unwanted background should copied color appeared my camerapagerenderer if i single touch or touch it not seems to be apppear when i pinch to zoomin using two fingers it appears on my screen
public override bool OnTouchEvent(MotionEvent e)
{
switch (e.Action & MotionEventActions.Mask)
{
case MotionEventActions.Down:
oldDist = getFingerSpacing(e);
break;
case MotionEventActions.Move:
float newDist = getFingerSpacing(e);
if (newDist > oldDist)
{
//mCamera is your Camera which used to take picture, it should already exit in your custom Camera
handleZoom(true, camera);
}
else if (newDist < oldDist)
{
handleZoom(false, camera);
}
oldDist = newDist;
break;
}
return true;
}
private void handleZoom(bool isZoomIn, global::Android.Hardware.Camera camera)
{
global::Android.Hardware.Camera.Parameters parameters = camera.GetParameters();
if (parameters.IsZoomSupported)
{
int maxZoom = parameters.MaxZoom;
int zoom = parameters.Zoom;
if (isZoomIn && zoom < maxZoom)
{
zoom++;
}
else if(zoom > 0)
{
zoom--;
}
parameters.Zoom = zoom;
camera.SetParameters(parameters);
}
else
{
Android.Util.Log.Error("lv", "zoom not supported");
}
}
private static float getFingerSpacing(MotionEvent e)
{
if(e.PointerCount==2)
{
int pointerIndex = e.FindPointerIndex(_activePointerId);
float x = e.GetX(pointerIndex);
float y = e.GetY(pointerIndex);
return (float)Math.Sqrt(x * x + y * y);
}
}
You could check the code below. It works on Android 10.0 with no color shades.
class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
{
global::Android.Hardware.Camera camera;
global::Android.Widget.Button takePhotoButton;
global::Android.Widget.Button toggleFlashButton;
global::Android.Widget.Button switchCameraButton;
global::Android.Views.View view;
Activity activity;
CameraFacing cameraType;
TextureView textureView;
SurfaceTexture surfaceTexture;
bool flashOn;
public CameraPageRenderer(Context context) : base(context)
{
}
float oldDist = 1f;
public override bool OnTouchEvent(MotionEvent e)
{
switch (e.Action & MotionEventActions.Mask)
{
case MotionEventActions.Down:
oldDist = getFingerSpacing(e);
break;
case MotionEventActions.Move:
float newDist = getFingerSpacing(e);
if (newDist > oldDist)
{
//mCamera is your Camera which used to take picture, it should already exit in your custom Camera
handleZoom(true, camera);
}
else if (newDist < oldDist)
{
handleZoom(false, camera);
}
oldDist = newDist;
break;
}
return true;
}
private static float getFingerSpacing(MotionEvent e)
{
if (e.PointerCount == 2)
{
float x = e.GetX(0) - e.GetX(1);
float y = e.GetY(0) - e.GetY(1);
return (float)Math.Sqrt(x*x + y*y);
}
return 0;
}
private void handleZoom(bool isZoomIn, global::Android.Hardware.Camera camera)
{
//camera.StopPreview();
// camera.Release();
// camera = global::Android.Hardware.Camera.Open((int)cameraType);
global::Android.Hardware.Camera.Parameters parameters = camera.GetParameters();
if (parameters.IsZoomSupported)
{
int maxZoom = parameters.MaxZoom;
int zoom = parameters.Zoom;
if (isZoomIn && zoom < maxZoom)
{
zoom++;
}
else if (zoom > 0)
{
zoom--;
}
parameters.Zoom = zoom;
camera.SetParameters(parameters);
camera.SetPreviewTexture(surfaceTexture);
PrepareAndStartCamera();
}
else
{
Android.Util.Log.Error("lv", "zoom not supported");
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
//SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
void SetupUserInterface()
{
activity = this.Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.CameraLayout, this, false);
cameraType = CameraFacing.Back;
textureView = view.FindViewById<TextureView>(Resource.Id.textureView);
textureView.SurfaceTextureListener = this;
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
{
camera = global::Android.Hardware.Camera.Open((int)cameraType);
textureView.LayoutParameters = new FrameLayout.LayoutParams(width, height);
surfaceTexture = surface;
camera.SetPreviewTexture(surface);
PrepareAndStartCamera();
}
public bool OnSurfaceTextureDestroyed(SurfaceTexture surface)
{
camera.StopPreview();
camera.Release();
return true;
}
public void OnSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
{
PrepareAndStartCamera();
}
public void OnSurfaceTextureUpdated(SurfaceTexture surface)
{
}
void PrepareAndStartCamera()
{
camera.StopPreview();
var display = activity.WindowManager.DefaultDisplay;
if (display.Rotation == SurfaceOrientation.Rotation0)
{
camera.SetDisplayOrientation(90);
}
if (display.Rotation == SurfaceOrientation.Rotation270)
{
camera.SetDisplayOrientation(180);
}
camera.StartPreview();
}
}
Update: The result on Android 6.0

How do you print TextArea to a USB Thermal Printer 58mm?(JAVAFX)

So I'm trying to make a billing system in which I want to print a receipt.I was able to do it with some code that I found online,but the font size is too big to print in the 58mm wide paper.I'm not able to adjust the font size.Any kind of help with this issue will be highly appreciated.Thank You.
Here is The Code :
public class PrinterService implements Printable {
public List<String> getPrinters(){
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printServices[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
List<String> printerList = new ArrayList<String>();
for(PrintService printerService: printServices){
printerList.add( printerService.getName());
}
return printerList;
}
#Override
public int print(Graphics g, PageFormat pf, int page)
throws PrinterException {
if (page > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
/*
* User (0,0) is typically outside the imageable area, so we must
* translate by the X and Y values in the PageFormat to avoid clipping
*/
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
/* Now we perform our rendering */
g.setFont(new Font("Roman", 0, 8));
g.drawString("Hello world !", 0, 10);
return PAGE_EXISTS;
}
public void printString(String printerName, String text) {
// find the printService of name printerName
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
PrintService service = findPrintService(printerName, printService);
DocPrintJob job = service.createPrintJob();
try {
byte[] bytes;
// important for umlaut chars
bytes = text.getBytes("CP437");
Doc doc = new SimpleDoc(bytes, flavor, null);
job.print(doc, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void printBytes(String printerName, byte[] bytes) {
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
PrintService service = findPrintService(printerName, printService);
DocPrintJob job = service.createPrintJob();
try {
Doc doc = new SimpleDoc(bytes, flavor, null);
job.print(doc, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private PrintService findPrintService(String printerName,
PrintService[] services) {
for (PrintService service : services) {
if (service.getName().equalsIgnoreCase(printerName)) {
return service;
}
}
return null;
}
}
#FXML
public void printit(ActionEvent actionEvent)
{
PrinterService printerService = new PrinterService();
System.out.println(printerService.getPrinters());
//print some stuff
printerService.printString("POS-58-Series", area.getText());
}

JavaFX TimeTextField

Base Article:
[https://community.oracle.com/thread/2552039?start=0&tstart=0][1]
I extend the solution from the oracle community with the event filters in the constructor for a better user ergonomics.
The JavaFX TimeTextField provides all functions needed for time handling.
Unfortunately it's missing in the JavaFX Standard in Java8, where a time handling field is a must in my point of view as in other technologies it is possible.
The thread in the oracle community is not as frequent as I expect it, please test it and try to improve it! We need it...
Features:
- only numeric keys are accepted.
- validation for a given time format
- (my improvement) when the last number of a block like hours or minutes was reached, the cursor jumps to the next block.
package test;
import java.util.regex.Pattern;
import javafx.beans.binding.Bindings;
import javafx.application.Application;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.IndexRange;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TimeTextFieldTest extends Application {
#Override
public void start(Stage primaryStage) {
VBox root = new VBox(5);
root.setPadding(new javafx.geometry.Insets(5));
Label hrLabel = new Label();
Label minLabel = new Label();
Label secLabel = new Label();
TimeTextField timeTextField = new TimeTextField();
hrLabel.textProperty().bind(Bindings.format("Hours: %d", timeTextField.hoursProperty()));
minLabel.textProperty().bind(Bindings.format("Minutes: %d", timeTextField.minutesProperty()));
secLabel.textProperty().bind(Bindings.format("Seconds: %d", timeTextField.secondsProperty()));
root.getChildren().addAll(timeTextField, hrLabel, minLabel, secLabel);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class TimeTextField extends TextField {
enum Unit {
HOURS, MINUTES, SECONDS
};
private final Pattern timePattern;
private final ReadOnlyIntegerWrapper hours;
private final ReadOnlyIntegerWrapper minutes;
private final ReadOnlyIntegerWrapper seconds;
public TimeTextField() {
this("00:00:00");
this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent inputevent) {
int c = TimeTextField.this.getCaretPosition();
if (c <= 7) {
if (!"1234567890:".contains(inputevent.getCharacter().toLowerCase())) {
inputevent.consume();
}
} else {
inputevent.consume();
}
}
});
this.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent inputevent) {
boolean withMinutes = false;
if (TimeTextField.this.getText() != null && TimeTextField.this.getText().length() >= 5
&& TimeTextField.this.getText().indexOf(":") == 2) {
withMinutes = true;
}
boolean withSeconds = false;
if (TimeTextField.this.getText() != null && TimeTextField.this.getText().length() == 8
&& TimeTextField.this.getText().lastIndexOf(":") == 5) {
withSeconds = true;
}
int c = TimeTextField.this.getCaretPosition();
if (((c == 2 && withMinutes) || (c == 5 && withSeconds))
&& (inputevent.getCode() != KeyCode.LEFT && inputevent.getCode() != KeyCode.BACK_SPACE)) {
TimeTextField.this.forward();
inputevent.consume();
}
}
});
}
public TimeTextField(String time) {
super(time);
// timePattern = Pattern.compile("\\d\\d:\\d\\d:\\d\\d");
timePattern = Pattern.compile("([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]");
if (!validate(time)) {
throw new IllegalArgumentException("Invalid time: " + time);
}
hours = new ReadOnlyIntegerWrapper(this, "hours");
minutes = new ReadOnlyIntegerWrapper(this, "minutes");
seconds = new ReadOnlyIntegerWrapper(this, "seconds");
hours.bind(new TimeTextField.TimeUnitBinding(Unit.HOURS));
minutes.bind(new TimeTextField.TimeUnitBinding(Unit.MINUTES));
seconds.bind(new TimeTextField.TimeUnitBinding(Unit.SECONDS));
}
public ReadOnlyIntegerProperty hoursProperty() {
return hours.getReadOnlyProperty();
}
public int getHours() {
return hours.get();
}
public ReadOnlyIntegerProperty minutesProperty() {
return minutes.getReadOnlyProperty();
}
public int getMinutes() {
return minutes.get();
}
public ReadOnlyIntegerProperty secondsProperty() {
return seconds.getReadOnlyProperty();
}
public int getSeconds() {
return seconds.get();
}
#Override
public void appendText(String text) {
// Ignore this. Our text is always 8 characters long, we cannot
// append anything
}
#Override
public boolean deleteNextChar() {
boolean success = false;
// If there's a selection, delete it:
final IndexRange selection = getSelection();
if (selection.getLength() > 0) {
int selectionEnd = selection.getEnd();
this.deleteText(selection);
this.positionCaret(selectionEnd);
success = true;
} else {
// If the caret preceeds a digit, replace that digit with a zero
// and move the caret forward. Else just move the caret forward.
int caret = this.getCaretPosition();
if (caret % 3 != 2) { // not preceeding a colon
String currentText = this.getText();
setText(currentText.substring(0, caret) + "0" + currentText.substring(caret + 1));
success = true;
}
this.positionCaret(Math.min(caret + 1, this.getText().length()));
}
return success;
}
#Override
public boolean deletePreviousChar() {
boolean success = false;
// If there's a selection, delete it:
final IndexRange selection = getSelection();
if (selection.getLength() > 0) {
int selectionStart = selection.getStart();
this.deleteText(selection);
this.positionCaret(selectionStart);
success = true;
} else {
// If the caret is after a digit, replace that digit with a zero
// and move the caret backward. Else just move the caret back.
int caret = this.getCaretPosition();
if (caret % 3 != 0) { // not following a colon
String currentText = this.getText();
setText(currentText.substring(0, caret - 1) + "0" + currentText.substring(caret));
success = true;
}
this.positionCaret(Math.max(caret - 1, 0));
}
return success;
}
#Override
public void deleteText(IndexRange range) {
this.deleteText(range.getStart(), range.getEnd());
}
#Override
public void deleteText(int begin, int end) {
// Replace all digits in the given range with zero:
StringBuilder builder = new StringBuilder(this.getText());
for (int c = begin; c < end; c++) {
if (c % 3 != 2) { // Not at a colon:
builder.replace(c, c + 1, "0");
}
}
this.setText(builder.toString());
}
#Override
public void insertText(int index, String text) {
// Handle an insert by replacing the range from index to
// index+text.length() with text, if that results in a valid string:
StringBuilder builder = new StringBuilder(this.getText());
builder.replace(index, index + text.length(), text);
final String testText = builder.toString();
if (validate(testText)) {
this.setText(testText);
}
this.positionCaret(index + text.length());
}
#Override
public void replaceSelection(String replacement) {
final IndexRange selection = this.getSelection();
if (selection.getLength() == 0) {
this.insertText(selection.getStart(), replacement);
} else {
this.replaceText(selection.getStart(), selection.getEnd(), replacement);
}
}
#Override
public void replaceText(IndexRange range, String text) {
this.replaceText(range.getStart(), range.getEnd(), text);
}
#Override
public void replaceText(int begin, int end, String text) {
if (begin == end) {
this.insertText(begin, text);
} else {
// only handle this if text.length() is equal to the number of
// characters being replaced, and if the replacement results in
// a valid string:
if (text.length() == end - begin) {
StringBuilder builder = new StringBuilder(this.getText());
builder.replace(begin, end, text);
String testText = builder.toString();
if (validate(testText)) {
this.setText(testText);
}
this.positionCaret(end);
}
}
}
private boolean validate(String time) {
if (!timePattern.matcher(time).matches()) {
return false;
}
String[] tokens = time.split(":");
assert tokens.length == 3;
try {
int hours = Integer.parseInt(tokens[0]);
int mins = Integer.parseInt(tokens[1]);
int secs = Integer.parseInt(tokens[2]);
if (hours < 0 || hours > 23) {
return false;
}
if (mins < 0 || mins > 59) {
return false;
}
if (secs < 0 || secs > 59) {
return false;
}
return true;
} catch (NumberFormatException nfe) {
// regex matching should assure we never reach this catch block
assert false;
return false;
}
}
private final class TimeUnitBinding extends IntegerBinding {
final Unit unit;
TimeUnitBinding(Unit unit) {
this.bind(textProperty());
this.unit = unit;
}
#Override
protected int computeValue() {
// Crazy enum magic
String token = getText().split(":")[unit.ordinal()];
return Integer.parseInt(token);
}
}
}
}

DevExpress GridControl Does not Update properly even I set up the NotifyPropertyChanged event correctly

I met a very strange Problem.
The basic idea is that I have a class to save data received from a trading api about forex price. Each property has been set with NotifyPropertyChanged method like below.
class RealTimeBar
{
public event PropertyChangedEventHandler PropertyChanged;
private const double EPSILON = 0.0000001;
private int _id;
private string _symbol;
private int _time;
private float _open;
private float _high;
private float _low;
private float _close;
int _volume;
public RealTimeBar(int id, string symbol)
{
_id = id;
_symbol = symbol;
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public int Id
{
get
{
return _id;
}
set
{
_id = value;
}
}
public string Symbol
{
get
{
return _symbol;
}
set
{
if (value != _symbol)
{
_symbol = value;
NotifyPropertyChanged("Symbol");
}
}
}
public int Time
{
get
{
return _time;
}
set
{
if (value != _time)
{
_time = value;
NotifyPropertyChanged("Time");
}
}
}
public float Open
{
get
{
return _open;
}
set
{
if (value != _open)
{
_open = value;
NotifyPropertyChanged("Open");
}
}
}
public float High
{
get
{
return _high;
}
set
{
if (value != _high)
{
_high = value;
NotifyPropertyChanged("High");
}
}
}
public float Low
{
get
{
return _low;
}
set
{
if (value != _low)
{
_low = value;
NotifyPropertyChanged("Low");
}
}
}
public float Close
{
get
{
return _close;
}
set
{
if (value != _close)
{
_close = value;
NotifyPropertyChanged("Close");
}
}
}
public int Volume
{
get
{
return _volume;
}
set
{
if (value != _volume)
{
_volume = value;
NotifyPropertyChanged("Volume");
}
}
}
}
It is quote a long class but with simple structure as you can see. Now I connected to api which fire event to me and I handle it by set the value from api to the class i defined.
BindingList<RealTimeBar> _realTimeBarList = new BindingList<RealTimeBar>();
public Hashtable _iForexHashtable = new Hashtable();
private void _UpdateForexQuote(int tickerId, int time, double open, double high, double low, double close, int volume,
double wap, int count)
{
///MessageBox.Show(tickerId.ToString());
((RealTimeBar)_iForexHashtable[tickerId]).Open = (float)open;
((RealTimeBar)_iForexHashtable[tickerId]).High = (float)high;
((RealTimeBar)_iForexHashtable[tickerId]).Low = (float)low;
((RealTimeBar)_iForexHashtable[tickerId]).Close = (float)close;
((RealTimeBar)_iForexHashtable[tickerId]).Volume = volume;
}
After some setting up, the method _UpdateForexQuote would distribute the coming info into properties of RealTimeBar class. Everything is fine.
When I start the program, it does not update. I thought that there is no data coming in. But when I randomly click somewhere in the A1cell of gridcontrol, then click another B1cell, the previous A1cell would update. Then if i click C1cell, then the B1cell would update. If you do not click one cell , it would never update. I show you the picture:
As you can see, that after clicking first three lines, the first three lines showed delayed data and since I never touch the fourth line, it shows zero. And the condition is that I just clicked the fifth line Low cell, that is why the Low does not update but other cells updated. It is very strange. I use same code before under devexpress 11 with vs 2010. But now with devexpress 12 with vs 2012, I met this problem which never occurred before.
UPDATE:
Below is the method I use to 1. define bindinglist and a hashtable, 2. put objects into the hashtable first and add the object from hashtable to bindinglist 3. bind the bindinglist to gridcontrol.
private void earningButtonItem_ItemClick(object sender, ItemClickEventArgs e)
{
_iTimer.AutoReset = false;
_iTimer.Enabled = false;
switchStockPool = "Earning Stock";
disconnectButtonItem.PerformClick();
connectButtonItem.PerformClick();
_iheitanshaoEarningDBConnect = new DBConnect("heitanshaoearning");
List<string>[] tempList;
int tempHash;
tempList = _iheitanshaoEarningDBConnect.SelectSymbolHighLow();
_quoteEarningOnGridList.Clear();
///tempList[0].Count
for (int i = 0; i < tempList[0].Count; i++)
{
tempHash = Convert.ToInt32(tempList[0][i].ToString().GetHashCode());
_iStockEarningHistHashtable[tempHash] = new QuoteOnGridHist(tempList[0][i], (float)Convert.ToSingle(tempList[1][i]), (float)Convert.ToSingle(tempList[2][i]), (float)Convert.ToSingle(tempList[3][i]));
_iStockEarningHashtable[tempHash] = new QuoteOnGrid(tempList[0][i], 0, 0);
_quoteEarningOnGridList.Add((QuoteOnGrid)_iStockEarningHashtable[tempHash]);
reqMktDataExStock(tempHash, tempList[0][i].ToString());
}
List<string>[] tempVolumeList;
tempVolumeList = _iheitanshaoEarningDBConnect.SelectAverageVolume();
for (int i = 0; i < tempList[0].Count; i++)
{
tempHash = Convert.ToInt32(tempVolumeList[0][i].ToString().GetHashCode());
((QuoteOnGrid)_iStockEarningHashtable[tempHash]).Average_Volume = ((float)Convert.ToSingle(tempVolumeList[1][i])) / volumeDenominator;
}
gridControl.DataSource = _quoteEarningOnGridList;
}
/////////////////////
Now when the price update event comes, the method below will update the object properties in hashtable. Since I defined Notifypropertychanged in object, it should update the object in bingdinglist and gridcontrol.
private void _UpdateStockMarketQuote(int tikcerId, int field, double price, int canAutoExecute)
{
////MessageBox.Show(tikcerId.ToString() + field.ToString() + price.ToString());
if (switchStockPool == "Selected Stock")
{
if (field == 4)
{
((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockHashtable[tikcerId]).Last_Price = (float)price;
}
//else if (field == 1)
//{
// ((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
// ((QuoteOnGrid)_iStockHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockHistHashtable[tikcerId]).Close;
//}
}
else if (switchStockPool == "Earning Stock")
{
if (field == 4)
{
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Gap_From_High = ((float)price - ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).High) / ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Gap_From_Low = ((float)price - ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Low) / ((QuoteOnGridHist)_iStockEarningHistHashtable[tikcerId]).Close;
((QuoteOnGrid)_iStockEarningHashtable[tikcerId]).Last_Price = (float)price;
}
//else if (field == 1)
//{
// ((quoteongrid)_istockearninghashtable[tikcerid]).gap_from_high = ((float)price - ((quoteongridhist)_istockearninghisthashtable[tikcerid]).high) / ((quoteongridhist)_istockearninghisthashtable[tikcerid]).close;
// ((quoteongrid)_istockearninghashtable[tikcerid]).gap_from_low = ((float)price - ((quoteongridhist)_istockearninghisthashtable[tikcerid]).low) / ((quoteongridhist)_istockearninghisthashtable[tikcerid]).close;
//}
}
}
Not only you need to have PropertyChanged event in a class, you need to implement INotifyPropertyChanged. That's how the grid knows a class can inform of changes.

Resources