Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java ME (J2ME) > Два метода paint


Автор: GavriKos 24.8.2008, 16:08
Доброго времени суток! Немного запутался в одной вещи, помогите разобраться.

Есть главный клас мидлета. В нем есть метод paint, который вызывается каждые 10 милисекунд (при помощи треда). Есть второй класс, в котором тоже есть метод paint. Суть в том, что при определенном событии метод paint второго класса должен вызываться определенное количество раз с задержкой 10 милисекунд. 

Я решил эту проблемму так - в первом классе в методе paint поставил счетчик, который каждый раз нарасщивается и при этом вызывается paint второго класса. Когда счетчик достигнет нужной величины - он нулится и paint из второго класса не вызывается:

Код

        if (flagDestroyStone==true)
        {
            if (calcFrames!=16) {exploided.paint(g); calcFrames++;}
            else {calcFrames=0;flagDestroyStone=false;}            
        }


В принципе все работает, но вот хотелось бы перенести эту всю конструкцию во второй класс, чтоб в первом можно было запустить отрисовку второго класса одним методом. Пробовал через потоки, но сразу потерпел неудачу - если событие приходит второй раз (т.е. второй раз должен запустится цикл отрисовки), то вылетает ексепшн мол поток уже запущен, второй раз не запустится. Пробовал что то вроде такого:

Код

s.paint(g);
         s.nextFrame();
         try{
         wait(10);
         } catch (InterruptedException ie) {}
         paint(g);


Но каждый раз при входе в paint вызывался какой-то ексепшн (конкретно - IllegalMonitorStateException). Подскажите, как лучше поступить, в каком направлении копать?

Автор: Antropoid 25.8.2008, 09:56
wait(10); нужно помещать в synchronized блок, или метод paint(), в котором это присутствует делать synchronized

Автор: GavriKos 25.8.2008, 15:07
Спасибо, вечером попробую.

Автор: GavriKos 26.8.2008, 10:18
В общем на wait больше не ругается, но от этого не легче. Написал вот такой код:

Код

    public synchronized void paint(Graphics g)
    {    if (bufFrame!=16)
         {
         s.paint(g);
         s.nextFrame();
         
         try{
         wait(50);
         } catch (InterruptedException ie) {}
         bufFrame++;
         paint(g);
         }
         else bufFrame=0;
    }


При вызове этого пеинта намертво замораживается все приложение на 50мс. Пробовал поставить в главном классе где-нибудь synhronized (в run,  в paint) - не помогло.

Автор: W0LF 27.8.2008, 11:31
а в каком потоке вызывается paint()? в главном? дай больше кода, покажи где вызывается paint? 

Автор: GavriKos 27.8.2008, 18:02
paint второго метода вызывается в общем потоке. Код дать не могу, его много чистить долго. 

Автор: Dummy 27.8.2008, 21:02
Цитата(GavriKos @  26.8.2008,  10:18 Найти цитируемый пост)
При вызове этого пеинта намертво замораживается все приложение на 50мс

А что, ожидалась какая-то другая реакция при заморозке рабочего потока на 50 мс?smile 

Автор: GavriKos 29.8.2008, 15:19
Стоп. wait замораживает выполнение текущего потока, даже если находится в другом классе и т.д? А как тогда решить этот вопрос? Вынести в отдельный поток второй класс?

Автор: W0LF 29.8.2008, 15:42
хм. ты не путай потоки и классы
конечно все надо выносить из главного треда

Автор: GavriKos 30.8.2008, 20:23
Вынес весь класс в отдельный поток. Получилось вот что:


Код

    public void paint(Graphics g)
    { 
        System.out.println("!!!ENTER PAINT!!!");
        s.paint(g);
    }
    
    public void run()
    {
        repaint();
        try{
        Thread.sleep(10);
        } catch (InterruptedException ie) {}
        run();
    }


Поток, естественно, запускаю (он запускается 100%, проверял). Вот только почему то в метод paint приложение не заходит. Пробовал this.paint - эффект тот же. Пробовал вместо repaint писать paint, в который Graphics передавал из главного класса - в метод тогда заходит, но ничего не рисует. Ткните носом. где ошибка. Или скажите хотя б, куда копать?

Автор: Antropoid 30.8.2008, 21:36
Рискну угадать  smile 
что делать нужно так:
Код

class YourClass extends Canvas implements Runnable {
...
}

Автор: GavriKos 31.8.2008, 13:04
Блин понятное дело что это сделано smile Так что не угадал. Вот полностью код класса, там правда может что то лишнее - чистить долго...

Код

public class SpritePlayer extends Canvas implements Runnable
{
    Sprite s;
    Image i; 
    int animDelay;
    int playType;
    //Graphics G;
    int bufFrame;
    
    boolean flagStop=false;
    
    public final int PLAY_TYPE_ONCE=1;
    public final int PLAY_TYPE_CIRCLE=2;
    Thread th;
    public SpritePlayer(String ResourseName,int FrameRate,int posX,int posY)
    {
        bufFrame=0;
        try{
            i = Image.createImage(ResourseName);            
        } catch (IOException ioe) {System.out.println("error");}  
        s = new Sprite(i, i.getWidth()/FrameRate, i.getHeight());
        s.setRefPixelPosition(posY, posY);
        th = new Thread(this);
        th.start(); 
    }
    
    public void paint(Graphics g)
    { 
        System.out.println("!!!ENTER PAINT!!!");
        s.paint(g);
    }
    
    public void run()
    {
        repaint();
        try{
        Thread.sleep(10);
        } catch (InterruptedException ie) {}
        run();
    }
    
    public void start()
    {    
           
       //th.notify();
        
        //paint(g);           
    }
}

Автор: GavriKos 31.8.2008, 13:57
поправка - этод код один раз заходит в paint.

Добавлено через 2 минуты и 34 секунды
только вот не из-за repaint  в run...

Автор: Dummy 31.8.2008, 16:22
Вызов repaint() для канвы не означает моментального вызова paint() - это только постановка запроса на перерисовку в общую очередь графической системы. Через какое время после вызова repaint() будет вызван paint() - точно угадать не возможно. Чтобы заставить графическую систему JVM немедленно обслужить все возможные repaint()'ы, нужно вызвать Canvas.serviceRepaints()

Автор: Antropoid 31.8.2008, 16:28
If the canvas is not visible, or if width and height are zero or less, or if the rectangle does not specify a visible region of the display, this call has no effect.
SpritePlayer должен быть на экране
Код

Display.getDisplay(YourMidletClass.getInstance()).setCurrent(new SpritePlayer()); 


Добавлено через 3 минуты и 28 секунд
Dummy, ему это не поможет, ибо
If there are no pending repaints, or if this canvas is not visible on the display, this call does nothing and returns immediately.

Автор: Dummy 31.8.2008, 22:28
GavriKos, так ты вызываешь Display.setCurrent() для SpritePlayer? Ответь, пж, иначе коллектив теряется в догадках smile 

И еще - чего это у тебя в методе run() бесконечная рекурсия? Ты так StackOverflowError схлопочешь. Замени рекурсию циклом.


Автор: GavriKos 1.9.2008, 10:56
Заменил уже давно. SetCurent делаю. При этом код второго класса уже вот такой:

Код

    public void paint(Graphics g)
    { 
        System.out.println("!!!ENTER PAINT!!!");
        s.paint(g);
        s.nextFrame();        
    }
    
    public void run()
    {
        System.out.println("!!!ENTER RUN!!!");
        while (true)
        {        
            repaint();
        try{
        Thread.sleep(100);
        } catch (InterruptedException ie) {}
        }        
    }


На оутпуте получаем 1 раз ENTER RUN и один раз ENTER PAINT. sleep ексепшн не выбивает - проверил.

Автор: Antropoid 1.9.2008, 14:18
Слушай, GavriKos, думаю в твоих же интересах написать мини приложение с классом-мидлета и твоим примером, и показать, что он действительно не вызывается, потому что у меня все работает.

Автор: GavriKos 1.9.2008, 14:39
Т.е. у тебя при запуске этого потока paint вызывается больше одного раза? Ладно, будем искать (с)

Автор: Antropoid 1.9.2008, 15:00
Цитата(GavriKos @  1.9.2008,  14:39 Найти цитируемый пост)
Т.е. у тебя при запуске этого потока paint вызывается больше одного раза?

ДА

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)