Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Developer
Posts: 19,636
Registered: ‎07-14-2008
My Device: Not Specified

Re: Help on analog clock code

[ Edited ]

Edit: Opps, this code was supposed to go in this Thread:

http://supportforums.blackberry.com/t5/Java-Development/RealTimeClockListener-problems/m-p/465367

 

However I think that it might help in this case too.  Please review. 

 

Try the following (which has not been tested on a device yet).

 

Code is not ideal, but does demonstrate two important tricks:

 

a) Using onExposed and OnObscured to stop the Thread (and thus reduce the overhead)

b) Doing as much as you can in an offline, rather than the Event Thread.  II have effectively got an 'offline' screen buffer that I use.

 

I am sure there are plenty of other 'enhancements' you could think of, but I've spent too much time on this already....  Real work calls...

 

This is NOT production code,  As is, with no warranty etc etc.  But if you spot a bug let me know....

 

Enjoy.

 

How to use it:

 

 

        // Create BitmapField for our Clock, size depnds on the Font
        Font clockFont = Font.getDefault().derive(Font.BOLD, 36, Ui.UNITS_pt); // 1/2 inch high
        int bitmapHeight = clockFont.getHeight() + 2;
        int bitmapWidth = clockFont.getAdvance("HH:MM:SS");
        Bitmap clockBitmap = new Bitmap(bitmapWidth, bitmapHeight);
        add(new ClockLabel(clockBitmap, Field.NON_FOCUSABLE | Field.FIELD_HCENTER, clockFont));

 

 

Actual code:

 

class ClockLabel extends BitmapField {

    Bitmap _ourBitmap = null; // Really only used to set the Size of this Field
    UpdateClockThread _updateClockThread = null;
    Font _fontTouse = null;
    
    public ClockLabel(Bitmap bitmap, long style, Font fontToUse) {
        super(bitmap, style);
        _ourBitmap = bitmap;
        _fontTouse = fontToUse;
    }
    protected void onDisplay() {
        onExposed();
    }
    protected void onUnDisplay() {
        onObscured();
    }
    protected void onExposed() {
        if ( _updateClockThread == null ) {
            _updateClockThread = new UpdateClockThread(_ourBitmap, _fontTouse, this);
            _updateClockThread.start();
        }
    }
    protected void onObscured() {
        if ( _updateClockThread != null ) {
            _updateClockThread.stop();
            _updateClockThread = null;
        }
    }
    public void invalidate() {
        super.invalidate();
    }
    class UpdateClockThread extends Thread {
        private SimpleDateFormat _sdf = null;
        private Bitmap _paintOnBitmap = null;
        private int _paintOnBitmapWidth = 0;
        private int _paintOnBitmapHeight = 0;
        private Graphics _g = null;
        private Font _fontToUse;
        private ClockLabel _ourField = null;
        private long LONG_ONE_THOUSAND = 1000;
        private boolean _stopped = false;
        public UpdateClockThread(Bitmap paintOnThis, Font fontToUse, ClockLabel fieldToInvalidate) {
            super();
            _paintOnBitmap = paintOnThis;
            _paintOnBitmapWidth = _paintOnBitmap.getWidth();
            _paintOnBitmapHeight = _paintOnBitmap.getHeight();
            _sdf = new SimpleDateFormat("HH:mm.ss");
            _g = new Graphics(_paintOnBitmap);
            _fontToUse = fontToUse;
            _g.setFont(_fontToUse);
            _ourField = fieldToInvalidate;
        }
        public void run() {
            long timeToSleep = 0;
            while (!_stopped) {
                String newTime = _sdf.formatLocal(System.currentTimeMillis());
                _g.setColor(Color.RED);
                _g.fillRect(0, 0, _paintOnBitmapWidth, _paintOnBitmapHeight);
                _g.setColor(Color.BLACK);
                _g.drawText(newTime, 2, 2, DrawStyle.HCENTER | DrawStyle.ELLIPSIS, _paintOnBitmapWidth-4);
                _ourField.invalidate();
                timeToSleep = LONG_ONE_THOUSAND - ( System.currentTimeMillis() % LONG_ONE_THOUSAND );
                if ( timeToSleep > 20 ) {
                    try {
                        Thread.sleep(timeToSleep);
                    } catch (Exception e) {
                    }
                }
            }
        }
        public void stop() {
            _stopped = true;
        }
    }

}

 

Contributor
Posts: 13
Registered: ‎02-17-2010
My Device: 8900
My Carrier: non

Re: Help on analog clock code

Hi Peter,

 

Thanks for that code, I tried to implement that approach for my analog clock but it still seems to be giving problem. I have tried to modify your approach by trying different things but it doesn't seem to work. Also, I read some discussions about timer being better approach if it works for you. I can believe such a small code can make processing slow on blackberry. All I am doing is a bitmap with to invalidate every second to display current time as analog clock. How does something like this can make ur menu to not work properly. Also, in your code stop the clock  when menu is displayed I would the clock to be ticking. I highly appreciate your help on this.

 

 

Developer
Posts: 19,636
Registered: ‎07-14-2008
My Device: Not Specified

Re: Help on analog clock code

Ok, I have modified my code and I think it will work in your environment.  Unfortunately I don't have a lot of your 'global' variables, nor do I have any of your png files, so the following has not been compiled.  It will no doubt fail, but I hope that you can figure out how to fix it.  As well as the 'tricks' from the last example, this one only loads the various Bitmaps once, which will save a load of time. 

 

Please leave the onObscured (I know you don't want it) until the processing is working correctly.  Then I would remove onObscured, and have the Thread detect when the application was not in the foreground - and stop if it is was not.  If not, it can stop updating the clock - the onExposed will mean that if it is ever bough to the foreground again the clock will reset itself to the correct time, probably before the user has even noticed.

 

Let me know how you get on wit this.

 

// How to use it

ClockBitmapField clock = new ClockBitmapField(face, Field.NON_FOCUSABLE | Field.FIELD_HCENTER,
                                              hrPng, minPng, secPng);
add(clock);

// Clock Face

class ClockBitmapField extends BitmapField {

    Bitmap _face = null;
    UpdateClockThread _updateClockThread = null;
    Bitmap [] _hourBitmaps = null;
    Bitmap [] _minBitmaps = null;
    Bitmap [] _secBitmaps = null;
    
    public ClockLabel(Bitmap face, long style, String [] hourPngs, String [] minPngs, String [] secPngs) {
        super(face, style);
        _face = face;
        _ourBitmap = new Bitmap(_face.getWidth(), _face.getHeight());
        this.setBitmap(_ourBitmap); // Swap to using work area
        _hourBitmaps = new Bitmap [hourPngs.length];
        for ( int i = 0; i < hourPngs.length; i++ ) {
            _hourBitmaps[i] = Bitmap.getBitmapResource(hourPngs[i]);
        }
        _minBitmaps = new Bitmap [minPngs.length];
        for ( int i = 0; i < minPngs.length; i++ ) {
            _minBitmaps[i] = Bitmap.getBitmapResource(minPngs[i]);
        }
        _secBitmaps = new Bitmap [secPngs.length];
        for ( int i = 0; i < secPngs.length; i++ ) {
            _secBitmaps[i] = Bitmap.getBitmapResource(secPngs[i]);
        }
    }
    protected void onDisplay() {
        onExposed();
    }
    protected void onUnDisplay() {
        onObscured();
    }
    protected void onExposed() {
        if ( _updateClockThread == null || !_updateClockThread.isAlive() ) {
            _updateClockThread = new UpdateClockThread(_ourBitmap, _face, this, _hourBitmaps, _minBitmaps, _secBitmaps);
            _updateClockThread.start();
        }
    }
    protected void onObscured() {
        if ( _updateClockThread != null ) {
            _updateClockThread.stop();
            _updateClockThread = null;
        }
    }
    public void invalidate() {
        super.invalidate();
    }
    class UpdateClockThread extends Thread {
        private Calendar _cal = null;
        int _curHr = 0;
        int _curMin = 0;
        int _curSec = 0;
        Bitmap _face = null;
        int _faceWidth = 0;
        int _faceHeight = 0;
        _ourBitmap = null;
        Graphics _g = null;
        ClockBitmapField _ourField = null;
        long LONG_ONE_THOUSAND = 1000;
        boolean _stopped = false;
        Bitmap [] _hourBitmaps = null;
        Bitmap [] _minBitmaps = null;
        Bitmap [] _secBitmaps = null;
        public UpdateClockThread(Bitmap ourBitmap, Bitmap face, ClockBitmapField fieldToInvalidate, 
                                 Bitmap [] hourBitmaps, Bitmap [] minBitmaps, Bitmap [] secBitmaps) {
            super();
            _cal = Calendar.getInstance();
            _face = face;
            _faceWidth = _face.getWidth();
            _faceHeight = _face.getHeight();
            _ourBitmap = ourBitmap;
            _g = new Graphics(_ourBitmap);
            _ourField = fieldToInvalidate;
        }
        public void run() {
            long timeToSleep = 0;
            while (!_stopped) {
                _g.setBackgroundColor(0x00191919);
                _g.clear();
                _g.drawBitmap(0, 0, _faceWidth, _faceHeight, _face, 0, 0);
                _cal.setTime(new Date(System.currentTimeMillis()));
                _curHr = cal.get(Calendar.HOUR);				
                _curMin = cal.get(Calendar.MINUTE);
                _curHr = (_curHr * 5) + (5 * _curMin / 60);
                if (_curHr > 60) _curHr = _curHr - 60;
                _curSec = cal.get(Calendar.SECOND);
                _g.drawBitmap(0, 0, _faceWidth, _faceHeight, _secBitmaps[_curSec], 0, 0);
                _g.drawBitmap(0, 0, _faceWidth, _faceHeight, _minBitmaps[_curMin], 0, 0);
                _g.drawBitmap(0, 0, _faceWidth, _faceHeight, _hourBitmaps[_curHr], 0, 0);
                _ourField.invalidate();
                timeToSleep = LONG_ONE_THOUSAND - ( System.currentTimeMillis() % LONG_ONE_THOUSAND );
                if ( timeToSleep > 20 ) {
                    try {
                        Thread.sleep(timeToSleep);
                    } catch (Exception e) {
                    }
                }
            }
        }
        public void stop() {
            _stopped = true;
        }
    }

} 

 

Developer
Developer
Posts: 1,123
Registered: ‎02-10-2009
My Device: 8130 / 8350 / 9530 / 9550 / 9850 / PlayBook
My Carrier: Verizon

Re: Help on analog clock code

If you do extend TimerTask instead of thread, then you can call timer.scheduleAtFixed Rate(task,1000) and let the time take care of making sure the average time between the start of each run is exactly 1 second. This would work perfectly for something like a clock, but poorly for a game as it will cause the game to run very fast if it were ever to lage behind. The only thing you will want to worry about when using a timer is that if the actual time on the device is changed then yout timer will be delayed or sped up accordingly (ie if you set the time backwards it will not run until the actual time it was scheduled for comes, and if you set it ahead it will keep firing until it catches up to the current time).

Highlighted
Contributor
Posts: 31
Registered: ‎01-27-2011
My Device: Tablet

Re: Help on analog clock code

can u explain please what i have to pass in hrPng, minPng, secPng variables .

m little bit confuse

thank

Developer
Posts: 144
Registered: ‎03-15-2011
My Device: blackberry smart phone
My Carrier: Airtel

Re: Help on analog clock code

hey i was also want to make an analog clock ... and came here to this post but i am little bit confused with what i should pass in the ClockBitmapField constructor hrPng, minPng, secPng can any body help me ..... please...