Доброго времени суток!
На дворе уже четвёртое января, а моя душа всё не успокаивается. Поэтому я решил продолжить тему написания J2ME приложений. Плюс ко всему, несколько человек проявили нешуточный интерес к данной теме. Причём это были не только рядовые пользователи хабра, но и read-only аккаунты. Ну да ладно, ближе к теме.
Буквально сразу же после публикации топика, были получены очень дельные комментарии от хабраюзера barker, а именно замечание, по сути являющееся прописной истиной и второй комментарий — поправка, не менее дельная.
Сегодня мы с вами поговорим о самом процессе двойной буферизации в javax.microedition.lcdui.Canvas и о том, почему же был создан javax.microedition.lcdui.game.GameCanvas.
Двойная буферизация является ничем иным, как техникой, которой предусматривается использование второго (внеэкранного) буфера для отрисовки фигур, спрайтов и так далее в него, с последующим копированием его содержания в экранный. Проблема в том, что при рисовании напрямую, т.е. рисование непосредственно в экранный буфер по времени не укладывается в промежуток времени перерисовки экрана (в Canvas это осуществляется функцией repaint()) и экран попросту начинает «мигать», т.е. пользователь видит перед собой промежуточный результат этого самого рисования. Использование этой самой технике позволяет разработчику избегать этих «миганий». Тем не менее, в Canvas использование этой техники является процессом велосипедостроения, т.к. разработчики стандарта и платформы J2ME не позаботились об этом.
Процесс «двойной буферизации» в Canvas проходит с помощью использования изображения (объекта Image пакета javax.microedition.lcdui), в качестве внеэкранного буфера. Вот так:
Вот и всё. Код содержит более чем наглядные комментарии, так что разбор кода не должен вызвать у вас проблем. Теперь рассмотрим «двойную буферизацию» в GameCanvas.
Прошло некоторое время и J2ME консорциумом был разработан пакет javax.microedition.lcdui.game, в котором содержался GameCanvas, который представлял собой всё тот же Canvas, но уже с решённой проблемой «двойной буферизации». Программистам теперь не нужно о ней заботиться. Код же будет выглядеть следующим образом:
Тут нам не нужно заботиться о буфере — всё сразу рисуется в него, а затем при вызове flushGraphics всё содержимое внеэкранного буфера копируется в экранный.
Несмотря на то, что данная задача отрисовки решается в несколько строк — это достаточно важная тема, в которой разработчикам нельзя «плавать». Надеюсь, сегодняшний урок был не менее поучительным, чем прошлый. На этом всё, разрешите откланяться.
До скорых встреч!
Исходники по сложившейся традиции вы можете забрать на Pastebin.
Здесь — первый пример.
И здесь — второй.
Введение
На дворе уже четвёртое января, а моя душа всё не успокаивается. Поэтому я решил продолжить тему написания J2ME приложений. Плюс ко всему, несколько человек проявили нешуточный интерес к данной теме. Причём это были не только рядовые пользователи хабра, но и read-only аккаунты. Ну да ладно, ближе к теме.
Буквально сразу же после публикации топика, были получены очень дельные комментарии от хабраюзера barker, а именно замечание, по сути являющееся прописной истиной и второй комментарий — поправка, не менее дельная.
О чём мы поговорим сегодня
Сегодня мы с вами поговорим о самом процессе двойной буферизации в javax.microedition.lcdui.Canvas и о том, почему же был создан javax.microedition.lcdui.game.GameCanvas.
Что такое «двойная буферизация»
Двойная буферизация является ничем иным, как техникой, которой предусматривается использование второго (внеэкранного) буфера для отрисовки фигур, спрайтов и так далее в него, с последующим копированием его содержания в экранный. Проблема в том, что при рисовании напрямую, т.е. рисование непосредственно в экранный буфер по времени не укладывается в промежуток времени перерисовки экрана (в Canvas это осуществляется функцией repaint()) и экран попросту начинает «мигать», т.е. пользователь видит перед собой промежуточный результат этого самого рисования. Использование этой самой технике позволяет разработчику избегать этих «миганий». Тем не менее, в Canvas использование этой техники является процессом велосипедостроения, т.к. разработчики стандарта и платформы J2ME не позаботились об этом.
«Двойная буферизация» в Canvas
Процесс «двойной буферизации» в Canvas проходит с помощью использования изображения (объекта Image пакета javax.microedition.lcdui), в качестве внеэкранного буфера. Вот так:
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics; /* импортируем необходимые для работы библиотеки */
import javax.microedition.lcdui.Image;
public class OurCanvas extends Canvas {
Image img; // наш Image
Graphics buf; // вот он, буфер
int w; // высота экрана
int h; // его ширина
public OurCanvas() { // конструктор Lego
w = getWidth(); // узнаём высоту экрана
h = getHeight(); // ширину
// сначала проверяем, поддерживается ли "двойная буферизация" самим устройством
// если да, то и заботится о создании второго буфера нам не нужно
// если же нет, то создаём Image
if (!isDoubleBuffered()) {
buffer = Image.createImage(w,h);
}
// получаем возможность отрисовки в img
buf = img.getGraphics();
}
// рисуем в наш буфер
public void draw(Graphics g) {
g.setColor(0xffffff);
g.fillRect(0,0,w,h);
g.setColor(0x111111);
g.fillRect(25,25,125,125);
g.setColor(0xababab);
g.fillRect(70,60,70,60);
}
public void paint(Graphics g) {
g.drawImage(0,0,w,h); // рисуем сам буфер
draw(buf); // рисуем в буфер
}
}
Вот и всё. Код содержит более чем наглядные комментарии, так что разбор кода не должен вызвать у вас проблем. Теперь рассмотрим «двойную буферизацию» в GameCanvas.
«Двойная буферизация» в GameCanvas
Прошло некоторое время и J2ME консорциумом был разработан пакет javax.microedition.lcdui.game, в котором содержался GameCanvas, который представлял собой всё тот же Canvas, но уже с решённой проблемой «двойной буферизации». Программистам теперь не нужно о ней заботиться. Код же будет выглядеть следующим образом:
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.Graphics; /* импортируем необходимые для работы библиотеки */
import javax.microedition.lcdui.Image;
public class OurCanvas extends GameCanvas implements Runnable {
Graphics buf;
Thread t;
int w; // высота экрана
int h; // его ширина
public OurCanvas() { // конструктор нашего OurCanvas
w = getWidth(); // узнаём высоту экрана
h = getHeight(); // ширину
// получаем ссылку на объект Graphics
buf = getGraphics();
// наша нить
t = new Thread(this);
}
// let's draw
public void run {
g.setColor(0xffffff);
g.fillRect(0,0,w,h);
g.setColor(0x111111);
g.fillRect(25,25,125,125);
g.setColor(0xababab);
g.fillRect(70,60,70,60);
flushGraphics(); // вот и вся наша "двойная буферизация"
}
}
Тут нам не нужно заботиться о буфере — всё сразу рисуется в него, а затем при вызове flushGraphics всё содержимое внеэкранного буфера копируется в экранный.
На этом всё
Несмотря на то, что данная задача отрисовки решается в несколько строк — это достаточно важная тема, в которой разработчикам нельзя «плавать». Надеюсь, сегодняшний урок был не менее поучительным, чем прошлый. На этом всё, разрешите откланяться.
До скорых встреч!
Пейте кофе, пишите на Java.
Post Scriptum
Исходники по сложившейся традиции вы можете забрать на Pastebin.
Здесь — первый пример.
И здесь — второй.