Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Archived:How to scroll an over sized image on PySymbian canvas

From Wiki
Jump to: navigation, search

Archived.pngAquivado: Este artigo foi arquivado, pois o conteúdo não é mais considerado relevante para se criar soluções comerciais atuais. Se você achar que este artigo ainda é importante, inclua o template {{ForArchiveReview|escreva a sua justificativa}}.

All PySymbian articles have been archived. PySymbian is no longer maintained by Nokia and is not guaranteed to work on more recent Symbian devices. It is not possible to submit apps to Nokia Store.

Article Metadata
Article
Created: lfd (27 Jun 2007)
Last edited: hamishwillee (31 May 2013)

You can scroll oversized images on canvas to create rich pages.

Here is a base class I use in different projects. The solution is not 100% perfect since there are a few issues with scalable fonts on 3rd Edition. This probably comes from wrap_text_to_array that needs to be checked. Owners of big screen resolution devices will understand when trying.

Contents

Scrolling images

Horizontal scroll

canvas.blit(overSizedImageObject ,target=( xValueInPixel, 0 ) )

Vertical scroll

canvas.blit(overSizedImageObject ,target=( 0, -yValueInPixel ) )



PageBuilder Library

This library shows a working example of image scrolling. This library creates an oversized image to display text. The image is blit to a canvas object and the scrolling factor can be controlled via the Up and Down softkeys.

Source

import appuifw, e32
from key_codes import EScancodeUpArrow, EScancodeDownArrow
from graphics import Image
try:
from akntextutils import wrap_text_to_array
except:
import sys
sys.exit("akntextutils module isn't installed!")
 
## Keyboard handler class.
class Keyboard( object ):
## The constructor
# @param self The object pointer
# @param aOnevent An optional function that can be called on events
def __init__( self, aOnevent=lambda:None ):
## Keboard state dictionnary
self._keyboard_state = { }
## Key down dictionnary
self._downs = { }
## User defined callback function run when an event occures
self._onevent = aOnevent
 
## Event handler
# @param self The object pointer
# @param aEvent Event detected
def handle_event( self, aEvent ):
if aEvent['type'] == appuifw.EEventKeyDown:
code = aEvent['scancode']
if not self.is_down( code ):
self._downs[code] = self._downs.get( code, 0 ) + 1
self._keyboard_state[code] = 1
elif aEvent['type'] == appuifw.EEventKeyUp:
self._keyboard_state[aEvent['scancode']] = 0
self._onevent( )
 
## Detects if the given keycode key is down
# @param self The object pointer
# @param aScancode key code
def is_down( self, aScancode ):
return self._keyboard_state.get( aScancode, 0 )
 
## Returns true if the given keycode key has been pressed
# @param self The object pointer
# @param aScancode Key code
def pressed( self, aScancode ):
if self._downs.get( aScancode, 0 ):
self._downs[aScancode] -= 1
return True
return False
 
 
## Base class from making scrollable pages.
class PageBuilder( object, appuifw.Canvas):
## Background color for the list
_iBackgroundColor = 0xffffff
## Default text font
_iDefaultFont = 'dense'
## Over sized image to be scrolled
_iOSImage = None
## Lines to print on the image
_iLines = None
## Line space
_iLineSpace = 13
## When True, elements are drawn
_iReady = False
## Scrollbar cursor outline color
_iScrollbarCursorOutlineColor = 0x0000ff
## Scrollbar cursor fill color
_iScrollbarCursorFillColor = 0xc3d9ff
## Scrollbar outline color
_iScrollbarOutlineColor = 0x000000
## Scrolling factor
_iYFactor = 0
## Text x origin in pixel
_iXText = 2
## Text x origin in pixel
_iYText = _iLineSpace
 
## The constructor
# @param self The object pointer
# @param aList List containing text to display
# @param aScrollY True by default; show the scrollbar or not
def __init__( self, aList, aScrollY=True ):
## If True, the scrollbar will be displayed
self._iScrollY = aScrollY
## Keyboard handler instance. self._eventCallback given will be called
# everytime a keyboard event will happen. That way it filters the
# useless events.
self._iKeyboard = Keyboard( self._eventCallback )
appuifw.Canvas.__init__( self,
self._redrawCallback,
self._iKeyboard.handle_event )
 
appuifw.app.body = self
self._formatData( aList )
self._createOversizedImage( )
self._iReady = True
 
## Displays the text on the application body
# @param self The object pointer
def show( self ):
appuifw.app.body = self
 
## Set new content for the text object
# @param self The object pointer
# @param aLong_str_array Array containing the long string to print
def set( self, aLong_str_array ):
self._formatData( aLong_str_array )
self._redrawCallback( )
 
## Key down, scrolls down
# @param self The object pointer
def _down( self ):
if ( ( self.size[1] ) + ( self._iYFactor + 1 ) * self._iLineSpace ) < \
( self._iOSImage.size[1] + self._iLineSpace ):
self._iYFactor += 1
self._redrawCallback( )
 
## Draw the image
# @param self The object pointer
def _drawImage( self ):
self.blit(self._iOSImage ,target=( 0,
-self._iYFactor * self._iLineSpace ) )
 
## Draw the scroll bar on the right
# @param self The object pointer
def _drawScrollbar( self ):
if self._iScrollY:
height = ( self._iOSImage.size[1] - self.size[1] ) / \
self._iLineSpace
if ( self._iOSImage.size[1] - self.size[1] ) % \
self._iLineSpace != 0:
height += 1
height += 1 # +1 ince we start counting from 0
height = self.size[1] / height
y = self._iYFactor * height
self.line( ( self.size[0] - 2, 0 ,self.size[0] - 2, self.size[1] ),
# vertical right side scroll bar
outline=self._iScrollbarOutlineColor )
self.rectangle( ( self.size[0] - 3, y, ( self.size[0] ), y + height ),
outline=self._iScrollbarCursorOutlineColor,
# scroll rectangle
fill=self._iScrollbarCursorFillColor)
## Event callback method for the canvas
# @param self The object pointer
def _eventCallback( self ):
if self._iKeyboard.pressed( EScancodeUpArrow ):
self._up( )
elif self._iKeyboard.pressed( EScancodeDownArrow ):
self._down( )
 
## Redraw callback method for teh canvas
# @param self The object pointer
# @param aRect Attribute value sent by the Canvas object
def _redrawCallback( self, aRect=None):
self.clear( self._iBackgroundColor )
if self._iReady:
self._drawImage()
self._drawScrollbar()
 
## Key up, scrolls up
# @param self The object pointer
def _up( self ):
if self._iYFactor > 0:
self._iYFactor -= 1
self._redrawCallback( )
 
 
## Generates array of line to be drawn
# @param self The object pointer
# @param aLong_str_array Array containing the long string to print
def _formatData(self, aLong_str_array):
temp = []
i = 0
for long_str in aLong_str_array:
# long_str is a long string to be wrapped
lines = wrap_text_to_array(long_str,
self._iDefaultFont,
self.size[0]-5)
for line in lines:
temp.append(line)
i += 1
# finally set the private lines variable
self._iLines = temp
 
## Create an oversized image
# @param self The object pointer
def _createOversizedImage( self ):
x, y = self._iXText, self._iYText
# calculate the height (head space + img height + 1 line + x line for
# the text)
height = y + ( len( self._iLines ) * self._iLineSpace ) + \
self._iLineSpace
# create the main image
self._iOSImage = Image.new( ( self.size[0], height ) )
# add the text on it
for line in self._iLines:
self._iOSImage.text( ( x, y ), line, font=self._iDefaultFont )
y += self._iLineSpace


Usage

# Create active object
SCRIPT_LOCK = e32.Ao_lock( )
 
def __exit__( ):
SCRIPT_LOCK.signal( )
 
appuifw.app.exit_key_handler = __exit__
appuifw.app.title= u'PageBuilder base class'
 
text = [u'iLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do' \
'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad' \
'minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex '\
'ea commodo consequat. Duis aute irure dolor in reprehenderit in '\
'voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur '\
'sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt '\
'mollit anim id est laborum.' ]
 
PageBuilder( text ).show( )
 
SCRIPT_LOCK.wait( )


PagerBuilder screenshot

Effective code re-use

It is now easy to create new pages styles without having to rewrite everything by inheriting the PageBuilder class.

In the example below a picture is added before the text.

With Python everything is virtual. The only methods we need to change are:

  • The constructor __init__
  • The method which creates the oversized image _createOversizedImage

So we just redefine (overwrite) them in ProductPage.

Source

## Topcenter image follwed by text decription.
class ProductPage( PageBuilder ):
_iXText = 2
_iYText = 5
_iImgWidth = 80
_iImgHeight = 60
## It can happen that no image are given for a product.
_iNoImageFill = 0xc0c0c0
## It can happen that no image are given for a product.
_iNoImageOutline = 0x000000
 
## The constructor
# @param self reference
# @param aImagePath Image path on the phone memory
# @param aList List containing text to display
# @param aScrollY True by default; show the scrollbar or not
def __init__( self, aText, aImagePath=None, aScrollY=True ):
self._iImagePath = aImagePath
PageBuilder.__init__( self, aText, aScrollY)
 
 
## Create an oversized image
# @param self The object pointer
def _createOversizedImage( self ):
x, y = self._iXText, self._iYText
# open first the imgage we want to display because we'll need its size
if self._iImagePath != None:
img = Image.open( self._iImagePath )
# calculate the height (head space + img height + 1 line +
# x line for the text)
height = y + img.size[1] + self._iLineSpace + ( len( self._iLines )\
* self._iLineSpace ) + self._iLineSpace
else:
height = y + self._iImgHeight + self._iLineSpace + \
( len( self._iLines ) * self._iLineSpace ) + \
self._iLineSpace
# create the main image
self._iOSImage = Image.new( ( self.size[0], height ) )
if self._iImagePath:
# blit product img
self._iOSImage.blit( img, target=( ( ( self._iOSImage.size[0] - \
img.size[0] ) / 2 ), y) )
y += img.size[1] + self._iLineSpace
else:
# print empty rectangle
self._iOSImage.rectangle( ( ( self.size[0] - self._iImgWidth ) / 2,\
y, ( ( self.size[0] - self._iImgWidth ) / 2)+ self._iImgWidth, \
y+self._iImgHeight ),
fill=self._iNoImageFill,
outline=self._iNoImageOutline )
 
y += self._iImgHeight + self._iLineSpace
 
# add the text on it
for line in self._iLines:
y += self._iLineSpace
self._iOSImage.text( ( x, y ), line, font=self._iDefaultFont )


Usage

SCRIPT_LOCK = e32.Ao_lock()
 
def __exit__( ):
SCRIPT_LOCK.signal( )
 
appuifw.app.exit_key_handler = __exit__
appuifw.app.title= u'PageBuilder: Image + Text'
 
text = [u'iLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do' \
'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad' \
'minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex '\
'ea commodo consequat. Duis aute irure dolor in reprehenderit in '\
'voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur '\
'sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt '\
'mollit anim id est laborum.' ]
 
imagePath = 'C:\\Images\\small.png'
 
ProductPage( text, imagePath ).show( )
 
SCRIPT_LOCK.wait( )
PagerBuilder image + text screenshot

Conclusion

This base class using oversized image can be re-used in a very efficient way to create rich content pages.

I'll let you know when I find a solution for big resolution screens.

This page was last modified on 31 May 2013, at 01:09.
58 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×