I'm trying to make a visualization of algorithms. I had a working program, but is was really dirty and I decided to re-orgranize it before I continued. The problem is that it won't repaint anymore before the algorithm finishes. (and I have tried using revalidate instead/in combination with repaint)
The option menu:
public class BootScreen extends JPanel implements ActionListener {
GridBagConstraints c = new GridBagConstraints();
JFrame frame = new JFrame();
SpinnerNumberModel arraySizeModel = new SpinnerNumberModel(50, 0, 100000, 1);
SpinnerNumberModel speedModel = new SpinnerNumberModel(20, 0, 10000, 1);
SpinnerNumberModel algSelectModel = new SpinnerNumberModel(1, 1, 5, 1);
JSpinner arraySizeSpinner = new JSpinner(arraySizeModel);
JSpinner speedSpinner = new JSpinner(speedModel);
JSpinner algSelectSpinner = new JSpinner(algSelectModel);
JButton start = new JButton("Start");
BootScreen() {
frame.setTitle("Settings");
frame.setSize(500, 250);
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(this);
//just creating the options menu, nothing special here (deleted for simplicity)
//...
}
#Override
public void actionPerformed( ActionEvent e ) {
Algorithm alg = new Algorithm(Integer.parseInt(arraySizeModel.getValue().toString()), Integer.parseInt
(speedModel.getValue().toString()));
switch(Integer.parseInt(algSelectModel.getValue().toString())) {
case 1:
alg.alg1();
break;
case 2:
alg.alg2();
break;
case 3:
alg.alg3();
break;
case 4:
alg.alg4();
break;
case 5:
alg.alg5();
break;
}
}
public static void main(String[] Args) {new BootScreen();}
}
The main algorithm stuffs:
public class Algorithm {
int[] A;
GUI gui;
int type;
int[] pointers;
int delay;
int max;
Random r = new Random();
Algorithm( int arraySize, int delaySet) {
A = new int[arraySize];
delay = delaySet;
gui = new GUI(this);
}
void generate(int maxIntSize, int pointersAmount, int typeSet) {
max = maxIntSize;
for( int i = 0; i < A.length; i++ ) {
A[i] = r.nextInt(max);
}
pointers = new int[pointersAmount];
for( int i = 0; i < pointers.length; i++ ) {
pointers[i] = -1;
}
type = typeSet;
}
void step(boolean sleep, int updatePointer, int updatePointerVal) {
pointers[updatePointer] = updatePointerVal;
gui.revalidate();
gui.repaint();
if( sleep ) {
try {
Thread.sleep(delay);
}catch( InterruptedException e ) {
}
}
}
//alg1(), alg2(), .... would be here. They first call generate() and call step() a couple of times. (deleted for simplicity)
}
The GUI:
public class GUI extends JPanel {
JFrame frame = new JFrame();
Algorithm alg;
GUI( Algorithm algIn ) {
alg = algIn;
frame.setTitle("Algorithmizer");
frame.setSize(1080, 720);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(this);
}
#Override
protected void paintComponent( Graphics g ) {
super.paintComponent(g);
//drawing alg.A as a bar-graph by looping through it (deleted for simplicity)
}
}
When I put System.out.println("1") before the repaint() call, System.out.println("2") in the paintComponent() function and System.out.println("3") after the repaint() call it will only print:
1
3
1
3
1
3
...
I also tried printing the stack, didn't get anything usefull from that either.
The program does repaint when the algorithm is done, but that isn't usefull to me.
Maybe take an approach like this. This will do all your calculations and stuff in a worker thread off the Event Dispatch Thread, and then call done() where you can do you GUI updates on the Event Dispatch Thread.
#Override
public void actionPerformed( ActionEvent e ) {
new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
runAlg();
return null
}
#Override
protected void done() {
//any of you gui stuff here
}
}.execute();
}
}
public void runAlg(){
Algorithm alg = new Algorithm(Integer.parseInt(arraySizeModel.getValue().toString()), Integer.parseInt
(speedModel.getValue().toString()));
switch(Integer.parseInt(algSelectModel.getValue().toString())) {
case 1:
alg.alg1();
break;
case 2:
alg.alg2();
break;
case 3:
alg.alg3();
break;
case 4:
alg.alg4();
break;
case 5:
alg.alg5();
break;
}
}
The problem is that it won't repaint anymore before the algorithm finishes.
Your algorithm is executing on the Event Dispatch Thread (EDT) which is the Thread the GUI uses to paint itself, therefore the GUI can't repaint itself until the algorithm is finished.
The solution is to use a separate Thread for the algorithm.
One way to do this is to use a Swing Worker which executes on a separate Thread and allows you to "publish" results as the algorithm is executing.
Read the section from the Swing tutorial on Concurrency for more details. The tutorial has a Swing Worker example.
Related
I'm writing my Tetris using Java Swing. The Game class revolves around a JFrame (frame), which consists of a TetrisPanel extending JPanel (panel) where the blocks fall, a JLabel (pontok) point counter, a JTextArea (rekord_text) showing high scores, and another JPanel (kovi) showing the next block to fall. My idea is that the game has 3 difficulty levels, where the blocks fall with different speed.
I thought the best way of approaching this problem is to create a new JFrame with the components above, but with the blocks' speed set different. I am able to close the old JFrame. However, when the new JFrame opens up, it is only a blank frame, and it won't respond to closing the window.
I should add that TetrisPanel is running a thread, but I am 90% sure I stop that with a volatile boolean.
Constructor of the Game class:
this.difSet(nehezseg); //this function sets the falling velocity
TetrisPanel.stopped = true; //this static member is the volatile boolean responsible for stopping the thread
new_game = false;
frame = new JFrame("Tetris_alpha");
frame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
panel = new TetrisPanel();
TetrisPanel.stopped = false;
new Thread(panel).start();
frame.add(panel, c);
pontok = new JLabel ("0");
frame.add(pontok, c);
rekord_text = new JTextArea();
//i set up the area
frame.add(rekord_text, c);
kovi = new NextAktualPanel();
frame.add(kovi, c);
menu = new MyMenu(this);
frame.setJMenuBar(menu);
frame.addWindowListener(new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
rekordok.add(panel.getPont());
rekordok.write(f);
e.getWindow().dispose();
System.exit(0);
}
}
);
frame.pack();
frame.setVisible(true);
}
The Game.start() function containing the game loop:
public void start()
{
//game_loop
while (!panel.GameOver() && !new_game)
{
if (panel.aktualLeertDetector())
{
panel.addAktualToBlocks();
panel.addNewAktual(next);
Elem temp = new Elem(0,0,rand.nextInt(7));
while (temp.getTipus() == next.getTipus())
temp = new Elem(0,0,rand.nextInt(7));
next = temp;
kovi.setNextAktual (next);
}
if (!paused)
pontok.setText(Integer.toString(panel.getPont()));
kovi.repaint();
panel.repaint();
}
The function which opens the new frame:
Public void newGame (Game g)
{
Game.new_game = true;
g.frame.dispose();
Game new_game = new Game("easy");
g = new_game;
g.start();
}
And the run() function of TetrisPanel:
public static volatile boolean stopped = false;
#Override
public void run() {
while (!stopped)
{
aktual.zuhan();
this.sorTeleAction();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Any help would be appreciated, including ideas about different a approach.
Do not use volatile boolean as status variable, use AtomicBoolean instead, volatile it's not the correct way to do this kind of things, and it does not either cause "immediate variable updating"... this is not volatile purpose.
It's not a good idea to start a thread on main AWT thread, you still have to use SwingUtilities.invokeLater(Runnable runnableAction). You can use something like this when launching a Gui Thread:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new Thread(threadAction).start();
} catch (Exception e) {
}
}
});
Hope that this will solve you problem!
I am writing a little game in Java and, like most games, I need to listen for user input. I decided to use java.awt.event.KeyListener to handle inputs.
Here is my main method:
public static void main(String[] args){
LevelViewer l = new LevelViewer(LevelFileIO.load());
List<Entity> entities = l.getEntities();
List<GameObject> gameObjects = l.getGameObjects();
Pacman player = null;
for (Entity e : entities){
if (e instanceof Pacman){
player = (Pacman)e;
break;
}
}
JFrame frame = new JFrame();
frame.add(l);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setFocusable(true);
frame.requestFocus();
class Listener implements KeyListener{
Pacman player;
Listener(Pacman player){
this.player = player;
}
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W:
player.up();
break;
case KeyEvent.VK_D:
player.right();
break;
case KeyEvent.VK_S:
player.down();
break;
case KeyEvent.VK_A:
player.left();
break;
}
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyTyped(KeyEvent e) {}
}
frame.addKeyListener(new Listener(player));
Timer timer = new Timer();
timer.schedule(new UpdateTimer(
entities.toArray(new Entity[entities.size()]),
gameObjects.toArray(new GameObject[gameObjects.size()]),
l), 0, 17);
}
That is all pretty straightforward, when I read key events I call methods in the player that simply change his velocity.
An example:
public void right(){
this.setVelocity(new Vector2(speed, 0));
this.setSprite(right);
}
The Timer at the end of the main method just calls this:
public UpdateTimer(Entity[] toUpdate, GameObject[] gameObjects, LevelViewer toRedraw){
this.toUpdate = toUpdate;
this.gameObjects = gameObjects;
this.toRedraw = toRedraw;
}
#Override
public void run() {
toRedraw.repaint();
if (timeAtLastUpdateCall == 0){
timeAtLastUpdateCall = System.currentTimeMillis();
for (Entity e : toUpdate){
e.start();
}
return;
}
long newTime = System.currentTimeMillis();
double deltaT = ((double)(newTime - timeAtLastUpdateCall)/1000.0);
timeAtLastUpdateCall = newTime;
for (Entity e : toUpdate){
for (GameObject g : gameObjects){
if (g.touching(e)){
e.setVelocity(e.getVelocity().multiply(-1));
e.free(g);
}
}
e.update(deltaT);
e.getSprite().nextFrame();
}
}
All this run function does is some collision checking and then calls the update method in each entity. In the case of the player it just calculates how much it should move since the last update call:
public void update(double deltaT){
this.setPosition(this.getPosition().add(velocity.multiply(deltaT)));
}
Now the problem is that when I press a key that changes the players velocity the change will usually occur instantaneously, but sometimes there can be noticeable lag (around a quarter of a second, much more than 17 ms).
Is this a problem with Java's KeyListener, or with my implementation?
I would like to fix this to have smooth user input.
I don't think this is an issue with KeyListener. I am not a game developer but some things to consider:
Have you timed how long it takes to do the TimerTask? If it's ever over 17ms then it could be a problem especially when you compare schedule to scheduleAtFixedRate
You may want to use a proper game loop particularly if you plan on this game being played on systems out side of your control.
I am having some difficulties using swing workers, timers, and I am actually a little confused.
As far as my understanding goes, I have to put on a timer to set-up recurring tasks that have to be called by the EDT.
I'm trying to make a program that shows graphically a sorting alghoritm (like this : https://www.youtube.com/watch?v=kPRA0W1kECg )
I just don't understand why the GUI won't refresh. I am quite sure the repaint method is being called since I put a sysout showing me the ordered values and it seems to work , but the GUI just... doesn't change.
Here's my code:
public class MainWindow {
private JFrame frame;
JPanel panel;
public final static int JFRAME_WIDTH = 800;
public final static int JFRAME_HEIGHT = 600;
public final static int NELEM = 40;
ArrayList<Double> numbers;
ArrayList<myRectangle> drawables = new ArrayList<myRectangle>();
Lock lock = new ReentrantLock();
Condition waitme = lock.newCondition();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainWindow window = new MainWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainWindow() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, JFRAME_WIDTH + 20, JFRAME_HEIGHT + 40);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new myPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
lock.lock();
try{
//Updating the gui
panel.repaint();
panel.revalidate();
//Giving the OK to the sorting alghoritm to proceed.
waitme.signal();
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
});
timer.start();
SwingWorker<Integer, String> sw = new SwingWorker<Integer, String>(){
#Override
protected Integer doInBackground() throws Exception {
mapAndCreate();
bubbleSort();
return null;
}
};
sw.execute();
}
private void bubbleSort() throws InterruptedException{
for(int i=0; i < NELEM; i++){
for(int j=1; j < (NELEM-i); j++){
if(drawables.get(j-1).wid > drawables.get(j).wid){
//swap the elements!
myRectangle temp = drawables.get(j-1);
drawables.set(j-1, drawables.get(j));
drawables.set(j, temp);
lock.lock();
try{
//Wait for the GUI to update.
waitme.await();
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
}
}
/***
* Function that maps values from 0 to 1 into the rectangle width.
*/
private void mapAndCreate() {
double max = 0;
numbers = new ArrayList<Double>(NELEM);
//Finding maximum.
for(int i = 0; i < NELEM; i++){
Double currElem = Math.random();
if(currElem > max) max = currElem;
numbers.add(currElem);
}
//Mapping process
int offset = 0;
for(int j = 0; j < NELEM; j++){
Integer mapped = (int) (( JFRAME_WIDTH * numbers.get(j) ) / max);
myRectangle rect = new myRectangle(offset , mapped);
drawables.add(rect);
offset += JFRAME_HEIGHT / NELEM;
}
}
private class myRectangle{
int myy , wid , colorR,colorG,colorB;
public myRectangle(int y , int wid){
this.myy = y;
this.wid = wid;
Random r = new Random();
colorR = r.nextInt(255);
colorG = r.nextInt(255);
colorB = r.nextInt(255);
}
}
private class myPanel extends JPanel{
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(myRectangle rectan : drawables){
Graphics2D graphics2D = (Graphics2D)g;
System.out.println(rectan.wid);
Rectangle2D.Double rect = new Rectangle2D.Double(0,rectan.myy,rectan.wid,JFRAME_HEIGHT / NELEM);
graphics2D.setColor(new Color(rectan.colorR,rectan.colorG,rectan.colorB));
graphics2D.fill(rect);
}
System.out.println("====================================================================================================");
}
}
}
Most OSs (or rather the UI frameworks which they use) don't support concurrent access. Simply put, you can't render two strings of text at the same time.
That's why Swing runs all rendering operations in the UI thread. Calling rendering functions (like paint()) outside of the UI thread can cause all kinds of problems. So when you do it, Swing will just remember "I should repaint" and return (instead of doing any actual work). That way, Swing protects you but most people would prefer to get an error with a useful message.
A timer always also means that there is a thread somewhere which executes when the timer runs out. This is not the UI thread of Swing. So any paing operations there must be wrapped with EventQueue.invokeLater() or similar.
Another common bug is to hog the UI thread (so no rendering happens because you do complex calculations there). That's what the SwingWorker is for. Again, in most methods of the SwingWorker, calling methods which would render something is forbidden (-> use invokeLater()).
So my guess is that the UI thread waits for the lock and the lock simply isn't unlocked early or often enough. See this demo how to do a simple animation in Swing.
public class TimerBasedAnimation extends JPanel implements ActionListener {
public void paint(Graphics g) {
// setup
// do some first-run init stuff
// calculate the next frame
// render frame
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame("TimerBasedAnimation");
frame.add(new TimerBasedAnimation());
...
}
}
As you can see in the code doesn't lock. Instead, you just send "render now" events from actionPerformed to Swing. Some time later, Swing will call paint(). There is no telling (and no way to make sure or force Swing) when this will happen.
So good animation code will take the current time, calculate the animation state at that time and then render it. So it doesn't blindly step through N phases in M seconds. Instead, it adjusts for every frame to create the illusion that the animation is smooth when it really isn't.
Related:
Java: Safe Animations with Swing
How to Use Swing Timers
I'm trying to make a simulation of a roulette game using GUI/Swing for my upcoming exam. I have two classes, one is called GUI and is actually the code used for the components, such as JFrame, JOptionPane, JButtons etc. The other one extends Thread and is supposed to show random numbers on a small JLabel, and the run method goes something like this:
public void run() {
int k = 0;
for (int i = 0; i < 50; i++) {
k = (new Random().nextInt(37));
label.setText(k + " ");
label.setFont(new Font("Tahoma", Font.BOLD, 56));
label.setForeground(Color.yellow);
try {
sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And in the GUI class I just want to TAKE the number from the last iteration of the above loop, and then pass it to a new int, which I'm going to use later in the GUI class.
Any ideas?
Use Swing Timer instead of Thread.sleep that sometime hangs the whole swing application.
Please have a look at How to Use Swing Timers
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
//next call from here
}
});
timer.setRepeats(false);
timer.start();
I just want to TAKE the number from the last iteration of the above loop, and then pass it to a new int, which I'm going to use later in the GUI class.
Just create a method (setter) in another class that accepts int and call it from this class for last call.
Sample code:
private int counter = 0;
private Timer timer;
...
final JLabel label = new JLabel();
label.setFont(new Font("Tahoma", Font.BOLD, 56));
label.setForeground(Color.yellow);
Thread thread = new Thread(new Runnable() {
public void run() {
timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (counter++ < 50) {
int k = (new Random().nextInt(37));
label.setText(k + " ");
} else {
timer.stop();
label.setText("next call");
}
}
});
timer.setRepeats(true);
timer.start();
}
});
thread.start();
snapshot:
i really need to find better ways to word my questions.
Basically I've created a program that takes information from a webpage and displays it nicely across the screen.
When the user closes the program, they actually hide it.
I also have another method which constantly loops checking for information to see if tis been updated.
unfortunately the problem im having is that it loops to fast, i only want it to check for information every 40 seconds or so.
What i tried was inserting a wait(1000,1000) in the method itself and in the main of the program. but both of these cause IllegalMonitorStateException.
Is this the correct way to make the thread wait properly? or is there a better way?
note: the only thread i have is the main.
MAIN
class Marquee
{
public static void main(String[] args) throws InterruptedException
{
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
while(true)
{
// this doesnt work
frame.wait(1000,1000);
frame.notifyAll();
frame.checkForNewUpdate();
System.out.println(" ____________________________next line _______________________________");
}
}
}
CHECK FOR UPDATES
public String[] checkForNewUpdate()
{
//setVisible(true);
String tempUpdate = getEngineersUpdate();
if (latestUpdate[0] != tempUpdate)
{
// do nothign
setVisible(false);
}
else if(latestUpdate[0]==tempUpdate)
{
latestUpdate[0] = tempUpdate;
//show the page again
setVisible(true);
}
else if(latestUpdate[0]!= "NULL")
{
// do nothing
//latestUpdate[0] = tempUpdate;
}
else
{
latestUpdate[0] = tempUpdate;
}
return latestUpdate;
}
1: WHat am i doing wrong to get this exception
2: Is there any other way to make a gap of time in a method
3: Am i going to have to put all these methods into another thread? Please say no
// my constructor which I failed to mention has a timer in it. only i dont know hwo to use it
class MyFrame extends JFrame implements ActionListener
{
private ActionListener listener;
private Timer t1;
private String [] latestUpdate = new String[1];
public MyFrame()
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// gets the maximum size of the screen
setSize(d.width,(d.height/100)*10);//sets it to max. need to change this
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int)rect.getMinX();
int y = (int)rect.getMaxY()-getHeight();
setLocation(x,y-30);
setTitle("ALERT::OUTAGE");
MyPanel panel = new MyPanel();
add(panel);
listener = this;
t1 = new Timer(50,listener);
t1.start();
}
by request, here is getEngineersUpdate()
public String getEngineersUpdate() //gets data from page and sets it to string.
{
String update = "blank";
final WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(false);// javascript causes some serious problems.
webClient.setCssEnabled(false);
String forChecking;
HtmlPage page;
try
{
URL outageURL = new URL("file:\\C:\\Users\\0vertone\\Desktop\\version control\\OUTAGE\\Outages.html"); //local drive at home
page = webClient.getPage(outageURL);
//All this crap can be gone if we just give the table an id
Object[] dates = page.getByXPath("//span[#id='date']/text()").toArray();
Object[] sites = page.getByXPath("//span[#id='site']/text()").toArray();
Object[] issues = page.getByXPath("//span[#id='issue']/text()").toArray();
System.out.println("" + dates[0].toString());
System.out.println("" + sites[0].toString());
System.out.println("" + issues[0].toString());
update = (dates[0].toString() + " " + sites[0].toString() + " " +issues[0].toString());
forChecking = dates[0].toString();
/**some examples of the getCellAt() method*/
//update = table.getCellAt(0,0).asText(); // This returns DATE/Time
//update = table.getCellAt(1,0).asText(); // This return the actual date
//update = table.getCellAt(0,1).asText(); // This returns, SITE/Sector
//update = table.getCellAt(1,1).asText(); // This returns the actual site issue
}
catch (FailingHttpStatusCodeException a)
{
System.out.println("Failing HTTP Status Execution");
a.printStackTrace();
}
catch (MalformedURLException b)
{
System.out.println("Malformed URL");
b.printStackTrace();
}
catch (IOException c)
{
System.out.println("IO PROBLEMS!");
c.printStackTrace();
}
webClient.closeAllWindows();
return update;
}
I've changed your code so it should work as you intended. I'm not clear on what getEngineersUpdate() does, so I can't say for sure if it will work, but I've given you a start. I've included 2 options for how to handle it, with explanation in the comments. You can see how to use a Timer properly in the constructor, also. Finally, I don't have your full code, so I had to rig something together to simulate it.
class Marquee {
public static void main(String[] args) throws InterruptedException {
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
}
}
class MyFrame extends JFrame {
private String [] latestUpdate = new String[1];
private static final int DISPLAY_TIME = 3000;
private Timer displayTimer;
/*
* Option #1:
* Ideally, you'd have the thread that generates the "Engineers Update" messages call this
* method. If you can't make this event based, then you should use option #2
*/
public void newUpdate(String message) {
setVisible(true);
// change this to whatever you need to.
text.setText(message);
displayTimer.restart();
}
// I used this to test it
private JTextField text;
public MyFrame() {
// gets the maximum size of the screen
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//sets it to max. need to change this
setSize(d.width, (d.height / 100) * 10);
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int) rect.getMinX();
int y = (int) rect.getMaxY() - getHeight();
setLocation(x, y - 30);
setTitle("ALERT::OUTAGE");
//MyPanel panel = new MyPanel();
//add(panel);
text = new JTextField("Initial Text");
add(text);
// this creates a timer that when it goes off, will hide the frame
displayTimer = new Timer(DISPLAY_TIME, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
// sets the timer not to repeat
displayTimer.setRepeats(false);
//This code is for option #2:
updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
checkForNewUpdate();
}
});
updateTimer.start();
}
// This is for option #2
private static final int UPDATE_INTERVAL = 1000;
private Timer updateTimer;
/*
* Option #2:
* Not ideal, but this should work.
*/
public String[] checkForNewUpdate() {
// I don't know how getEngineersUpdate() works
// which would have made it much easier to help you.
String tempUpdate = getEngineersUpdate();
// String comparison doesn't work like this in java.
// you also had a sleeping NullPointerException here
if (!tempUpdate.equals(latestUpdate[0])) {
// this is when you have a new update, correct?
newUpdate(tempUpdate);
latestUpdate[0] = tempUpdate;
} else if (tempUpdate.equals(latestUpdate[0])) {
// it's the same update as last time, so do nothing
} else if (tempUpdate.equals("NULL")) {
// You need to handle this according to what getEngineersUpdate() does
}
return latestUpdate;
}
// This code is rigged to show how it would work
private static int i = 0;
private String getEngineersUpdate() {
// 1 in 6 chance of returning "NULL"
if (Math.random() * 6 - 1 < 0)
return "NULL";
// probability of 1 in 4 of generating a new update
if(Math.random() * 4 - 1 < 0)
return "UPDATE #"+i++;
else
return "UPDATE #"+i;
}
}
I think you can't call wait() on an JFrame, but I am not sure.
You have to call wait() within a snychronized-block. (Example below)
Thread.sleep(1000l) can be used, if it runs in a Thread, but look for the class Timer
It would be much better design, if you create a thread, which checks for updates. You can notify the GUI (JFrame) with some kind of event-listener about the new date to display.
Take a look at the Timer and Callable.
You should create another thread, you should call checkforNewUpdate method from this thread. And also do not forget use SwingUtilities.invokeLater method to update your UI inside checkforNewUpdate method. here is the some part of the code;
public class Marque {
private JFrame frame;
class CheckForUpdate implements Runnable {
public void run() {
while(true) {
checkForNewUpdate();
try {
Thread.sleep(40000);
} catch (InterruptedException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
} }
}
public String[] checkForNewUpdate() {
//your code
// user interface interaction code
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
public Marque() {
frame = new JFrame();
//....frame related code
new Thread(new CheckForUpdate()).start();
}
public static void main(String[] arg) {
Marque marque = new Marque();
}