Updating a set number of progress bars in one JFrame(preferably) - java

Looked around and there were a few similar questions, but none seemed to show how to run more than one progress bar in a single JFrame while updating it from 3 other threads.
Preferably I plan to have a progressbar class of its own, a lot of the examples I saw people doing all the progressbar work inside a main thread which I didn't really like. If that's how you're meant to do it I'm sorry I've never used a progressbar before.
I want to monitor the progress of the robot threads. I was going to send an update directly from the Robot class to my progress bar and have a progressbar object in my main if that's possible.
my main thread is sort of like this
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
Motor m = new Motor();
Robot xRob = new Robot(cyclicBarrier, m);
Robot yRob = new Robot(cyclicBarrier, m);
Robot zRob = new Robot(cyclicBarrier, m);
Thread xRobThread = new Thread(xRob);
Thread yRobThread = new Thread(new Robot(cyclicBarrier, m));
Thread zRobThread = new Thread(zRob);
boolean clockwise = true, counterClockwise = false;
m.setMotor(clockwise, 14400000, xRob);
m.setMotor(clockwise, 0, yRob);
m.setMotor(counterClockwise, 36000000, zRob);
xRobThread.start();
yRobThread.start();
zRobThread.start();
This is the important parts of my robot class.
public class Robot implements Runnable{
public void run(){
System.out.println("Running: ");
m.Engage(this);
try {
System.out.println("Sleeping: ");
Thread.sleep(3000);
cyclicBarrier.await();
} catch (Exception e){
e.printStackTrace();
}
System.out.println("Engaging: ");
}
public void Rotate(){
if ((opcode & clockwise) > 0){
rotation++;
if(rotation == 360){
rotation = 0;
moveCount++;
}
}
if ((opcode & counter) > 0){
rotation--;
if(rotation == -360){
rotation = 0;
moveCount --;
}
}
}
}
Here is the progress bar I have so far
public class ProgressBar {
final int MAX = 100;
final JFrame frame = new JFrame("JProgress ");
final JProgressBar pbOne = new JProgressBar();
final JProgressBar pbTwo = new JProgressBar();
final JProgressBar pbThree = new JProgressBar();
ProgressBar(){
pbOne.setMinimum(0);
pbOne.setMaximum(MAX);
pbOne.setStringPainted(true);
pbTwo.setMinimum(0);
pbTwo.setMaximum(MAX);
pbTwo.setStringPainted(true);
pbThree.setMinimum(0);
pbThree.setMaximum(MAX);
pbThree.setStringPainted(true);
frame.setLayout(new FlowLayout());
frame.getContentPane().add(pbOne);
frame.getContentPane().add(pbTwo);
frame.getContentPane().add(pbThree);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setVisible(true);
}
public void setProgress(int progress){
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pb.setValue(progress); //HERE IS where I get lost. How do I differentiate between PBs and Threads
// As in which thread the code is coming from and which progress bar it's updating.
}
});
java.lang.Thread.sleep(100);
} catch (InterruptedException e) {
JOptionPane.showMessageDialog(frame, e.getMessage());
}
}
}
I was going to update the progress everytime it went through a rotation in my robot class, but I haven't implemented that yet since I wanted to first get the design down.

Related

Creating and Discarding JFrames that run Threads

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!

KeyListener in a new thread for game input capture

I am making an old school Snake game in Java with Swing. I've read that in order to capture input in real time I need to run my game loop in a new thread so that It's wait() method won't interfere with the input capture. I've made InputCapture class implementing KeyListener and I've implemented keyPressed() method like that:
public class InputCapture implements KeyListener {
private Direction capturedDirection;
//Methods
#Override
public void keyPressed(KeyEvent e) {
boolean inputConsoleDebug = true;
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
capturedDirection = Direction.left;
if (inputConsoleDebug) System.out.println("LEFT");
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
capturedDirection = Direction.right;
if (inputConsoleDebug) System.out.println("RIGHT");
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
capturedDirection = Direction.up;
if (inputConsoleDebug) System.out.println("UP");
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
capturedDirection = Direction.down;
if (inputConsoleDebug) System.out.println("DOWN");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
public Direction getCapturedDirection() {
return capturedDirection;
}
}
Then I've made Game class extending Thread and I've put game loop code into run() method:
public class Game extends Thread {
private Board board;
private Snake snake;
private JFrame frame;
private long waitTime;
private int difficultyStep;
private Direction inputDirection;
private InputCapture inputManager;
//Constructors
Game(Dimension boardSize) {
//Set difficulty
int applesToWin = boardSize.width * boardSize.height - 1;
final int easiestWaitTime = 1000;
final int hardestWaitTime = 100;
difficultyStep = (easiestWaitTime - hardestWaitTime) / applesToWin;
waitTime = easiestWaitTime;
//Set starting point
final int startingPointX = boardSize.width / 2;
final int startingPointy = boardSize.height / 2;
//Set board and snake
board = new Board(boardSize);
snake = new Snake(board, startingPointX, startingPointy);
//Set window Frame
frame = new JFrame(SnakeApplication.getApplicationName());
frame.setContentPane(board);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setResizable(false);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
interrupt();
}
});
//Set input manager
inputManager = new InputCapture();
frame.addKeyListener(inputManager);
inputDirection = null;
}
//Methods
public void run() {
board.spawnApple();
while (!isWon()) {
try {
sleep(waitTime);
} catch (InterruptedException e) {
return;
}
try {
inputDirection = inputManager.getCapturedDirection();
snake.move(inputDirection);
} catch (LosingMove e) {
showGameOverDialog();
return;
}
board.repaint();
}
showWinDialog();
}
JFrame getFrame() {
return frame;
}
private boolean isWon() {
for (int row = 0; row < board.getFields().length; row++) {
for (int col = 0; col < board.getFields()[0].length; col++) {
if (!(board.getFields()[row][col].getContent() instanceof Snake.SnakeNode)) return false;
}
}
return true;
}
private void showGameOverDialog() {
JFrame gameOverFrame = new JFrame();
JOptionPane.showMessageDialog(gameOverFrame, "Game Over!");
}
private void showWinDialog() {
JFrame gameOverFrame = new JFrame();
JOptionPane.showMessageDialog(gameOverFrame, "You Win!");
}
}
In my MainMenu class I've made startNewGame() method that is called when New Game button is clicked. This method creates Game object and starts a new thread by calling start() method.
public class MainMenu {
//Form components references
private JButton exitButton;
private JFrame frame;
private JPanel mainPanel;
private JButton newGameButton;
private JLabel titleLabel;
//Constructors
MainMenu() {
//Set window Frame
frame = new JFrame(SnakeApplication.getApplicationName());
frame.setContentPane(mainPanel);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(false);
frame.pack();
newGameButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
startNewGame();
}
});
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
exitGame();
}
});
}
JFrame getFrame() {
return frame;
}
private Dimension showBoardSizeDialog() {
Frame boardSizeFrame = new Frame();
int width = Integer.parseInt(JOptionPane.showInputDialog(boardSizeFrame, "Set board's width:"));
int height = Integer.parseInt(JOptionPane.showInputDialog(boardSizeFrame, "Set board's height:"));
return new Dimension(width, height);
}
private void startNewGame() {
Dimension boardSize = showBoardSizeDialog();
frame.setVisible(false);
Game game = new Game(boardSize);
game.getFrame().setVisible(true);
//Starting game loop in a new thread
game.start();
try {
game.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
frame.setVisible(true);
}
}
But when testing the app it gets stuck in the game loop and doesn't capture input at all. Why? I was trying to debug It, but every time the new thread is started it gets stuck in game loop. The Board itself is painted only when main thread ends its execution. Why? Shouldn't It be repainted many times during game loop if execution is stucked there?
Also, I've made thread interrupt when frame's close button is clicked (red X button) so execution could get back to MainMenu and reappear it, but clicking red close button has no effect.
The program freezes because of the call to game.join() in startNewGame. join keeps the thread it was called from from continuing execution until the thread it was called on dies. In your situation, join defeats the purpose of using another thread, so you should just remove that.
There are other issues, though. You probably shouldn't use a thread. You should probably use a Swing Timer. Swing isn't thread-safe, and I can already see a few places where your code isn't thread-safe either. (For example, you need to declare capturedDirection as volatile.) Writing correct multi-threaded code with Swing is a bit complicated and it would be much simpler to just use a timer.
Otherwise, if you don't use a timer, you need to use e.g. synchronization between the game thread (which writes to shared game state) and the Swing thread which does painting (and presumably reads from shared game state). If you don't, you may run in to problems that are hard to diagnose.
Also see The Use of Multiple JFrames: Good or Bad Practice?
You should make your Game class extending Runnable instead of Thread.
Then to have the game in a different thread:
Game theGame = ... // initialization code here
new Thread(theGame).start();

Why my GUI won't update even tho repaint() is being called?

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

Is there a way to animate an entire Jframe in Java so that it moves?

I would like to create a program where the Jframe is able to move freely on it's own. Kind of like a translation / transition.
For example,
Click on program to begin.
Jframe spawns at location (0,0).
Automatically move (animate) 100 pixels to the right so that the new coordinates are (100,0).
I know there's the setLocation(x,y) method that sets the initial position once the program runs but is there a way to move the entire Jframe after the program starts?
The basic concept would look something like this...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
public MoveMe01() {
EventQueue.invokeLater(
new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point location = frame.getLocation();
Point to = new Point(location);
if (to.x < 100) {
to.x += 4;
if (to.x > 100) {
to.x = 100;
}
}
if (to.y < 100) {
to.y += 4;
if (to.y > 100) {
to.y = 100;
}
}
frame.setLocation(to);
if (to.equals(location)) {
((Timer)e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}
This is a pretty straight, linear animation. You'd be better of investigating one of the many animation engines available for Swing, this will provide you with the ability to change the speed of the animation based on the current frame (doing things like slow-in and slow-out for example)
I would take a look at
Timing Framework
Trident
Universla Tween Engine
Updated with a "variable time" solution
This is basically an example of how you might do a variable time animation. That is, rather then having a fixed movement, you can adjust the time and allow the animation to calculate the movement requirements based on the run time of the animation...
public class MoveMe01 {
public static void main(String[] args) {
new MoveMe01();
}
// How long the animation should run for in milliseconds
private int runTime = 500;
// The start time of the animation...
private long startTime = -1;
public MoveMe01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
final JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Use the Force Luke"));
frame.pack();
frame.setLocation(0, 0);
frame.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (startTime < 0) {
// Start time of the animation...
startTime = System.currentTimeMillis();
}
// The current time
long now = System.currentTimeMillis();
// The difference in time
long dif = now - startTime;
// If we've moved beyond the run time, stop the animation
if (dif > runTime) {
dif = runTime;
((Timer)e.getSource()).stop();
}
// The percentage of time we've been playing...
double progress = (double)dif / (double)runTime;
Point location = frame.getLocation();
Point to = new Point(location);
// Calculate the position as perctange over time...
to.x = (int)Math.round(100 * progress);
to.y = (int)Math.round(100 * progress);
// nb - if the start position wasn't 0x0, then you would need to
// add these to the x/y position above...
System.out.println(to);
frame.setLocation(to);
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
}

Make a main method wait on a smaller method (java)

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();
}

Categories

Resources