Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Помогите разобраться с двойной буферизацией 
V
    Опции темы
SplinterL
Дата 29.6.2006, 20:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 29.6.2006

Репутация: нет
Всего: нет



Делаю программу, которая должна отрисовывать графику на отдельной панели в том же окне , что и основная программа. При перетаскивании этой графики мышкой, она не должна мерцать. Для этого я использовал двойную буферизацию. Делал, так как описано в книге по Java, но во-первых изображение все равно мерцает, а во-вторых на панели где должна отрисовываться графика, рисуется еще и весь интерфейс программы: все  кнопки и текстовые поля. Подскажите где я допускаю ошибку в коде и как правильно реализовывать двойную буферизацию в GUI приложениях? smile 

Surface - панель где рисуется графика. 

Вставляется в основную программу так:
Код


Surface s =new Surface();

    private void initComponents() {
jPanel3.add("Center",s);
}



Код класса Surface:
Код


import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.*;
import java.applet.*;
import javax.swing.*;

public class Surface extends JPanel{
    Canvas c;
    int w,h,mx,my;
    Image buf=null;
    boolean first=true;
    
    public Surface(){
        c=new Canvas();
        this.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e){
                mx=e.getX();
                my=e.getY();
                repaint();
            }
        });
        this.setForeground(Color.black);
        this.setBackground(Color.white);
        repaint();
        
        
    }
    
    public void paint(Graphics g){
        Graphics g2;
        if (first==true){
            w = getSize().width;
            h = getSize().height;
            buf=createImage(w,h);
            first=false;
        }
        g2=g;
        g=buf.getGraphics();
        
        for(int i=0; i<w; i+=3) g.drawLine(i,0,w-i,h);
        for(int i=0; i<h; i+=3) g.drawLine(0,i,w,h-i);
        g2.drawImage(buf,mx,my,null);
    }
    
    public void update(Graphics g){
        paint(g);
    }
    
  
    }
}
 
PM MAIL ICQ   Вверх
powerOn
Дата 29.6.2006, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 31
Всего: 159



Цитата(SplinterL @  29.6.2006,  21:19 Найти цитируемый пост)
на панели где должна отрисовываться графика, рисуется еще и весь интерфейс программы: все  кнопки и текстовые поля


Это означает, что ты перерисовываешь только сам компонент, а прорисовать его контейнер забываешь  smile
Вызывай метод repaint() для контейнера в котором находится целевой компонент и все будет в порядке. Например, если ты рисуешь на JPanel, которая находится на JFrame, то вызывай repaint для JFrame (или для ContentPane этого JFrame). Он пререрисует себя и свои компоненты.  smile


 

  


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
Samuil
Дата 30.6.2006, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


в(Job)ываю
**


Профиль
Группа: Участник
Сообщений: 705
Регистрация: 26.4.2006
Где: Uzbekistan.Tashke nt

Репутация: нет
Всего: 6



Код

 public void update(Graphics g) { // THe Method for Double Buffering

        Dimension d = size();

        if ((offGraphics == null) || (d.width != offDimension.width) ||
            (d.height != offDimension.height)) {

            offDimension = d;
            offImage = createImage(d.width, d.height);
            offGraphics = offImage.getGraphics();
        }

        offGraphics.setColor(getBackground());
        offGraphics.fillRect(0, 0, d.width, d.height);
        offGraphics.setColor(Color.yellow);

        paintFrame(offGraphics);
        g.drawImage(offImage, 0, 0, this);

    }

    public void paint(Graphics g) { // Not Neded
        update(g);
    }
public void paintFrame(Graphics g){
g.draw.... and other

 


--------------------
Выбор уже сделан, остается его только осознать   
smile    smile 
      smile  

user posted image
PM MAIL ICQ   Вверх
powerOn
Дата 30.6.2006, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 31
Всего: 159



Samuil, а про комментировать код? Что он делает то? 


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
SplinterL
Дата 30.6.2006, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 29.6.2006

Репутация: нет
Всего: нет



Samuil, твой код не помогает. Все работает как и раньше: мерцает и под слоем графики рисуется интерфейс.
MoonCat, где писать repaint() для контейнера, в основной программе? Разъясни пожалуйста....
Лучше всего кодом. smile 
Значит пойду читать тексты программ, которые к jsdk прилагаются, у них то все работает.. smile  
PM MAIL ICQ   Вверх
powerOn
Дата 30.6.2006, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 31
Всего: 159



Цитата(SplinterL @  30.6.2006,  20:00 Найти цитируемый пост)
MoonCat, где писать repaint() для контейнера, в основной программе? Разъясни пожалуйста....
Лучше всего кодом. smile 


Выложи код своей программы целиком. 


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
powerOn
Дата 30.6.2006, 20:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 31
Всего: 159



Вот пример кода.

Панель: 
Код

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;

public class TestPanel extends javax.swing.JPanel {
// координаты курсора.
    int mx = 0, my = 0;

// БУФЕР ДЛЯ ВНЕОКОННОЙ ПРОРИСОВКИ (!)
    BufferedImage offscreen = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
   
// конструктор: добавляем слушателей на изменение размеров компонента и перемещение мыши (драг)
    public TestPanel() {
        addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                formComponentResized(evt);
            }
        });
        addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e){
                mx = e.getX();
                my = e.getY();
                repaint();
            }
        });
    }

// прорисовка
    public void paint(Graphics g) {
     // super.repaint();

// ДВОЙНАЯ БУФЕРИЗАЦИЯ: Рисуем сначало все в буфер, а потом ОДНОЙ БЫСТРОЙ ОПЕРАЦИЕЙ прорисовываем буфер на экране.

//рисуем на внеэкранном буфере.
        Graphics g2 =  offscreen.getGraphics();
       
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, getWidth(), getHeight());
        
        g2.setColor(Color.BLUE);
        g2.fillRect(mx, my, 100, 100);
// рисуем на экран        
        g.drawImage(offscreen, 0, 0, null);
   }
                        
   // подганяем размер буфера под размеры компонента, если размеры последнего изменились.
    private void formComponentResized(java.awt.event.ComponentEvent evt) {                                      
        int x = getWidth();
        int y = getHeight();
        if ((x > 1) && (y > 1)) {
            offscreen = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB);
            repaint();
        }
    }                                     
}


Фрайм для запуска.
Код

public class TestFrame extends javax.swing.JFrame {
    public TestFrame() {
        initComponents();
    }
    private void initComponents() {
        testPanel1 = new TestPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().add(testPanel1, java.awt.BorderLayout.CENTER);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-413)/2, (screenSize.height-379)/2, 413, 379);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TestFrame().setVisible(true);
            }
        });
    }

    private TestPanel testPanel1;
}
 


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
SplinterL
Дата 30.6.2006, 21:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 29.6.2006

Репутация: нет
Всего: нет



MoonCat твой код тоже не работает, ЧЕСТНО! Когда синий квадрат на белом фоне двигаешь то все нормально. А когда попробуешь что-нибудь посложнее вроде

Код

for(int i=0; i<d.width; i+=3) g2.drawLine(i,0,d.width-i,d.height);
for(int i=0; i<d.height; i+=3) g2.drawLine(0,i,d.width,d.height-i);


то изображение начинает мерцать, когда его передвигаешь или если двигаешь все окно целиком. Я специально проверил стандартные программы из jsdk. В них все нормально. ?  
PM MAIL ICQ   Вверх
Samuil
Дата 30.6.2006, 23:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


в(Job)ываю
**


Профиль
Группа: Участник
Сообщений: 705
Регистрация: 26.4.2006
Где: Uzbekistan.Tashke nt

Репутация: нет
Всего: 6



Привет вот код только ошибки в нем есть придется тебе исправлять!

Улучшение изображения двойной буферизацией 

Суть двойной буферизации в том, что в оперативной памяти создается буфер — объект класса image или Bufferedimage, и вызывается его графический контекст, в котором формируется изображение. Там же происходит очистка буфера, которая тоже не отражается на экране. Только после выполнения всех действий готовое изображение выводится на экран. 

Все это происходит в методе updateo, а метод paint о только обращается к update (). Листинги 15.10—15.11 разъясняют данный прием. 

Листинг 15.10. Двойная буферизация с помощью класса image 

public void update(Graphics g){ 

int w = getSize().width, h = getSize().height; 

// Создаем изображение-буфер в оперативной памяти  

Image offlmg = createlmage(w, h); 

// Получаем его графический контекст  

Graphics offGr = offImg.getGraphics(); 

// Меняем текущий цвет буфера на цвет фона  

offGr.setColor(getBackground()); 

//и заполняем им окно компонента, очищая буфер  

offGr.fillRect(0, 0, w, h); 

// Восстанавливаем текущий цвет буфера  

offGr.setColor(getForeground()); 

// Для листинга 15.9 выводим в контекст изображение  

offGr.drawlmage(img[count % 10], 0, 0, this); 

// Рисуем в графическом контексте буфера 

// (необязательное действие)  

paint(offGr); 

// Выводим изображение-буфер на экран 

// (можно перенести в метод paint())  

g.drawlmage(offlmg, 0, 0, this); } 

// Метод paint() необязателен  

public void paint(Graphics g)J update(g); } 

Листинг 15.11. Двойная буферизация с помощью класса Bufferedimage 

public void update(Graphics g){  

Graphics2D g2 = (Graphics2D},g;  

int w = getSize().width, h = getSize().height; 

// Создаем изображение-буфер в оперативной памяти  

Bufferedimage bi = (Bufferedimage)createlmage(w, h); 

// Создаем графический контекст буфера  

Graphics2D big = bi.createGraphics(); 

// Устанавливаем цвет фона  

big.setColor(getBackground()); 

// Очищаем буфер цветом фона  

big.clearRect(0, 0, w, h); 

// Восстанавливаем текущий цвет  

big.setColor(getForeground()); 

// Выводим что-нибудь в графический контекст big  

// ... 

// Выводим буфер на экран  

g2.drawImage(bi, 0, 0, this);  



Метод двойной буферизации стал фактическим стандартом вывода изменяющихся изображений, а в библиотеке Swing он применяется автоматически. 

Данный метод удобен и при перерисовке отдельных частей изображения. В этом случае в изображении-буфере рисуется неизменяемая часть изображения, а в методе paint() — то, что меняется при каждой перерисовке. 

В листинге 15.12 показан второй способ анимации — кадры изображения рисуются непосредственно в программе, в методе update (), по заданному закону изменения изображения. В результате красный мячик прыгает на фоне изображения. 

Листинг 15.12. Анимация рисованием 

import Java.awt.*; 

import j ava.awt.event.*; 

import Java.awt.geom.*; 

import java.awt.image.*; 

class DrawAniml extends Frame{  

private Image img;  

private int count; 

DrawAniml(String s) {  

super(s); 

MediaTracker tr = new MediaTracker(this);  

img = getToolkit().getlmage("back2.jpg");  

tr.addlmage(img, 0);  

try{ 

tr.waitForlD(0) ;  

}catch(InterruptedException e) {} 

SetSize(400, 400);  

setvisible(true); 



public void update(Graphics g){  

Graphics2D g2 = (Graphics2D)g;  

int w = getSizeO.width, h = getSize().height;  

Bufferedlmage bi = (Bufferedlmage)createlmage(w, h) ;  

Graphics2D big = bi.createGraphics(); 

// Заполняем фон изображением img  

big.drawlmage(img, 0, 0, this); 

// Устанавливаем цвет рисования  

big.setColor(Color.red); 

// Рисуем в графическом контексте буфера круг,  

// перемещающийся по синусоиде  

big.fill(new Arc2D.Double(4*count, 50+30*Math.sin(count), 

50, 50, 0, 360, Arc2D.OPEN));  

// Меняем цвет рисования  

big.setColor(getForeground()); 

// Рисуем горизонтальную прямую  

big.draw(new Line2D.Double(0, 125, w, 125)); 

// Выводим изображение-буфер на экран  

g2.drawlmage(bi, 0, 0, this); } 

public void go(){  

while(count < 100){  

repaint();  

try{ 

Thread.sleep(10);  

}catch(InterruptedException e){}  

count++;  

}  

}  

public static void main(String[] args){ 

DrawAniml f = new DrawAniml(" Анимация"); 

f.go(); 

f.addWindowListener(new WindowAdapter(){ 

public void windowClosing(WindowEvent ev){ 

System.exit(0);  



});  

}  



Эффект мерцания, переливы цвета, затемнение и прочие эффекты, получающиеся заменой отдельных пикселов изображения, удобно создавать с помощью класса Memoryimagesource. Методы newPixeis() этого класса вызывают немедленную перерисовку изображения даже без обращения к методу repaint(), если перед этим выполнен метод setAnimated(true). Чаще всего применяются два метода: 

newPixels(int x, int y, int width, int height) — получателю посылается указанный аргументами прямоугольный фрагмент изображения; 
 nevPixels() — получателю посылается все изображение. 
В листинге 15.13 показано применение этого способа. Квадрат, выведенный на экран, переливается разными цветами. 

Листинг 15.13. Анимация с помощью MemorylmageSource 

import Java.awt.*; 

import java.awt.event.*; 

import java.awt.image.*; 

class InMemory extends Frame{ 

private int w = 100, h = 100, count;  

private int[] pix = new int[w * h];  

private Image img;  

MemorylmageSource mis;  

InMemory(String s){ super(s);  

int i = 0;  

for(int у = 0; у < h; y++){ 

int red = 255 * у / (h - 1);  

for(int x = 0; x < w; x++){ 

int green = 25$ * x / (w - 1); 

pix[i++] = (255 « 24}|(red << 16)|(green << 8) | 128;  





mis = new MemorylmageSource(w, h, pix, 0, w); 

// Задаем возможность анимации 

mis.setAnimated(true); 

img = createImage(mis); 

setSize(350, 300); 

setVisible(true);  

}  

public void paint(Graphics gr){ 

gr.drawImage(img, 10, 30, this); 



public void update(Graphics g) { paint(g); } 

public void got){  

while (count < 100){ 

int i = 0;  

// Изменяем массив пикселов по некоторому закону  

for(int у - 0; у < h;,y++) 

for (int x. = 0; x < w; x++) 

pix[i++J = (255 « 24)|(255 + 8 * count « 16)| 

(8*count «8)| 255 + 8 * count;  

// Уведомляем потребителя об изменении  

mis.newPixels();  

try{ 

Thread.sleep(100);  

}catch(InterruptedException e){}  

count++;  

}  

}  

public static void main(String[] args){ 

InMemory f= new InMemory(" Изображение в памяти"); 

f.go(); 

f.addWindowListener(new WindowAdapter(){ 

public void windowClosing(WindowEvent ev){ 

System.exit(0);  



));  

}  



Вот и все средства для анимации, остальное — умелое их применение. Комбинируя рассмотренные способы, можно добиться удивительных эффектов. В документации SUN J2SDK, в каталогах demo\applets и demo\jfc\Java2D \src, приведено много примеров апплетов и приложений с анимацией. 

 


--------------------
Выбор уже сделан, остается его только осознать   
smile    smile 
      smile  

user posted image
PM MAIL ICQ   Вверх
powerOn
Дата 30.6.2006, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 31
Всего: 159



Цитата(SplinterL @  30.6.2006,  22:57 Найти цитируемый пост)
Я специально проверил стандартные программы из jsdk. В них все нормально. ?   

SplinterL, примеры, кстати, с исходниками идут, посмотри как там прорисовка идет и сделай по аналогии  smile 


Samuil, используй кнопку код для оформления исходников. 
И если это не твои мысли, то лучше просто выложить ссылку на источник, чем копировать все сюда в качестве ответа.
http://www.lib.csu.ru/dl/text/programm/inf...a15/Index13.htm  smile 
 


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.1782 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.