I've tried to make a countdown timer in AWT Frame, but was trapped with change of digit in label. I tried to use thread to solve the problem. Here is my unfinished code:
public static void main(String[] args){
Frame app = new Frame("Time Ticker");
//label is used to display digit here I will let the app count from 0-99;
final Label label = new Label();
//set it final bc this can be accessed in Anonymous Inner class
Thread threadDigit = new Thread(){
public void run(){
for(int i=0; i<100; i++){
label.setText(""+i);
//Problem: Reported As Error Why I cannot setText this way?
try{
//so the count down process will be more obvious
sleep(500);
}catch(Exception e){
System.out.println("insomia");
}
}
};
threadDigit.start();
app.add(label);
app.setSize(300,400);
app.setVisible(true);
}
Even though I did this way, the outcome is no thread sleep at all, only showing 99, I know I start threadDigit only once and so the for loop did everything from 0-99 and displayed 99, wondering how can I see digit tick from 0-99 with 500 millisecond's interval. Thanks for your help!
Related
So I have been having some trouble trying to create a teletype effect for my swing program. I essentially want to update a JFrame at 40ms increments with a new letter, "typing" out a message to the user. However, it flickers a lot when I try to do this. The method is below:
public static void animateTeletype(String input, JTextArea displayArea)
throws InterruptedException {
displayArea.setText("");
String s = "";
for(int i = 0; i<input.length(); i++) {
s += input.substring(i, i+1);
displayArea.setText(textToDisplay);
Thread.sleep(40);
displayArea.update(displayArea.getGraphics());
}
}
I figure the problem stems from updating the text too fast, and it has to update more than it can handle. I am not sure how I would go about this issue, as reducing tick time will make text scroll too slowly. Any advice is appreciated!
** I've solved the problem. This is my new code:
static Timer timer = null;
public static void animateTeletype(final String input, final JTextArea displayArea) throws InterruptedException
{
final String[] s = new String[1];
s[0] = " ";
final int[] i = new int[1];
i[0] = 0;
displayArea.setText("");
timer = new Timer(30, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
s[0] = input.substring(i[0], i[0]+1);
i[0]++;
displayArea.append(s[0]);
if(displayArea.getText().equals(input))
timer.stop();
}
});
timer.start();
}
displayArea.update(displayArea.getGraphics());
Don't use the update() method. There is never any reason to do that. Get rid of that statement.
Swing components will automatically repaint themselves.
displayArea.setText(textToDisplay);
Don't uset setText(...) to add new text.
Instead you should be using:
displayArea.append( "some more text" );
Don't use Thread.sleep(40) for animation. It you want animation then use a Swing Timer to schedule the animation.
I suggest you look at other section of the tutorial for Swing basics. Maybe something like How to Use Text Fields.
Ok so i'm going to try to explain this, well I created a shoot method in a class that contains my bluespell, and all of it's constructors, well the problem is when I press space once it constantly shoots without me pressing it again, and if I press it twice the speed at which it fires doubles and it starts to contain more than one x and y position on my grid I just want the spell to fire when fired and I only need one item because I don't want there to be more than one instance of it on the grid I want it to be that the player cannot fire until the spell has left the grid, here's my code thanks oh and I only have it called in my key released seeing as it should only do it once the key has been released, but if that should change please let me know thanks :)
public void shootSpell(){
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
ActionListener taskPerformed = new ActionListener(){
public void actionPerformed(ActionEvent e){
if(b.gety() != 19){
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety()+1)].setIcon(b.getIcon());
}
else{
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() +1);
}
}
};
new Timer(delay, taskPerformed).start();
else if(key == KeyEvent.VK_SPACE){
GoodSpell.shootSpell();
}
Do not use a Timer! Your task should not repeat every 100 milliseconds. If I understand your code, you should run the code from your ActionListener in a new thread.
// Something like this,
new Thread(new Runnable() {
public void run() {
if (b.gety() != 19) {
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety() + 1)].setIcon(b
.getIcon());
} else {
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() + 1);
}
}
}).start();
You also need to do a check if the spell is currently in view/activate prior to initiating a new spell in the shoot() method...
public void shootSpell(){
//do a check here if a spell is already running!
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
//......
So in your method that is updating the spell going accross the screen you either need to have a flag in there if its still active, or if you are running it in a new thread, save that thread to a global var and check to see if the thread is running prior instantiating a new BlueSpell()
This is a continuation from my last post Java: Animated Sprites on GridLayout. Thanks to a reply, it gave me an idea in where I just had to insert a loop in the trigger condition and call pi[i].repaint() in it. So far it works. Though I tried to integrate it to my game which composed of multiple sprites, it had no improvement in it. Without the animation, the sprites show on the grid with no problems. I inserted the animation loop in the GridFile class and it didn't show. I also tried to insert the animation loop in the MainFile, it showed irregular animations, kinda like a glitch. Can someone tell me where did I went wrong? Ideas are welcome.
MainFile class
public class MainFile {
JFrame mainWindow = new JFrame();
public JPanel gridPanel;
public MainFile() {
gridPanel= new GridFile();
mainWindow.add(gridPanel,BorderLayout.CENTER);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(700,700);
mainWindow.setResizable(false);
mainWindow.setVisible(true);
}
public static void main(String[]args){
new MainFile();
}
}
GridFile class
public class GridFile extends JPanel{
ImageIcon gameBackground = new ImageIcon(getClass().getResource("Assets\\GridBackground.png"));
Image gameImage;
int[] pkmArray = new int[12];
int random = 0;
Pokemon[] pkm = new Pokemon[36];
JPanel[] pokeball = new JPanel[36];
int j = 0;
public GridFile(){
setLayout(new GridLayout(6,6,6,6));
setBorder(BorderFactory.createEmptyBorder(12,12,12,12));
gameImage = gameBackground.getImage();
for(int i = 0;i < 36;i++){
do{
random = (int)(Math.random() * 12 + 0);
if(pkmArray[random] <= 3){
pokeball[i] = new Pokemon(random);
pokeball[i].setOpaque(false);
pokeball[i].setLayout(new BorderLayout());
pkmArray[random]++;
}
}while(pkmArray[random] >= 4);
add(pokeball[i],BorderLayout.CENTER);
}
while(true){
for(int i = 0; i < 36; i++){
pokeball[i].repaint();
}
}
}
public void paintComponent(Graphics g){
if(gameImage != null){
g.drawImage(gameImage,0,0,getWidth(),getHeight(),this);
}
}
}
Use a swing Timer for the repainting, and give a bit time between the frames for swing to do the painting work. There's no point trying to draw faster than what could be displayed anyway. If you have the animation loop in main(), the repaint manager will try to drop some of the repaint requests that appear close to each other, which can be the cause of the irregular animation you see.
You should create and access swing components only in the event dispatch thread. You current approach is breaking the threading rules.
Addition: When the animation loop is where you have it now, the GridFile constructor never returns, which explains that you'll see nothing because the code never gets far enough to show the window.
I'm looking for the best way to do the following. If someone could point me in the right direction I'd be greatfull.
I have 5 buttons,
Button 1
Button 2
Button 3
Button 4
Button 5
What I'd like to happen is every 5 seconds the focus of the button move one down. So the app starts and Button 1 has focus. Then 5 seconds later button 2 takes focus and so on so on until Button 5 and then back to Button 1. When I say focus I mean that if the space bar was pressed the button would be pressed. Any assistance would be appreciated. Thanks
You could use a java swing timer for this task. Take a look at the example in oracle docs
http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
You can use the KeyboardFocusManager for this as well. Sample code below using Timer object from java.util. The code below changes focus every 500 ms.
final KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
manager.focusNextComponent();
}
}, 0, 500);
Hope this helps.
You can create thread that sleeps for 5 senconds, then awakes and sets focus to the next button. Store your buttons in array.
final int n = 5;
final int TIMEOUT = 5000;
Button[] buttons = new Button[n];
// fill the array
new Thread() {
for (i = 0; ; i < n ? i++ : i = 0) {
buttons.requestFocusInWindow();
try {
Thread.sleep(TIMEOUT);
} catch(InterruptedException e) {}
}
}.start();
You can also use java.util.Timer
I've implemented a count down timer(in function) which updates a label in swing panel every second this is the code:
public void DefineTimer()
{
Action updateClockAction = new AbstractAction() {
public void actionPerformed(ActionEvent e){
JPanelMainGame.this.jLabelSeconds.setText(Integer.toString(JPanelMainGame.this.m_TimerTotalSeconds));
JPanelMainGame.this.jLabelSeconds.setFont(new java.awt.Font("Lucida Handwriting", 1, 36));
JPanelMainGame.this.jLabelSeconds.setForeground(Color.red);
JPanelMainGame.this.jLabelSeconds.setVisible(true);
if( JPanelMainGame.this.m_TimerTotalSeconds >0)
{
JPanelMainGame.this.m_TimerTotalSeconds--;
}
else if ( JPanelMainGame.this.m_TimerTotalSeconds == 0)
{
JPanelMainGame.this.m_Timer.stop();
JPanelMainGame.this.jLabelSeconds.setText("0");
System.out.println("!m_WasGameDecisived: "+!m_WasGameDecisived);
JPanelGameApplet gameApplet = (JPanelGameApplet) getTopLevelAncestor();
//Checking whether time ended for both players and no solution was recieved
if(gameApplet.GetJPanelChooseGame().GetGameType() == eGameType.Net)
{
gameApplet.GetClinetThread().UpdateServerOfTimeEnded();
if (!m_WasGameDecisived)
{
//
System.out.println("Tie - No one had a solution in the given time");
System.out.println("Before send request to solve - Is Socket Closed:"+((JPanelGameApplet)
gameApplet.GetClinetThread().SendRequestToClosePlayerThreadAndRemoveItFromPlayersOnServer();
((JPanelGameApplet)getTopLevelAncestor()).GetDJ().stop();
Menu.BrowseTo(PanelMenuNumber.k_ChooseGame, JPanelMainGame.this.getParent());
((JPanelGameApplet)getTopLevelAncestor()).GetDJ().play(0);
}
}
else if(gameApplet.GetJPanelChooseGame().GetGameType() == eGameType.Single)
{
JPanelMainGame.this.showPopUpSelectionBar();
}
}
((JPanelGameApplet)getTopLevelAncestor()).GetNetMainGame().Initialize();
}
};
m_Timer = new Timer(1000, updateClockAction);
}
Now my problem is in another part of my code when I want to to the following things:
case ProtocolMessages.k_StartGame:
m_GameApplet.GetJpanelStartNetGame().DefineTimer();
m_GameApplet.GetJpanelStartNetGame().GetTimer().start();
m_GameApplet.ShowBoardToSolve();
Menu.BrowseTo(PanelMenuNumber.k_NetPlayersGameStart,m_GameApplet.GetJPanelNetGameSetting().getParent());
m_GameApplet.GetDJ().Next();
break;
So The problem is when I want to start a game, I'm defining my timer and allocating it,
give it start command and going to the screen that I should see there the timer (JLabel updating).
And still although it should be already counting (even before that screen that shows the timer) I still got delay: I get the panel that show the timer, and after about two seconds the Jlabel appear and start to count down.
I think that it is because the event dispatch thread that is not updating immediately the Jlabel in the time I'm doing Jlabel.setText()
Any suggestions of how can I start a game without delay in showing the Jlabel?
Thanks
Call SwingUtilities.invokeAndWait frm the thread to set the label text.