×

Discussion Board

Results 1 to 13 of 13
  1. #1
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21

    Painting problem

    Hi,

    I've got the next "really not cool" problem:

    I've got a Canvas that draws a "please wait" screen with a hourglass en bla bla bla..... It's animated by using a Thread that changes the state of the Canvas (just an int that's changed every interval)

    The Canvas is showed if data is send to the server. Sometimes a Form was first shown (optionForm) before the WaitCanvas is set as current screen and sometimes it is set as current after another Canvas was shown.

    My problem is that if the WaitCanvas is shown after a Form, an empty screen is showed (Command's are showed, but no graphics ) But if the WaitCanvas is showed after another Canvas it is showed!

    The following code always outputs: wait shown!
    Code:
    display.setCurrent(waitCanvas);
    if(waitCanvas.isShown()) System.out.println("wait shown");
    else System.out.println("wait is not shown");
    But when I place the following code in the paint method of the WaitCanvas it outputs NOTHING... because the paint method is never called (but the Thread calls the repaint method every interval (300 ms))

    Code:
    if(this.isShown()) System.out.println("painting showed");
    else System.out.println("painting unShowed");
    Can anybody enlighten me?
    Last edited by guidopater; 2003-05-30 at 11:29.

  2. #2
    Regular Contributor
    Join Date
    Mar 2003
    Location
    Canada
    Posts
    101
    Make sure that the thread that you're waiting on yields (e.g., using Thread.yield()) once in awhile so that the WaitCanvas.paint() method gets a chance to run.

  3. #3
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21

    Already tried that!

    Hey LiamQ,

    I already tried that... but this time I've tried it again but with a yield on every single line

    But I won't work! It so strange because when I'm trying it works when I switch from a Canvas to the WaitCanvas, but doesn't work from a Form to the WaitCanvas! I think this has something to do with this strange problem!

    But I'm surprised that nobody else had the same problem!

  4. #4
    Regular Contributor
    Join Date
    Mar 2003
    Posts
    393
    Please post your complete code.

    [N]/Forum Nokia

  5. #5
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21

    My code

    Oke I'm gonna try to post as much of the source as I can, because the project that I'm building may not be exposed

    But Oke here we go!

    First a short explanation.

    There are 4 classes involved!
    - The Connection Class, this is a class that runs as a Thread and can send information to a server by calling connection.send(String data);

    -The waitCanvas, is a Canvas that paints an image depending on a state (if state == 1 it paints the first image, if state == 2 it paints the second image, so on and so on). It has a engine to change the state.

    -The waitEngine, is a Thread that changes the state of the WaitCanvas on a given interval

    -The Mainclass, this is the class that is started and creates the other classes. When a user interacts with the UI and information has to be send.
    First the Mainclass will display the waitCanvas and next the Main class will create a String of data and calls connection.send(data); After the connection method has returned the response of the server and that response is processed the next Displayable will be showed.


    NOWWWWW..... The source

    Class ServerConnection
    Code:
    import javax.microedition.io.*;
    import java.io.*;
    import java.util.Vector;
    
    public class ServerConnection extends Thread {
      private HttpConnection connection = null;
      private Connector connector;
      private MainSystem system;
    
      private final String serverURL;
    
      public ServerConnection(MainSystem system, String serverURL) {
        this.system = system;
        this.serverURL = serverURL;
      }
     
      public synchronized String send(String data) {
        try {
          if(serverURL != null) {
            connection = (HttpConnection) Connector.open(serverURL);
            connection.setRequestMethod(HttpConnection.POST);
            OutputStream output = connection.openOutputStream();
    
            output.write(data.getBytes());
            output.flush();
            output.close();
    
            InputStream input = connection.openInputStream();
            int contentLength = (int)connection.getLength();
            if(contentLength < 1) contentLength = 4096;
            byte[] raw = new byte[contentLength];
            int length = input.read(raw);
    
            input.close();
            connection.close();
            input = null;
            output = null;
            connection = null;
            System.gc();
    
            String response = null;
    
            response = new String(raw,0 , length);
          }
        } catch (Exception ex) { system.log("send error :"+ex+" -> "+data); ex.printStackTrace();}
        return "";
      }
    
      public void destroy() {
        connection = null;
        connector = null;
        system = null;
      }
    }
    Class WaitCanvas
    Code:
    import javax.microedition.lcdui.*;
    import java.io.IOException;
    
    public class WaitCanvas extends Canvas{
      private Display display;
      private WaitEngine engine;
      private Image virtualScreen;
      private Graphics drawGraphics;
    
      private int screenWidth = 0;
      private int screenHeight = 0;
    
      private int state = 0;
      private int maxState = 4;
      private final String headerText = "Busy";
      private String message = "";
    
      private MainSystem system;
      private StyleSheet styleSheet;
    
      // used for the animation
      private Image[] ani;
      private int aniIndex = 0;
    
      public WaitCanvas(MainSystem system) {
        this.system = system;
        this.display = system.display;
        
        // create the engine with a interval of 300 ms
        engine = new WaitEngine(this,300);
        
        screenWidth = getWidth();
        screenHeight = getHeight();
        virtualScreen = Image.createImage(screenWidth,screenHeight);
        drawGraphics = virtualScreen.getGraphics();
    
        ani = new Image[8];
        for(int i = 0; i < 8; i++) {
          try {
            ani[i] = Util.createImage("/hourglass/"+(i+1)+".png");
          } catch (IOException ex) { system.log("Hourglass ani problem("+(i+1)+"): "+ex.toString());}
        }
        
        // start the engine
        engine.start();
      }
    
      public synchronized void setMessage(String message){
        state = 0;
        this.message = message;
        repaint();
      }
    
    
      public void paint(Graphics g) {
        drawGraphics.setColor(255,255,255);
        drawGraphics.fillRect(0,0,screenWidth, screenHeight);
    
        drawGraphics.drawImage(ani[aniIndex],Util.div(screenWidth,2)-Util.div(ani[aniIndex].getWidth(),2),Util.div(screenHeight,2)-Util.div(ani[aniIndex].getHeight(),2),0);
        if(++aniIndex >= ani.length) aniIndex = 0;
    
        int headerX = 5;
        int headerY = 5;
        int messageX = 5;
        int messageY = screenHeight - fontMessage.getHeight() - 5;
    
        drawGraphics.setColor(0,0,0);
    
        drawGraphics.drawString(headerText, headerX, headerY, 0);
        String points = "";
    
        // HERE STATE IS USED TO DETERMINE HOW MANY POINTS AFTER BUSY THERE WILL BE.
        for(int i = 0; i < state; i++) points += ".";
        drawGraphics.drawString(points, headerX+fontHeader.stringWidth(headerText)+1, headerY, 0);
    
        drawGraphics.setColor(0,0,0);
        drawGraphics.drawString(message, messageX, messageY, 0);
        g.drawImage(virtualScreen, 0, 0, 0);
      }
    
      public void showNotify() { repaint(); }
    
      public synchronized void setState(int state) {  this.state = state; }
    
      public synchronized int getState() { return state; }
    
      public synchronized int getMaxState() { return maxState; }
    
      public void suspend() { engine.suspend(); }
    
      public void resume() { engine.resume(); }
    
      public void stop() { engine.stop(); }
    
      public void destroy() {
        engine.stop();
        engine.destroy();
        engine = null;
        display = null;
        virtualScreen = null;
        drawGraphics = null;
        system = null;
      }
    }

    Class WaitEngine
    Code:
    public class WaitEngine extends Thread {
      private WaitCanvas waitCanvas;
      private int interval;
    
      private boolean running = true;
      private boolean suspending = false;
      private Object o = new Object();
    
      public WaitEngine(WaitCanvas waitCanvas, int interval) {
        this.waitCanvas = waitCanvas;
        this.interval = interval;
      }
    
      public void run() {
        while (running) {
          if (suspending) {
            try {
              synchronized (o) { o.wait(); }
            } catch (InterruptedException ie) { }
          } else {
            try {
              try { Thread.sleep(interval); } catch (InterruptedException ex) {}
              
              // CHANGE THE STATE
              int state = waitCanvas.getState()+1;
              if(state >= waitCanvas.getMaxState()) waitCanvas.setState(0);
              else waitCanvas.setState(state);
              waitCanvas.repaint();
            } catch(NullPointerException ex) {}
          }
        }
      }
    
      public void suspend() { suspending = true; }
    
      public void resume() { suspending = false; synchronized (o) { o.notify(); }}
    
      public void stop() { running = false; }
    
      public void destroy() { o = null; waitCanvas = null; }
    }
    Class MainSystem
    Code:
    import javax.microedition.lcdui.Display;
    import javax.microedition.lcdui.Displayable;
    import javax.microedition.lcdui.Command;
    import javax.microedition.lcdui.CommandListener;
    
    public class MainSystem extends MIDlet implements CommandListener {
      protected static final int STATUS_OK = 0;
      protected static final int STATUS_ERROR = 1;
      protected static final int STATUS_UNKNOWN = 2;
    
      private Displayable lastView = null;
      private Displayable lastViewLog = null;
      Display display;
    
      private ServerConnection connection;
    
      private SigninForm signinForm;
      private WaitCanvas waitCanvas;
    
      //command
      private Command okCommand = new Command("Login", Command.SCREEN, 1);
    
      public MainSystem() {
        display = Display.getDisplay(this);
    
        signinForm = new SigninForm();
        signinForm.addCommand(okCommand);
        signinForm.setCommandListener(this);
    
        waitCanvas = new WaitCanvas(this);
        waitCanvas.addCommand(cancelCommand);
        waitCanvas.setCommandListener(this);
        
        connection = new ServerConnection(this,"http://localhost:5555");
        connection.start();
      }
    
      public void startApp() throws MIDletStateChangeException {
        display.setCurrent(signinForm);
      }
    
      public void destroyApp(boolean unconditional) throws MIDletStateChangeException {
        destroy();
      }
    
      private void startWaiting(String text) {
        waitCanvas.setMessage(text);
        display.setCurrent(waitCanvas);
      }
    
      public void commandAction(Command c, Displayable s) {
        if(s == signinForm) {
          if(c == okCommand) {
            startWaiting("Signin in");
            String username = signinForm.getUsername();
            String password = signinForm.getPassword();
            String response = connection.send("fake_data:username>password");
            process(response);
            display.setCurrent(signinForm);
          }
        }
      }
    
      public void process(String data) {
        // do something with the data;
      }
    
      public void destroy() {}
    }


    So that's it! I must note that is not the actual code, but a rip off... but the essential things of my problem are all included!

    In short my problem is that the WaitCanvas is not shown while sending en getting data... BUT if the Canvas before the WaitCanvas was a Canvas it will be shown! (Strange isn't it)

    p.s. I had to exclude my JavaDOC due to a maxlength problem (10000 chars)

  6. #6
    Registered User
    Join Date
    Mar 2003
    Location
    Copenhagen, Denmark
    Posts
    18
    Hello Guidopater,

    Been there too

    Please note, that whetever you perform during event dispatching (e.g in the commandAction() method, or keyPressed() method) is performed by the event mechanism (apparently a single thread) which also carries out painting.

    This means that while you use the event thread to perform network operations and other stuff, it simply cannot also repaint the display at the same time.. What you need to do is to have another thread performing your user input response, and leave the event thread to it's repainting duties right away.

    That should solve the problem.

  7. #7
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21

    ???

    Oke I understand your story... almost

    How would that appear in code... like a new class extends thread that only handles input?

    Can you give me a short code example, please!

    (Would making my MainSystem a Thread do the trick?)

    Thenx in advance
    Last edited by guidopater; 2003-06-11 at 11:20.

  8. #8
    Registered User
    Join Date
    Mar 2003
    Location
    Copenhagen, Denmark
    Posts
    18
    Hi again,

    Not necessarily a new class. Your main class can implement Runnable and control this behaviour from its run method.

    I suggest that you start your thread during midlet initialization, and let it live for as long time as you need to respond to user input.

    it could look like:


    public static final int EVENT_INPUTFORM_OK = 0;
    public static final int EVENT_INPUTFORM_CANCEL = 1;
    .........

    private int currentEvent;
    private boolean keepWaitingForInput = true;

    public void run(){

    while(keepWaitingForInput){
    synchronized(this){
    wait();
    }

    //-> An event was dispatched.
    switch(currentEvent){
    case EVENT_INPUTFORM_OK:
    // Do network stuff
    break;

    case EVENT_INPUTFORM_CANCEL:
    // whatever to do.
    break;
    }
    }

    }

    public void commandAction(Command c, Displayable s) {
    if(s == signinForm) {
    if(c == okCommand) {
    // Set the event to be peformed.
    currentEvent = EVENT_INPUTFORM_OK;
    }
    }

    // Wake up the thread to perform the event.
    synchronized(this){
    notify();
    }
    }


    Maybe you should exand the synchronized block to ensure that the currentEvent is not being reset by a new event, before the other thread has reacted to this event.

    It works for me! Hope it'll solve your problem too.
    Last edited by schm1; 2003-06-11 at 15:05.

  9. #9
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21
    Currently I'm ticking like a somebody almost losing his job

    So in about, 30 minutes (debugging) I'm gonna know if it works what I did, and if not: I'm just gonna try what you describe above!


    Thenx

  10. #10
    Registered User
    Join Date
    Mar 2003
    Location
    Copenhagen, Denmark
    Posts
    18
    I'm sorry I posted half an answer by an accident. You might wanna read my previous post again for a more complete example.

  11. #11
    Registered User
    Join Date
    Mar 2003
    Location
    Maastricht, The Netherlands
    Posts
    21
    OOOOOOOOOwwwwwwwwww wYEEAAAAAAAAAAAAAHHHHHHH

    After 3 weeks of dipping, I've done it.... it works!!!!!????? (with a lot of help of schm1)

    YOEEEEEHOOOOOOEEEEEEEEEEEEEEE

    schm1 I want to thank you for your knowledge and your quick replies

    me very happy

  12. #12
    Registered User
    Join Date
    Mar 2003
    Location
    Copenhagen, Denmark
    Posts
    18
    I'm glad you got it to work! Cheers :-)

  13. #13
    Regular Contributor
    Join Date
    Mar 2003
    Posts
    393

    Managing Fast repaints

    Have a look at this as well...

    http://discussion.forum.nokia.com/fo...=%2Acounter%2A

    [N]/Forum Nokia

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •