I'm currently working on an application with animation in JavaFX. The application is used by human corrector, who is correcting computer-generated subtitles. In the animation there is a floating text. My problem is that the animation sometimes shutters. You can see the following image for demonstration:
This flaw occurs mainly after resizing. When the animation breaks, it never gets to the fully functioning state again.
I use the JFXpanel which is in inserted in Swing UI. I use it this way because I've created quite a lot of code in Swing and I didn't want to toss it all away. I don't use Swing for animation because I wasn't able to create an animation that is smooth enough.
Here is the animation-related code:
public class AnimationPanel extends JFXPanel {
public MyAnimationTimer animationTimer;
public EditObject editObject;
public Color colorHOST1;
public Color colorHOST2;
public Color colorGUEST1;
public Color colorGUEST2;
public Color colorUSER;
public Color colorSIGNING;
public Color basicColor = Color.WHITE;
public Color currentColor = Color.WHITE;
public AnimationPanel(EditObject editObject) {
super();
this.editObject = editObject;
Group group = new Group();
this.animationTimer = new MyAnimationTimer((List<MyText>)(List<?>)group.getChildren(), this);
final Scene scene = new Scene(group, 800, 600, Color.BLACK);
this.setScene(scene);
this.animationTimer.start();
/* // Update animation when component is resized
this.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {
animationTimer.updateAnimations();
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public void componentHidden(ComponentEvent e) {
}
});*/
}
public void setColors(Gui g) {
this.colorHOST1 = Color.rgb(g.colorHOST1.getRed(), g.colorHOST1.getGreen(), g.colorHOST1.getBlue(), g.colorHOST1.getAlpha()/255.0);
this.colorHOST2 = Color.rgb(g.colorHOST2.getRed(), g.colorHOST2.getGreen(), g.colorHOST2.getBlue(), g.colorHOST2.getAlpha()/255.0);
this.colorGUEST1 = Color.rgb(g.colorGUEST1.getRed(), g.colorGUEST1.getGreen(), g.colorGUEST1.getBlue(), g.colorGUEST1.getAlpha()/255.0);
this.colorGUEST2 = Color.rgb(g.colorGUEST2.getRed(), g.colorGUEST2.getGreen(), g.colorGUEST2.getBlue(), g.colorGUEST2.getAlpha()/255.0);
this.colorUSER = Color.rgb(g.colorUSER.getRed(), g.colorUSER.getGreen(), g.colorUSER.getBlue(), g.colorUSER.getAlpha()/255.0);
this.colorSIGNING = Color.rgb(g.colorSIGNING.getRed(), g.colorSIGNING.getGreen(), g.colorSIGNING.getBlue(), g.colorSIGNING.getAlpha()/255.0);
}
}
public class MyAnimationTimer extends AnimationTimer {
private List<MyText> nodes;
private long subtitle_max_time_in_app;
private AnimationPanel animationPanel;
private boolean stopAtTheEnd = false;
private boolean isAtTheEnd = false;
private int currentPos = 0;
public MyAnimationTimer(List<MyText> nodes, AnimationPanel animationPanel) {
super();
this.nodes = nodes;
this.animationPanel = animationPanel;
}
#Override
public void handle(long now) {
MyText node;
if(this.stopAtTheEnd) {
if(this.isAtTheEnd) {
for (int i = this.currentPos; i < this.nodes.size(); i += 2) {
node = nodes.get(i);
if(this.collides(nodes.get(i-2), node)) {
node.setTranslateXforTextandSubText(nodes.get(i-2).getBoundsInParent().getWidth() + nodes.get(i-2).getTranslateX() + 10);
this.currentPos+=2;
}
node.setTranslateXforTextandSubText(node.getTranslateX() - node.getVelocity());
}
} else {
if(nodes.size()!=0) {
node = nodes.get(0);
if((node.getTranslateX() - node.getVelocity()) < 0) {
node.setTranslateXforTextandSubText(0);
this.isAtTheEnd = true;
this.currentPos = 2;
} else {
for (int i = 0; i < this.nodes.size(); i += 2) {
node = nodes.get(i);
node.setTranslateXforTextandSubText(node.getTranslateX() - node.getVelocity());
}
}
}
}
} else {
for (int i = 0; i < this.nodes.size(); i += 2) {
node = nodes.get(i);
node.setTranslateXforTextandSubText(node.getTranslateX() - node.getVelocity());
}
}
}
private boolean collides(MyText node1, MyText node2) {
return (node1.getBoundsInParent().getWidth() + node1.getTranslateX() - node2.getTranslateX()) + 7 >= 0;
}
public void addNode(final MyText node) {
Platform.runLater(() -> {
node.setTranslateYforTextandSubText(animationPanel.getHeight() / 2);
node.setTranslateXforTextandSubText(animationPanel.getWidth());
node.setVelocity(this.getVelocity());
nodes.add(node);
nodes.add(node.id);
// Check for overlaying
if(nodes.size()>=4) {
int size = nodes.size();
double overlaying = (nodes.get(size-4).getBoundsInParent().getWidth() + nodes.get(size-4).getTranslateX() - nodes.get(size-2).getTranslateX()) + 7;
if(overlaying>0) {
nodes.get(size-2).setTranslateXforTextandSubText(nodes.get(size-2).getTranslateX()+overlaying);
}
}
});
}
public void recalculateGaps() {
Platform.runLater(() -> {
if (nodes.size() >= 4) {
double overlaying;
// System.out.println("Size: " + nodes.size());
for (int i = nodes.size() - 2; i > 0; i -= 2) {
overlaying = (nodes.get(i - 2).getBoundsInParent().getWidth() + nodes.get(i - 2).getTranslateX() - nodes.get(i).getTranslateX()) + 7;
if (overlaying > 0) {
nodes.get(i - 2).setTranslateXforTextandSubText(nodes.get(i - 2).getTranslateX() - overlaying);
}
}
}
});
}
public void removeNodesBehindTheScene() {
Platform.runLater(() -> {
MyText node;
for (int i=0; i<nodes.size(); i+=2) {
node = nodes.get(i);
if(node.getTranslateX() > 0) {
break;
} else {
if(!node.isOverdue()) {
animationPanel.editObject.setMessageToBeSendSoon(node);
}
nodes.remove(i);
nodes.remove(i);
i-=2;
}
}
});
}
/* public void updateAnimations() {
// This method is called when the window is resized.
for (int i=0; i<this.nodes.size(); i+=2) {
nodes.get(i).setTranslateYforTextandSubText(animationPanel.getHeight()/2);
}
this.setVelocity();
}*/
public double getVelocity() {
return (this.animationPanel.getWidth()/4)*3/((double) this.subtitle_max_time_in_app)*1000/60;
}
public void setSubtitle_max_time_in_app(long subtitle_max_time_in_app) {
this.subtitle_max_time_in_app = subtitle_max_time_in_app;
}
public void setStopAtTheEnd(boolean stopAtTheEnd) {
// Remove all overdue
if(stopAtTheEnd) {
Platform.runLater(() -> {
for (int i = 0; i < nodes.size(); i += 2) {
if (nodes.get(i).isOverdue()) {
nodes.remove(i);
// Remove ID number
nodes.remove(i);
i -= 2;
} else {
break;
}
}
});
this.isAtTheEnd = false;
this.currentPos = 0;
}
this.stopAtTheEnd = stopAtTheEnd;
}
public void removeUpToNode(MyText node) {
Platform.runLater(() -> {
if(nodes.contains(node)) {
for (int i = 0; i < nodes.size(); i += 2) {
if (nodes.get(i) == node) {
nodes.remove(i);
nodes.remove(i);
break;
}
else {
nodes.remove(i);
nodes.remove(i);
i-=2;
}
}
}
});
}
public void addNodesAtTheBeginning(List<MyText> nodes_list, double nodeposition) {
Platform.runLater(() -> {
MyText node;
double position;
for (int i = nodes_list.size() - 1; i >= 0; i--) {
node = nodes_list.get(i);
node.setTranslateYforTextandSubText(animationPanel.getHeight() / 2);
if(nodes.size()!=0) {
position = this.nodes.get(0).getTranslateX() - node.getBoundsInParent().getWidth() - 10;
} else {
position = animationPanel.getWidth();
}
if(i==(nodes_list.size() - 1)) {
double exactposition = nodeposition - node.getBoundsInParent().getWidth();
if(exactposition < position) {
node.setTranslateXforTextandSubText(exactposition);
} else {
node.setTranslateXforTextandSubText(position);
}
} else {
node.setTranslateXforTextandSubText(position);
}
node.setVelocity(this.getVelocity());
nodes.add(0, node.id);
nodes.add(0, node);
}
});
}
}
I've tested various versions of JavaFX(including the one packed in JDK9), but with no result. Thanks in advance
Finally I fixed the bug. The problem was that I was setting a property of an existing node from my own thread instead of JavaFX thread. Putting it in Platform.runLater method fixed it. I didn't notice the bug immediately because it didn't throw the illegal thread exception as it does when you try to add node. I should have red the documentation more thoroughly.
Thanks
Related
Hello I'm fairly new to programming and this is my first time posting here so any help would be appreciated so:
my problem is that I"m trying to create some kind of 2D shooter game in java but I don't know if my simple game loop is good because when i shoot a missile it shoots a one every 20 ms and it's too fast and shoots a ton of missiles at once so is there any way to adjust it ? Like to keep some delay between every missile and the other??
and please tell me if i have problems or bad programming in my code !!
this is my game panel where most of the game happens and where my loop and adding missiles method in
public class GamePanel extends JPanel implements KeyListener {
Measurments mesure = new Measurments();
int panel_width = mesure.getUniversalWidth();
int panel_height = mesure.getUniversalHeight();
Timer timer;
Random rand = new Random();
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Missile> missiles = new ArrayList<>();
Player player = new Player(0, 0);
boolean up = false;
boolean down = false;
boolean right = false;
boolean left = false;
boolean isShooting = false;
boolean isRunning = true;
public boolean gameRunning() {
return isRunning;
}
int count = 5;
int missilesCount = 6;
public GamePanel() {
timer = new Timer(20, new ActionListener() {
public void actionPerformed(ActionEvent e) {
StartGame();
repaint();
}
});
setSize(panel_width, panel_height);
addKeyListener(this);
timer.start();
for (int i = 0; i < count; i++) {
addEnemy(new Enemy(rand.nextInt(750), rand.nextInt(500)));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.paint(g2d);
for (int i = 0; i < enemies.size(); i++) {
Enemy temp = enemies.get(i);
temp.paint(g2d);
}
for (int i = 0; i < missiles.size(); i++) {
Missile mis = missiles.get(i);
mis.paint(g2d);
mis.behave();
}
}
public void StartGame() {
if (isRunning) {
runGame();
setBackground(Color.YELLOW);
} else {
setBackground(Color.BLACK);
}
}
public void runGame() {
update();
};
public void update() {
player.checkBorders();
checkColls();
if (up) {
player.updateUp();
}
if (down) {
player.updateDown();
}
if (right) {
player.updateRight();
}
if (left) {
player.updateLeft();
}
if (isShooting) {
for (int i = 0; i < 5; i++) {
missiles.add(new Missile(player.getX() + 16, player.getY() + 16));
}
}
for (int i = 0; i < missiles.size(); i++) {
Missile temp = missiles.get(i);
if (temp.getX() == panel_width) {
RemoveMissile(temp);
}
}
}
public void addEnemy(Enemy e) {
enemies.add(e);
}
public void removeEnemy(Enemy e) {
enemies.remove(e);
}
public void addMissile(Missile e) {
missiles.add(e);
}
public void RemoveMissile(Missile e) {
missiles.add(e);
}
public void checkColls() {
for (int i = 0; i < enemies.size(); i++) {
Enemy tempEnm = enemies.get(i);
for (int e = 0; e < missiles.size(); e++) {
Missile tempMis = missiles.get(e);
if (tempMis.missileRect().intersects(tempEnm.enemyRect())) {
enemies.remove(tempEnm);
missiles.remove(tempMis);
}
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = true;
}
if (key == e.VK_DOWN) {
down = true;
}
if (key == e.VK_RIGHT) {
right = true;
}
if (key == e.VK_LEFT) {
left = true;
}
if (key == e.VK_ENTER) {
isRunning = true;
}
if (key == e.VK_SPACE) {
isShooting = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = false;
}
if (key == e.VK_DOWN) {
down = false;
}
if (key == e.VK_RIGHT) {
right = false;
}
if (key == e.VK_LEFT) {
left = false;
}
if (key == e.VK_SPACE) {
isShooting = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
Thanks in advance !!
private long fired = 0L;
public void update() {
...
// firing missiles: only if the missile count is less than the max., and the elapsed
// time is more than a limit (100 ms)
if ( isShooting && missiles.size() < missilesCount &&
( System.currentTimeMilis() - this.fired ) > 100 ) {
missiles.add( new Missile( player.getX() + 16, player.getY() + 16 ) );
// time of last firing
this.fired = System.currentTimeMilis();
}
...
}
public void RemoveMissile(Missile e) {
// as Guest is asked in another answer, this method should remove, not add...
missiles.remove(e);
}
I'm currently making a space invaders-esque game for my software engineering course. I've already got everything working that satisfies the requirements, so this isn't a 'solve my homework' kind of question. My problem is that the game will lag (at what seems like random times & intervals) to the point where it becomes too frustrating to play. Some things I think might be causing this - though I'm not positive - are as follows:
Problem with timer event every 10 ms (I doubt this because of the very limited resources required for this game).
Problem with collision detection (checking for collision with every visible enemy every 10 ms seems like it would take up a large chunk of resources)
Problem with repainting? This seems unlikely to me however...
#SuppressWarnings("serial")
public class SIpanel extends JPanel {
private SIpanel panel;
private Timer timer;
private int score, invaderPace, pulseRate, mysteryCount, distanceToEdge;
private ArrayList<SIthing> cast;
private ArrayList<SIinvader> invaders, dead;
private ArrayList<SImissile> missileBase, missileInvader;
private SIinvader[] bottomRow;
private SIbase base;
private Dimension panelDimension;
private SImystery mysteryShip;
private boolean gameOver, left, right, mysteryDirection, space, waveDirection;
private boolean runningTimer;
private Music sound;
private void pulse() {
pace();
processInputs();
if (gameOver) gameOver();
repaint();
}
private void pace() {
// IF invaders still live
if (!invaders.isEmpty()) {
invaderPace++;
// Switch back manager
if (distanceToEdge <= 10) {
switchBack();
pulseRate = (pulseRate >= 16) ? (int) (pulseRate*(0.8)) : pulseRate;
waveDirection = !waveDirection;
distanceToEdge = calculateDistanceToEdge();
}
// Move invaders left/right
else if (invaderPace >= pulseRate) {
invaderPace = 0;
distanceToEdge = calculateDistanceToEdge();
moveAI();
invadersFire();
if (!dead.isEmpty()) removeDead();
if (mysteryCount < 1) tryInitMysteryShip();
}
// All invaders are kill, create new wave
} else if (missileBase.isEmpty() && missileInvader.isEmpty() && !cast.contains(mysteryShip)) {
// System.out.println("New Wave!");
newWave();
}
// Every pace
if (!missileBase.isEmpty()) moveMissileBase();
// Every two paces
if (invaderPace % 2 == 0) {
if (!missileInvader.isEmpty()) moveMissileInvader();
if (mysteryCount > 0) moveMysteryShip();
}
}
private void processInputs() {
if (left) move(left);
if (right) move(!right);
if (space) fireMissile(base, true);
}
protected void fireMissile(SIship ship, boolean isBase) {
if(isBase && missileBase.isEmpty()) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()-(ship.getHeight()/4));
missileBase.add(m);
cast.add(m);
} else if (!isBase && missileInvader.size()<3) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()+(ship.getHeight()/4));
missileInvader.add(m);
cast.add(m);
}
}
private void newWave() {
pulseRate = 50;
int defaultY=60, defaultX=120, defaultWidth=30, defaultHeight=24;
for(int i=0; i<5; i++) {
for(int j=0; j<10; j++) {
if (i<1) invaders.add(new SItop((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<3) invaders.add(new SImiddle((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<5) invaders.add(new SIbottom((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
}
}
for (SIinvader s: invaders) {
cast.add(s);
}
if (!cast.contains(base)) {
cast.add(base);
}
bottomRow = getBottomRow();
}
private void tryInitMysteryShip() {
Random rand = new Random();
int x=rand.nextInt(1000);
if (x<=3) {
mysteryCount = 1;
if (rand.nextBoolean()) {
mysteryDirection = true;
}
if (mysteryDirection) {
mysteryShip = new SImystery(0, 60, 36, 18);
} else {
mysteryShip = new SImystery(480, 60, 36, 18);
}
cast.add(mysteryShip);
}
}
private void moveMysteryShip() {
int distance = 0;
if (mysteryDirection) {
mysteryShip.moveRight(5);
distance = getWidth() - mysteryShip.getX();
} else {
mysteryShip.moveLeft(5);
distance = 30+mysteryShip.getX()-mysteryShip.getWidth();
}
if (distance <= 5) {
dead.add(mysteryShip);
mysteryShip = null;
mysteryCount = 0;
}
}
private void removeDead() {
#SuppressWarnings("unchecked")
ArrayList<SIinvader> temp = (ArrayList<SIinvader>) dead.clone();
dead.clear();
for (SIinvader s : temp) {
invaders.remove(s);
cast.remove(s);
}
bottomRow = getBottomRow();
}
private void invadersFire() {
int[] p = new int[bottomRow.length];
for (int i=0; i<p.length; i++) {
for (int j=0; j<p.length; j++) {
p[j] = j;
}
Random rand = new Random();
int a=rand.nextInt(101);
if (a>=20) {
int b=rand.nextInt(p.length);
fireMissile(bottomRow[b], false);
}
}
}
private int calculateDistanceToEdge() {
int distance = 0;
SIinvader[] outliers = getOutliers();
if (waveDirection) {
distance = getWidth() - outliers[0].getX()-outliers[0].getWidth();
} else {
distance = outliers[1].getX();
}
return distance;
}
private SIinvader[] getOutliers() {
SIinvader leftMost = invaders.get(0), rightMost = invaders.get(0);
for (SIinvader s : invaders) {
if (s.getX() < leftMost.getX()) {
leftMost = s;
}
if (s.getX() > rightMost.getX()) {
rightMost = s;
}
}
return new SIinvader[] { rightMost, leftMost };
}
private SIinvader[] getBottomRow() {
SIinvader[] x = new SIinvader[(invaders.size()>10)?10:invaders.size()];
for (int i=0; i<x.length; i++) {
x[i] = invaders.get(i);
for (SIinvader s:invaders) {
if (s.getX() == x[i].getX()) {
if (s.getY() > x[i].getY()) {
x[i] = s;
}
}
}
}
return x;
}
private void move(boolean b) {
int defaultX = 5;
if (b) base.moveLeft(defaultX);
else base.moveRight(defaultX);
}
private void moveAI() {
for(SIinvader s : invaders) {
s.changeImage();
int defaultX = 5;
if (waveDirection) s.moveRight(defaultX);
else s.moveLeft(defaultX);
}
}
private void moveMissileBase() {
if (invaders.isEmpty()) return;
int movement = -5, bound = 0;
SImissile missile = missileBase.get(0);
missile.moveDown(movement);
SIinvader lowestInvader = getLowestInvader();
if (missile.getY() < (lowestInvader.getY() + lowestInvader.getHeight())) {
for (SIinvader s:bottomRow) {
if (checkCollision(missile, s)) {
s.setHit();
dead.add(s);
cast.remove(missile);
missileBase.clear();
score += s.value;
return;
}
}
if (mysteryCount > 0) {
if (checkCollision(missile, mysteryShip)) {
mysteryShip.setHit();
dead.add(mysteryShip);
cast.remove(missile);
missileBase.clear();
score += mysteryShip.value;
return;
}
}
if (missile.getY() < bound) {
missileBase.remove(missile);
cast.remove(missile);
}
}
}
private SIinvader getLowestInvader() {
SIinvader lowest = bottomRow[0];
for (SIinvader invader : bottomRow) {
if (invader.getY() > lowest.getY()) {
lowest = invader;
}
}
return lowest;
}
private void moveMissileInvader() {
int movement = 5, bound = (int) panelDimension.getHeight();
for (SImissile missile : missileInvader) {
missile.moveDown(movement);
if(missile.getY() >= base.getY()) {
if (checkCollision(missile, base)) {
base.setHit();
gameOver = true;;
missileInvader.remove(missile);
cast.remove(missile);
return;
} else if (missile.getY() >= bound-25) {
missileInvader.remove(missile);
cast.remove(missile);
return;
}
}
}
}
private boolean checkCollision(SIthing missile, SIthing ship) {
Rectangle2D rect1 = new Rectangle2D.Double(
missile.getX(),
missile.getY(),
missile.getWidth(),
missile.getHeight()
);
Rectangle2D rect2 = new Rectangle2D.Double(
ship.getX(),
ship.getY(),
ship.getWidth(),
ship.getHeight()
);
return rect1.intersects(rect2);
}
private void switchBack() {
int defaultY = 12;
for (SIinvader s : invaders) {
if (s.getY() > getHeight()) {
gameOver = true;
return;
}
s.moveDown(defaultY);
}
}
private void gameOver() {
pause(true);
SI.setGameOverLabelVisibile(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
Font font = new Font("Arial", 0, 20);
setFont(font);
String score = "Score: "+this.score;
Rectangle2D rect = font.getStringBounds(score, g2.getFontRenderContext());
int screenWidth = 0;
try { screenWidth = (int) panelDimension.getWidth(); }
catch (NullPointerException e) {}
g2.setColor(Color.GREEN);
g2.drawString(score, (int) (screenWidth - (10 + rect.getWidth())), 20);
for(SIthing a:cast) {
a.paint(g);
}
}
public SIpanel() {
super();
setBackground(Color.BLACK);
cast = new ArrayList<SIthing>();
missileBase = new ArrayList<SImissile>();
score = invaderPace = mysteryCount = pulseRate = 0;
sound = new Music("AmbientMusic.wav");
panel = this;
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = true; break;
case KeyEvent.VK_RIGHT : right = true; break;
case KeyEvent.VK_SPACE : space = true; break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = false; break;
case KeyEvent.VK_RIGHT : right = false; break;
case KeyEvent.VK_SPACE : space = false; break;
}
}
});
setFocusable(true);
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulse();
}
});
}
public void reset() {
SI.setGameOverLabelVisibile(false);
score = invaderPace = mysteryCount = 0;
pulseRate = 50;
cast = new ArrayList<SIthing>();
invaders = new ArrayList<SIinvader>();
dead = new ArrayList<SIinvader>();
missileBase = new ArrayList<SImissile>();
missileInvader = new ArrayList<SImissile>();
base = new SIbase(230, 370, 26, 20);
waveDirection = true;
gameOver = false;
sound.stop();
sound.loop();
panelDimension = SI.getFrameDimensions();
bottomRow = getBottomRow();
newWave();
timer.start();
runningTimer=true;
}
public SIpanel getPanel() {
return this.panel;
}
public void pause(boolean paused) {
if (paused) timer.stop();
else timer.start();
}
}
I believe that collision detection may be the reason for lagging and you should simply investigate it by trying to increase and decrease count of enemies or missiles drastically to see if that makes a difference.
Consider garbage collector your enemy. In your checkCollision method you are instantiating two (very simple) objects. It may not seem like a lot, but consider that your might be creating them for each collision check, and that at 60fps it adds up until it may reach critical mass when GC says "stop the world" and you see noticeable lag.
If that is the case, possible solution to that would be to not instantiate any objects in a method called so frequently. You may create Rectangle2D once, and then update its position, instead of creating a new one each time, so you will avoid unnecessary memory allocation.
Within the scope of a paper I am writing at high school I chose to make my own audio-file-to-spectrogram-converter from scratch in order to create landscapes out of these spectrograms.
I already do have my implementation of an FFT and of using that to make a heightmap, a spectrogram. But I often get weird artifacts in the form of vertical stripes when the frequencies get dense, as you can see in the image below.
The example is right at the beginning with a window length of 2048 and on a log^2-scale. The FFT I am using is flawless, I've already compared it to others and they produce the same result.
This is the function which transforms the amplitudes into frequencies and stores them in a 2D-array:
private void transform(int from, int until) {
double val, step;
for(int i=from; i<until; i++) {
for(int j=0; j<n; j++)
chunk[j] = data[0][i*n+j+start];
fft.realForward(chunk);
for(int j=0; j<height; j++) {
val = Math.sqrt(chunk[2*j]*chunk[2*j] + chunk[2*j+1]*chunk[2*j+1]);
map[i][j] = val;
}
}
}
Now my Question: Where do these vertical stripes come from and how do I get rid of them?
I currently don't employ a window function and every calculation is stringed to one another, which means there is no overlapping. It is the simplest way you can think of making a spectrogram. Could it help introducing a window function or doing each calculation independent of whether the frame was already involved in a previous calculation, that is to say overlapping the frame-windows?
Also, what other ways are there to improve on my basic approach in order to get a better result?
This is the whole class. I feed it the data and all the necessary information from an audio file:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import org.jtransforms.fft.DoubleFFT_1D;
public class Heightmap extends JFrame implements WindowListener{
public static final int LOG_SCALE = 0;
public static final int LOG_SQUARE_SCALE = 1;
public static final int SQUARE_SCALE = 2;
public static final int LINEAR_SCALE = 3;
private BufferedImage heightmap;
private FileDialog chooser;
private JMenuBar menuBar;
private JMenu fileMenu;
private JMenuItem save, close;
private DoubleFFT_1D fft;
private int[][] data;
private double[][] map;
private double[] chunk;
private int width, height, n, start, scale;
private String name;
private boolean inactive;
public Heightmap(int[][] data, int resolution, int start,
int width, int height, int scale, String name) {
this.data = data;
this.n = resolution;
this.start = start;
this.width = width;
this.height = height;
this.scale = scale;
this.name = name;
fft = new DoubleFFT_1D(n);
map = new double[width][height];
heightmap = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
chunk = new double[n];
System.out.println("Starting transformation...");
long time;
time = System.currentTimeMillis();
transform();
time = System.currentTimeMillis() - time;
System.out.println("Time taken for calculation: "+time+" ms");
time = System.currentTimeMillis();
makeHeightmap();
initComponents();
time = System.currentTimeMillis() - time;
System.out.println("Time taken for drawing heightmap: "+time+" ms");
}
private void initComponents() {
this.setSize(width, height);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setTitle(name);
createMenuBar();
chooser = new FileDialog(this, "Choose a directory", FileDialog.SAVE);
chooser.setDirectory("/Users/<user>/Desktop");
this.addMouseListener(new HeightmapMouseListener());
this.addKeyListener(new HeightmapKeyListener());
this.addWindowListener(this);
this.setVisible(true);
}
private void createMenuBar() {
menuBar = new JMenuBar();
fileMenu = new JMenu();
fileMenu.setText("File");
save = new JMenuItem("Save...", KeyEvent.VK_S);
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.META_DOWN_MASK));
save.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
chooser.setVisible(true);
String fileName = chooser.getFile();
String dir = chooser.getDirectory();
chooser.setDirectory(dir);
if(fileName != null) {
try {
File outputfile = new File(dir + fileName + ".png");
ImageIO.write(heightmap, "png", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Saved "+fileName+".png to "+dir);
}
}
});
close = new JMenuItem("Close", KeyEvent.VK_C);
close.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.META_DOWN_MASK));
close.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
}
});
fileMenu.add(save);
fileMenu.addSeparator();
fileMenu.add(close);
menuBar.add(fileMenu);
this.setJMenuBar(menuBar);
}
public void paint(Graphics g) {
g.drawImage(heightmap, 0, 0, null);
}
private void transform() {
transform(0, width);
}
private void transform(int from, int until) {
double max = Double.MIN_VALUE;
double min = Double.MAX_VALUE;
double val, step;
for(int i=from; i<until; i++) {
for(int j=0; j<n; j++) {
chunk[j] = data[0][i*n+j+start];
}
fft.realForward(chunk);
for(int j=0; j<height; j++) {
val = Math.sqrt(chunk[2*j]*chunk[2*j] + chunk[2*j+1]*chunk[2*j+1]);
if(val > max)
max = val;
if(val < min)
min = val;
map[i][j] = val;
}
if(min != 0) {
step = max/(max-min);
for(int j=0; j<height; j++)
map[i][j] = (map[i][j]-min)*step;
}
}
}
/*
* Paints heightmap into the BufferedImage
*/
private void makeHeightmap() {
double max = 0;
switch(scale) {
case LOG_SCALE: max = Math.log(findMax(map)+1); break;
case LOG_SQUARE_SCALE: max = Math.pow(Math.log(findMax(map)+1), 2); break;
case SQUARE_SCALE: max = Math.sqrt(findMax(map)); break;
case LINEAR_SCALE: max = findMax(map); break;
default: max = Math.pow(Math.log(findMax(map)+1), 2); break;
}
double stepsize = 255.0/max;
int val, rgb;
for(int x=0; x<width; x++)
for(int y=0; y<height; y++) {
switch(scale) {
case LOG_SCALE: val = (int) (Math.log(map[x][y]+1)*stepsize); break;
case LOG_SQUARE_SCALE: val = (int) (Math.log(map[x][y]+1)*stepsize); val *= val; break;
case SQUARE_SCALE: val = (int) (Math.sqrt(map[x][y])*stepsize); break;
case LINEAR_SCALE: val = (int) (map[x][y]*stepsize); break;
default: val = (int) (Math.log(map[x][y]+1)*stepsize); val *= val; break;
}
rgb = 255<<24 | val<<16 | val<<8 | val;
heightmap.setRGB(x, height-y-1, rgb);
}
}
private double findMax(double[][] data) {
double max = 0;
for(double[] val1: data)
for(double d: val1)
if(d > max)
max = d;
return max;
}
private class HeightmapKeyListener implements KeyListener {
boolean busy = false;
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_RIGHT && !busy && start < data[0].length-width*n) {
busy = true;
for(int x=0; x<width-1; x++)
map[x] = map[x+1].clone();
start += n;
transform(width-1, width);
makeHeightmap();
repaint();
busy = false;
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT && !busy && start > 0) {
busy = true;
for(int x=width-1; x>0; x--)
map[x] = map[x-1];
start -= n;
transform(0, 1);
makeHeightmap();
repaint();
busy = false;
}
}
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
}
private class HeightmapMouseListener implements MouseListener {
public void mouseClicked(MouseEvent e) {
if(inactive) {
inactive = false;
return;
}
long time = System.currentTimeMillis();
int posX = e.getX();
int diff = posX - width/2; //difference between old and new center in pixels
int oldStart = start;
start = start + diff*n;
if(start < 0) start = 0;
int maxFrame = data[0].length-width*n;
if(start > maxFrame) start = maxFrame;
if(start == oldStart) return;
System.out.println("Changing center...");
int absDiff = Math.abs(diff);
if(start < oldStart) { //shift the start backward, recalculate the start
for(int x=width-1; x>=absDiff; x--)
map[x] = map[x-absDiff].clone();
transform(0, absDiff);
}
else if(start > oldStart) { //shift the back forward, recalculate the back
for(int x=0; x<width-absDiff; x++)
map[x] = map[x+absDiff].clone();
transform(width-absDiff, width);
}
makeHeightmap();
repaint();
System.out.println("Time taken: "+(System.currentTimeMillis()-time)+" ms");
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
}
public void windowActivated(WindowEvent arg0) { }
public void windowClosed(WindowEvent arg0) { }
public void windowClosing(WindowEvent arg0) { }
public void windowDeactivated(WindowEvent arg0) {
inactive = true;
}
public void windowDeiconified(WindowEvent arg0) { }
public void windowIconified(WindowEvent arg0) { }
public void windowOpened(WindowEvent arg0) { }
}
EDIT:
Implementing a window function improved the result drastically. I really didn't understand what a window function would do and therefore underestimated its effect.
However, after doing so I tried mapping a cosine wave with a frequency of 10kHz which (again) produced some strange artifacts:
What could be the cause of this one? I implemented a overflow protection by clipping everything under 0 to 0 and over 255 to 255 with no change whatsoever.
This type of artifact can be due to overflow or otherwise exceeding parameter bounds before or in your color mapping function, or perhaps with some function (log?) returning NaN values. You might be able to find this by putting in some asserts for out-of-range or illegal values.
I have two classes (Sampling and Stacker). The Sampling class (my Main class) is extends JFrame and has a JButton with an ActionListener to open the Stacker class.
The problem is when the button is clicked, the Stacker class will open but only a frame without any components. When I switch the main method into the Stacker class, the program works fine. What is the problem?
Here is the code:
The Sampling class:
public class Sampling extends JFrame implements ActionListener
{
private JButton openStacker;
Stacker st;
public Sampling()
{
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
dispose();
st = new Stacker();
}
public static void main (String args[])
{
new Sampling();
}
}
The Stacker game class:
public class Stacker extends JFrame implements KeyListener
{
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5,5};
int layer = 19;
int deltax[] = {0,0};
boolean press = false;
boolean forward = true;
boolean start = true;
public Stacker()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton [m][n];
setLayout(new GridLayout(n,m));
for (int y = 0;y<n;y++)
{
for (int x = 0;x<m;x++)
{
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
this.addKeyListener(this);
this.setVisible(true);
go();
}
public void go()
{
int tmp = 0;
Component temporaryLostComponent = null;
do{
if (forward == true)
{
forward();
} else {
back();
}
if (deltax[1] == 10-length[1])
{
forward = false;
} else if (deltax[1] == 0)
{
forward = true;
}
draw();
try
{
Thread.sleep((long) time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}while(press == false);
if (layer>12)
{
time= 150-(iteration*iteration*2-iteration);
} else
{
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");
repeat();
}
last = deltax[1];
start = false;
go();
}
public int check()
{
if (start == true)
{
return length[1];
}
else if (last<deltax[1])
{
if (deltax[1]+length[1]-1 <= last+length[0]-1)
{
return length[1];
}
else
{
return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
}
}
else if (last>deltax[1])
{
return length[1]-Math.abs(deltax[1]-last);
}
else
{
return length[1];
}
}
public void forward()
{
deltax[0] = deltax[1];
deltax[1]++;
}
public void back()
{
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw()
{
for (int x = 0;x<length[1];x++)
{
b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0;x<length[1];x++)
{
b[x+deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat()
{
if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
{
dispose();
new Stacker();
}else{
System.exit(0);
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
press = true;
}
}
public void keyReleased(KeyEvent arg0)
{
}
public void keyTyped(KeyEvent arg0)
{
}
}
Just to put all my comments into an answer, and give you somewhere to start with:
Comment 1:
Take out go(); see that happens. I tested it and it will work. If you leave it there, even the frame's close button is jammed. You're blocking the edt with the while->Thread.sleep junk. You'll want to do some refactoring. You're code it hard to follow and I have no idea what you're trying to do, so I didn't even attempt it
Comment 2:
If you're wondering why it works when you just run the main from the Stacker class, it's probably because you are running it outside the EDT,
public static void main(String[] args) { new Stacker(); }. What happens when you click the button, that action is performed within the EDT, and hence your new Stacker() will be run on the EDT. In which case the EDT gets blocked by your while loop. If you try run the program from the Stacker class, but wrap it in a SwingUtilities.invokeLater, you will also notice the program fails to work. Swing programs should be run on the EDT though.
Comment 2: Read the first few sections on Concurrency with Swing
So what you can do is use a Swing Timer (which operates on the EDT) for the game loop. What I did was refactor your code a bit. It doesn't operate the way you want it to yet, only because I didn't really understand the logic of your code. So I couldn't get it to work. What I did though, is put some of the logic into the Timer.
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
And when the go() method is called, it just starts the timer by calling timer.start(). Basically what you need to know about the timer, is that every tick (the milliseconds you pass it), the actionPerformed will be called. So you can update the game state in that method, just like you did in the while loop each iteration.
Take some time to go over How to Use Swing Timers
To get the game working properly, you still need to make some adjustments, but this should give you a head start.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Sampling extends JFrame implements ActionListener {
private JButton openStacker;
Stacker st;
public Sampling() {
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
dispose();
st = new Stacker();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sampling();
}
});
}
}
class Stacker extends JFrame implements KeyListener {
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5, 5};
int layer = 19;
int deltax[] = {0, 0};
boolean press = false;
boolean forward = true;
boolean start = true;
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
public Stacker() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400, 580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton[m][n];
setLayout(new GridLayout(n, m));
for (int y = 0; y < n; y++) {
for (int x = 0; x < m; x++) {
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
JPanel panel = (JPanel)getContentPane();
panel.addKeyListener(this);
this.setVisible(true);
panel.requestFocusInWindow();
go();
}
public void go() {
int tmp = 0;
Component temporaryLostComponent = null;
timer.start();
if (layer > 12) {
time = 150 - (iteration * iteration * 2 - iteration);
} else {
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");
repeat();
}
last = deltax[1];
start = false;
//go();
}
public int check() {
if (start == true) {
return length[1];
} else if (last < deltax[1]) {
if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
return length[1];
} else {
return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
}
} else if (last > deltax[1]) {
return length[1] - Math.abs(deltax[1] - last);
} else {
return length[1];
}
}
public void forward() {
deltax[0] = deltax[1];
deltax[1]++;
}
public void back() {
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw() {
for (int x = 0; x < length[1]; x++) {
b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0; x < length[1]; x++) {
b[x + deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat() {
if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dispose();
new Stacker();
} else {
System.exit(0);
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("Pressed");
press = true;
}
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
Notice the SwingUtilities.invokeLater in the main. That's how you can start up the program on the EDT. The link on Concurrency In Swing will give you more information.
I want to implement a native drag and drop of widgets of a FlexTable without using any third party library in GWT.Im looking for something similar to this
http://tech.pro/tutorial/688/javascript-tutorial-drag-drop-lists
this is in javascript i want to achieve the similar kind of functionality with GWT
I have looked into the answer provided by #BruceLowe over here
Making a drag and drop FlexTable in GWT 2.5
but its is missing a few classes namely DragVerticalHandler and DraggableWidget classes so the code is not working. Does anyone know how to achieve this
After a little Prototyping I was able to make a drag gable flextable.I created a class which extended the flex table.Here is the code
public class DragFlexTable extends FlexTable implements
MouseDownHandler,MouseUpHandler,MouseMoveHandler,
MouseOutHandler
{
private int row,column,draggedrow,draggedcolumn;
private Element td;
private Widget w;
private boolean emptycellclicked;
DragFlexTable()
{
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEDOWN | Event.ONMOUSEMOVE);
this.addMouseDownHandler(this);
this.addMouseMoveHandler(this);
this.addMouseUpHandler(this);
this.addMouseOutHandler(this);
}
#Override
public void onBrowserEvent(Event event)
{
super.onBrowserEvent(event);
td = getEventTargetCell(event);
if (td == null)
{
return;
}
Element tr = DOM.getParent((com.google.gwt.user.client.Element) td);
Element body = DOM.getParent((com.google.gwt.user.client.Element) tr);
row = DOM.getChildIndex((com.google.gwt.user.client.Element) body, (com.google.gwt.user.client.Element) tr);//(body, tr);
column = DOM.getChildIndex((com.google.gwt.user.client.Element) tr, (com.google.gwt.user.client.Element) td);
}
boolean mousedown;
#Override
public void onMouseDown(MouseDownEvent event)
{
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT)
{
//to ensure empty cell is not clciked
if (!td.hasChildNodes())
{
emptycellclicked = true;
}
event.preventDefault();
start(event);
mousedown = true;
}
}
#Override
public void onMouseMove(MouseMoveEvent event)
{
if (mousedown)
{
drag(event);
}
}
#Override
public void onMouseUp(MouseUpEvent event)
{
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT)
{
if (!emptycellclicked)
{
end(event);
}
emptycellclicked = false;
mousedown = false;
}
}
#Override
public void onMouseOut(MouseOutEvent event)
{
this.getCellFormatter().getElement(row, column).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(row, column).getStyle().clearBorderColor();
this.getCellFormatter().getElement(row, column).getStyle().clearBorderWidth();
w.getElement().getStyle().setOpacity(1);
mousedown = false;
}
private void start(MouseDownEvent event)
{
w = this.getWidget(row, column);
w.getElement().getStyle().setOpacity(0.5);
}
private void drag(MouseMoveEvent event)
{
if (draggedrow != row || draggedcolumn != column)
{
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderColor();
this.getCellFormatter().getElement(draggedrow, draggedcolumn).getStyle().clearBorderWidth();
this.draggedrow = row;
this.draggedcolumn = column;
this.getCellFormatter().getElement(row, column).getStyle().setBorderStyle(BorderStyle.DASHED);
this.getCellFormatter().getElement(row, column).getStyle().setBorderColor("black");
this.getCellFormatter().getElement(row, column).getStyle().setBorderWidth(2, Unit.PX);
}
}
private void end(MouseUpEvent event)
{
insertDraggedWidget(row, column);
}
private void insertDraggedWidget(int r,int c)
{
this.getCellFormatter().getElement(r, c).getStyle().clearBorderStyle();
this.getCellFormatter().getElement(r, c).getStyle().clearBorderColor();
this.getCellFormatter().getElement(r, c).getStyle().clearBorderWidth();
w.getElement().getStyle().setOpacity(1);
if (this.getWidget(r, c) != null)
{
//pushing down the widgets already in the column
// int widgetheight = (this.getWidget(r, c).getOffsetHeight() / 2) + this.getWidget(r, c).getAbsoluteTop();
// int rw;
//placing the widget above the dropped widget
for (int i = this.getRowCount() - 1; i >= r; i--)
{
if (this.isCellPresent(i, c))
{
this.setWidget(i + 1, c, this.getWidget(i, c));
}
}
}
this.setWidget(r, c, w);
//removes unneccesary blank rows
cleanupRows();
//pushing up the column in the stack
// for (int i = oldrow;i<this.getRowCount()-1 ;i++)
// {
//
// this.setWidget(i ,oldcolumn, this.getWidget(i+1, oldcolumn));
//
// }
}
private void cleanupRows()
{
ArrayList<Integer> rowsfilled = new ArrayList<Integer>();
for (int i = 0; i <= this.getRowCount() - 1; i++)
{
for (int j = 0; j <= this.getCellCount(i) - 1; j++)
{
if (this.getWidget(i, j) != null)
{
rowsfilled.add(i);
break;
}
}
}
//replace the empty rows
for (int i = 0; i < rowsfilled.size(); i++)
{
int currentFilledRow = rowsfilled.get(i);
if (i != currentFilledRow)
{
for (int j = 0; j < this.getCellCount(currentFilledRow); j++)
{
this.setWidget(i, j, this.getWidget(currentFilledRow, j));
}
}
}
for (int i = rowsfilled.size(); i < this.getRowCount(); i++)
{
this.removeRow(i);
}
}
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler)
{
return addDomHandler(handler, MouseUpEvent.getType());
}
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler)
{
return addDomHandler(handler, MouseDownEvent.getType());
}
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler)
{
return addDomHandler(handler, MouseMoveEvent.getType());
}
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler)
{
return addDomHandler(handler, MouseOutEvent.getType());
}
}
and the on module load for the above custom widget is
public void onModuleLoad()
{
Label a = new Label("asad");
Label b = new Label("ad");
Label c = new Label("qwad");
Label w = new Label("zxd");
a.setPixelSize(200, 200);
a.getElement().getStyle().setBorderStyle(BorderStyle.SOLID);
a.getElement().getStyle().setBorderWidth(1, Unit.PX);
b.setPixelSize(200, 200);
c.setPixelSize(200, 200);
w.setPixelSize(200, 200);
a.getElement().getStyle().setBackgroundColor("red");
b.getElement().getStyle().setBackgroundColor("yellowgreen");
c.getElement().getStyle().setBackgroundColor("lightblue");
w.getElement().getStyle().setBackgroundColor("grey");
DragFlexTable d = new DragFlexTable();
d.setWidget(0, 0, a);
d.setWidget(0, 1, b);
d.setWidget(1, 0, c);
d.setWidget(1, 1, w);
d.setCellPadding(20);
RootPanel.get().add(d);
}