Thursday, February 28, 2008

Windows Mobile UI: How to change device's display orientation


Share

In this post I describe the problem when changing the screen orientation, well 2 problems and at the end the final solution for changing the screen orientation. if you just want to read about the solution, scroll down...

In order to learn how to rotate the screen orientation I watched a MSDN How To Video, which helped but didn't give me the right solution (hence this post :) )

By the video, in order to change the screen orientation you would write this line:

SystemSettings.ScreenOrientation = ScreenOrientation.Angle270;


This line does change the screen orientation, the problem occurs if you also want to  monitor the screen orientation change. (see How to Monitor screen orientation change) In my case I wanted my application to always be in landscape mode, meaning that in case of a screen rotation to portrait mode, I will rotate the screen back to landscape mode.



I used the SystemState change event to monitor the change and used



SystemSettings.ScreenOrientation = ScreenOrientation.Angle270;



To change the orientation back to landscape.  The screen orientation indeed changed, but after this change the SystemState change event didn't always fire, hence in some cases my application was displayed in portrait mode. the reason for this was that the SystemState.DisplayRotation didn't change. problem...



I thought about using the resize event, and changing the SystemSettings.ScreenOrientation.. but I got an exception.  the reason for the exception was that when being in the Resize function, I changed the SystemSettings.ScreenOrientation, making another call to the Resize function...



I found that other developers had the same problem, and saw 2 solutions, the first is to catch the exception and display to the user a message indication that the application dose not supports this mode, and the second was to use a timer (of 200 ms) inside the Resize(), that will change the orientation. I didn't like both solutions... so I found a third one... :)



my solution:



I wanted to use the SystemState change event, since its much more efficient than the Resize event. I understood that I need to change the SystemState.DisplayRotation, but its read only...



Since the SystemState.DisplayRotation is read from the registry... I was to write the value to the registry causing it to change and hence the SystemState change event will always fire :)



problem solved!



note that SystemSettings.ScreenOrientation still needs to be changed, since its the parameter that decides the display orientation.



the code:



void OrientationWatcher_Changed(object sender, ChangeEventArgs args)
{
int newOrientation = (int)args.NewValue;
if (condition on newOrientation)
ChangeToLandscape();

}
public static void ChangeToLandscape()
{
SystemSettings.ScreenOrientation = ScreenOrientation.Angle270;
Registry.SetValue(@"HKEY_LOCAL_MACHINE\System\GDI\ROTATION",
"Angle", 270, RegistryValueKind.DWord);
}

Continue Reading...

Windows Mobile UI: How to monitor the device's screen orientation


Share
getting screen orientation:

There are two members that indicate the screen orientation mode (Landscape or portrait)

SystemState.DisplayRotation



SystemSettings.ScreenOrientation


Note: these 2 members may not always be the same. Ill will discuss this issue in my next post




Monitoring screen orientation


When the screen orientation changes we have 2 ways to know about it:



System state change event



When the SystemState.DisplayRotation is changed, an event is fired. We can catch it and use it:



Creating the event:



private SystemState _orientationWatcher;
_orientationWatcher = new
SystemState(SystemProperty.DisplayRotation);
_orientationWatcher.Changed += new
ChangeEventHandler(OrientationWatcher_Changed);



Below is the function that "does something" when there is an orientation change. you should make sure to use the new orientation value from the args param and not get it from the System state since its read from the registry.



void OrientationWatcher_Changed(object sender, ChangeEventArgs args)
{
int newOrientation = (int)args.NewValue; // new orientation
//do what you want to do when there is a orientation change
}


resize event



You can use the control's  resize event and check if the screens orientation was changed. you can use the SystemState or SystemSettings parameters.



The problem with this is that the resize event is called allot of times: its called around 4 times each time you display a screen, create a screen,  and resize the screen - i.e. change the screen's orientation.



Hence I don't recommend using it for monitoring the rotation change.



 



 



 



 

Continue Reading...

Tuesday, February 26, 2008

J2ME UI: Text wrapping on Canvas


Share

The drawString() method that is used to write text on the canvas dose not know how to wrap the text, hence,  when using it and writing a long text, only one line will appear and the text will be cut.

In order to have the text written correctly, there is a need to implement a text wrap.

The below function writes the given 'txt' on the canvas's Graphics 'g', starting from 'x' and 'y' coordinates, using the given 'font'. the area in which the text should be written is 'width' and the text is written by the 'alignment' . using the alignment you can write text from left to right or from right to left

The function returns the next y coordinate on the canvas, which is the next location for a text to be written. this is good for cases that you want to continue writing on the canvas but with a different font or color.

public int write(Graphics g, String txt, int x, int y,
int width, Font font,
int alignment ){
m_font = font;
m_txt = txt;
m_length = txt.length();
m_width = width;
//reseting
m_position =0;
m_start = 0;

int fontHight = m_font.getHeight() + 1;
String s;
g.setFont(m_font);
while(hasMoreLines()){
s = nextLine().trim();
g.drawString(s, x, y, Graphics.TOP|alignment );
y += fontHight;
}
return y;
}


below is the implementation  for the  "helper" functions


private boolean hasMoreLines(){
return (m_position<(m_length-1));
}


private String nextLine(){
int maxLength = m_txt.length();
int next = next();
if(m_start>=maxLength || next>maxLength)
return null;
String s =m_txt.substring(m_start, next);
m_start = next;
if((m_txt.length()-1>m_start )&& ((m_txt.charAt(m_start)=='\n') ||
(m_txt.charAt(m_start)==' '))){
m_position++;
m_start++;
}
return s;
}




private int next(){
int i=getNextWord(m_position);
int lastBreak = -1;
String line;
line= m_txt.substring(m_position, i);
int lineWidth = m_font.stringWidth(line);
while (i<m_length && lineWidth<= m_width){
if(m_txt.charAt(i)==' ' )
lastBreak = i;
else if(m_txt.charAt(i)== '\n'){
lastBreak =i;
break;
}
if(++i<m_length){
i= getNextWord(i);
line = m_txt.substring(m_position, i);
lineWidth = m_font.stringWidth(line);
}
}
if(i==m_length && lineWidth<= m_width)
m_position = i;
else if(lastBreak == m_position)
m_position++;
else if(lastBreak < m_position)
m_position =i;
else
m_position = lastBreak;
return m_position;
}


private int getNextWord(int startIndex){
int space = m_txt.indexOf(' ', startIndex);
int newLine = m_txt.indexOf('\n', startIndex);
if(space ==-1)
space = m_length;
if(newLine ==-1)
newLine = m_length;
if(space<newLine)
return space;
else
return newLine;
}

Continue Reading...

Sunday, February 3, 2008

J2ME UI: Implementing a Progress Bar


Share

first we create the Progress Bar object, the is is the simple part :)

public class Gauge {


    


    private int m_x, m_y, m_hight, m_width, m_Progress;


    


    public void set(int x, int y, int height, int width ) {


        m_x = x;


        m_y = y;


        m_height = height;


        m_width = width;


    }


    


    public void  setProgress(int progress){


     m_progress= progress;


    }


    


    public void paint(Graphics g){


        if(m_progress>=m_width)


            return;


        g.setColor(0);


        g.drawRect(m_x, m_y-1, m_width, m_height+1);


        


        g.setColor(GuiConstants.JAJAH_COLOR);


        g.fillRect(m_x+1, m_y, m_Progress, m_height);


        g.setColor(GuiConstants.LIST_BACK_COLOR);


        if(m_width-m_Progress>0)


            g.fillRect(m_Progress + m_x, m_y, m_width-m_Progress, m_height);


    }




now we need to use it:



in order to display the Progress Bar, we will display it using a canvas. the canvas will hold a Progress Bar as a member, and it will display it. on that canvas more info can be displayed. note that on each progress update  a repaint occurs. its sufficient to only repaint the progress bar or any updated UI.





public void run() {


        try{


            init();// init params


            m_paintSuper = true;


            repaint();


            boolean run = !connection.callAllowed();// condition for running the bar


            while(run){


                for(int i= 1;i<m_gauge.getWidth()&& run;i++){


                    m_gauge.setProgress(i);


                    Thread.sleep(GAUGE_SPEED); // to make gauge slower


                    repaint();


                    run = !connection.callAllowed();


                }


            }


        }


        catch (Exception e) {


            run();


        }


    }


    


    protected void paint(Graphics g) {


          // things that need to painted only once


          if(m_paintSuper){ 


            super.paint(g);


          }


           m_paintSuper = false;


        }


            


        m_gauge.paint(g);


    }


    




now that we have the canvas ready with the Progress bar and the update of the progress we are left to display the canvas





if(m_gauge == null)


     m_gauge = new GaugeView(null);


// sets the text for the canvas or any other thing to the canvas


m_Gauge.setText(str);         


Display.getDisplay(m_midlet).setCurrent(m_gauge);


Thread t = new Thread(m_gauge);


t.start();


Continue Reading...
 

Blogroll

Site Info

Text