I have ten words in a string array. As an example: {"A B","C D","E F","G H"......}.
I have to display these words in succession, holding each word on screen for 2 seconds. With each new word displayed, the font size needs to get smaller as well.
How do I do this on a BlackBerry?
You can use a Timer to control the timing:
import java.util.Timer
int index;
String[] words;
...
TimerTask task = new TimerTask() {
public void run()
{
// TODO: Check the bounds and kill the timer when we're done.
// Invoke the code in the UI Thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run()
{
// Code to enumerate and concat the string...
}
});
}
};
timer timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 2000);
To change font size:
// in the class body:
final int minFontSize = 5;
int maxFontSize = minFontSize + words.length();
// in the timer's run method:
net.rim.device.api.ui.Font defaultFont = this.getFont();
net.rim.device.api.ui.Font myFont = defaultFont.derive(0, maxFontSize - index)
// change the font of the ui control
field.setFont(myFont);
I haven't checked the code to see if it compiles, but I hope you get the idea.
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.
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!
In my program, there is a button, "Display", and another button, "Reset".
The user enters the number of prime numbers they want in the text field and then clicks the "Display" button. Then, the first x prime numbers will appear in the text area.
In the code, I have:
Declarations:
Thread go;
Thread newThread;
JLabel howManyLabel;
JTextField howMany;
JButton display;
JButton reset;
JTextArea primes;
Action Event:
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == display) {
display.setEnabled(false);
if (go == null) {
go = new Thread(this);
go.start();
} else {
newThread = new Thread(this);
newThread.start();
}
} else if (source == reset) {
display.setEnabled(true);
howMany.setText(" ");
primes.setText(" ");
}
}
Run method:
public void run() {
int quantity = Integer.parseInt(howMany.getText());
int numPrimes = 0;
int candidate = 2; // candidate = the number that MIGHT be prime
primes.append("First " + quantity + " primes:");
while(numPrimes < quantity) {
if (isPrime(candidate)) {
primes.append(candidate + ", ");
numPrimes++;
}
candidate++;
}
}
The run() method is in the same class, and simply calculates the first x amount of prime numbers.
I am trying to create a new thread every time the "Reset" button is called. The thread runs the first time, but then does not run again after I click "Reset". Can the run() method only work once?
Thanks in advance.
The run() method is just like any other method and can be invoked any number of times. The method that cannot be invoked multiple times is start()(according to Thread).
Your explanation does not seem to fit with the code you gave. You say you want to spawn a new thread when a user clicks reset, yet you only construct or start threads if the source is Display. Did you mean, rather, that you want to cancel the last thread and enable controls for the user to start again? In that case you should use a Future, not a generic thread.
Another thing is that UI components are generally not thread-safe. Swing explicitly warns against it on every components JavaDoc. What you may be seeing is just components not updating their visible state when they are changed from a different thread. Have you tried using a debugger to see if a thread is actually not getting spawned, or it is being spawned, but not having the result you want?
I'm wondering why still I couldn't to figure out a way to do this. Although it seems like very simple, I spent my entire day for this. But couldn't do that.
I have set of dice images. 1.png,2.png,.... and 6.png.
There is an ImageView in my layout. That is,
ImageView dice = (ImageView) findViewById(R.id.imageViewrollingdiceOne);
Here I want to change this imageView rapidly to see a some kind of a visual/animation using above 6 images. For that I wrote following piece of code.
Code 1:
for (int j=0;j<10;j++){
int randomNum = random.nextInt(6);
System.out.println("Random Value " + randomNum);
dice.setImageResource(images[randomNum]);
}
Output:
There is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration.
I thought that it is because the loop is executing very fast.
Then I did the following.
Code 2:
for (int j=0;j<10;j++){
int randomNum = random.nextInt(6);
System.out.println("Random Value " + randomNum);
dice.setImageResource(images[randomNum]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Output:
Again there is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration.
Then I did the following.
Code 3:
final Handler localHandler = new Handler();
Runnable runnableObject = new Runnable() {
public void run() {
final ImageView dice = (ImageView) findViewById(R.id.imageViewrollingdiceOne);
int randomNum = random.nextInt(6);
System.out.println("Random Value" + randomNum);
dice.setImageResource(images[randomNum]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
for (int j=0;j<10;j++){
localHandler.postDelayed(runnableObject, 1000);
}
Again there is not a visual. imageView remains unchanged and suddenly changes at the loop last iteration. There are no any errors in logcat in all three cases.
I found that threading also doesn't do the trick.
First of all there is already an animation set in android that can help you achive what you are after it is called FrameAnimation, here is an example on how to use it:
FrameAnimation Example
Your First, second and third code are running in the main thread, you should never use sleep in the main thread !.
If you still want to set the image resource manually you can use this code:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
int randomNum = random.nextInt(6);
dice.setImageResource(images[randomNum]);
handler.postDelayed(this, 500);
}
}, 500);
This is helpful when you're using list of items and changing according time interval one by one. Initially i value should be 0, size of list depends.
final Handler handler = new Handler();
handler.postDelayed(new Runnable(){
public void run(){
if(i<4) {
galleryImg.setImageResource(myImageList[i]);
i++;
} else {
i=0;
}
handler.postDelayed(this, 10000);
}
}, 500);
The reason you're probably not seeing changes is because the final callback to the main UI thread happens after your thread finishes its execution and you only see the final result. Now, this is my (probably poor) understanding and someone more versed in it can probably correct me.
That said you should probably look to using an AnimationDrawable object:
ImageView sImage = (ImageView)findViewById(R.id.imageViewrollingdiceOne);
AnimationDrawable anim = new AnimationDrawable();
for (int j=0;j<6;j++) {
anim.addFrame(new BitmapDrawable(images[j], 200);
}
sImage.setBackgroundDrawable(anim);
anim.setOneShot(false);
anim.start();
This assumes you've generated images[] with the images in random order already. If you want to change that up put whatever code you need in the for-loop.
What it does is creates an animation object much like how you'd see a gif work with a set delay interval between changes (in this code its 200ms). You can elect to change that number if you wish. The setOneShot call makes sure it loops instead of finishing the animation and stopping on the last image.
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.