Como atualizar gráficos de uma classe de janela em Java

Paiku Han:

Eu estou tentando desenhar sobre um vlcj (ligação java da biblioteca VLC) do painel para que eu possa reproduzir um vídeo e desenhar sobre ele. E eu tenho encontrar alguns problemas. Aqui está o código de base completa:

Code-Listagem 1: AppOverlay.java

package app;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;

import com.sun.jna.platform.WindowUtils;

@SuppressWarnings("serial")
public class AppOverlay extends Window implements Runnable {

    private final boolean isRunning;
    private final int fps;
    private BufferedImage graphics;
    private BufferedImage img;
    private int x, y;
    private boolean ltr;

    public AppOverlay(Window owner) {
        super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
        setBackground(new Color(0,0,0,0));

        graphics    = new BufferedImage(1280,800, BufferedImage.TYPE_INT_ARGB);
        isRunning   = true;
        img         = null;
        ltr         = true;
        fps         = 60;
        x           = 0;
        y           = 0;
    }

    @Override
    public void run(){
        while(isRunning){

            try{
                Thread.sleep(1000/fps);
            } catch(InterruptedException e){
                e.printStackTrace();
            }

            if(ltr) {
                if(x < 1280) x++;
                else ltr = false;
            } else {
                if(x < 0) ltr = true;
                else x--;
            }

            repaint();
        }
    }

    public void createAndShowGUI() {
        setVisible(true);

        Thread thread = new Thread(this);
        thread.start();

        String path = "Drive:\\path\\to\\image.png";
        try {
            img = ImageIO.read(new java.io.FileInputStream(path));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        Graphics2D gfx = graphics.createGraphics();
        gfx.setColor(new Color(255,255,255,0));
        gfx.clearRect(0, 0, 1280, 800);
        if(img != null) gfx.drawImage(img, x, y, null);
        gfx.dispose();
        g2d.drawImage(graphics, 0, 0, null);
    }
}

Code-Listagem 2: AppPlayer.java

package app;

import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;

@SuppressWarnings("serial")
public class AppPlayer extends EmbeddedMediaPlayerComponent {

}

Code-Listagem 3: AppFrame.java

package app;

import java.awt.Dimension;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class AppFrame extends JFrame {

    private AppPlayer appPlayer;
    private AppOverlay overlay;

    public AppFrame(){
        super();
    }

    public void createAndShowGUI() {

        appPlayer = new AppPlayer();
        appPlayer.setPreferredSize(new Dimension(1280,800));
        getContentPane().add(appPlayer);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("App");
        setVisible(true);
        pack();

        overlay = new AppOverlay(this);
        appPlayer.mediaPlayer().overlay().set(overlay);
        appPlayer.mediaPlayer().overlay().enable(true);
        overlay.createAndShowGUI();
    }
}

Código de listagem 4: Main.java

package main;

import javax.swing.SwingUtilities;

import app.AppFrame;

public class Main {

    public static void main(String[] args) {
        final AppFrame app = new AppFrame();
        SwingUtilities.invokeLater( new Runnable() {
            @Override
            public void run() {
                app.createAndShowGUI();
            }
        });
    }

}

com isso e a biblioteca vlcj-4, você deve ser capaz de testar o meu código você mesmo. Meu problema é que o Overlay (classe AppOverlay que estende a classe Janela) não exibir ou atualizar a animação, a menos que desmarque a janela (eu clicar em outra janela ou no ambiente de trabalho ou na barra de ferramentas OS) para que a janela (aplicação) está inativo, em seguida, selecione a janela (a aplicação) novamente. Ele só irá carregar um quadro e é isso. Eu tenho que desmarcar e selecione novamente a janela novamente por ele para carregar outra foto (este é apenas o caso para o Overlay ou seja, se eu jogar um vídeo na classe AppPlayer o vídeo estará jogando muito bem.

O que eu quero é ser capaz de desenhar alguns gráficos animados na sobreposição. Eu sei que com a classe JPanel há o método paintComponent (), mas a classe de janela não tem esse método (apenas o paint () e repaint () métodos estão disponíveis).

O que devo fazer para corrigir isso?

EDITAR:

Eu tentei adicionar um JPanel em que eu desenho em vez de desenhar diretamente sobre a AppOverlay

Código de listagem 5: AppPanel.java

package app;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

public class AppPanel extends JPanel implements Runnable {
    private int x, y;
    private boolean ltr;

    public AppPanel() {
        x   = 0;
        y   = 0;
        ltr = true;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(new Color(0,0,0,0));
        g.clearRect(0, 0, 1280, 800);
        g.setColor(Color.RED);
        g.fillRect(x, y, 100, 100);
    }

    @Override
    public void run() {
        while(true){

            try{
                Thread.sleep(1000/60);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
            if(ltr) {
                if(x < 1280) x++;
                else ltr = false;
            } else {
                if(x < 0) ltr = true;
                else x--;
            }

            repaint();
        }
    }
}

em seguida, adicioná-lo ao AppOverlay.

Código de listagem 6: AppOverlay.java com modificação parcial

public class AppOverlay extends Window implements Runnable {
    //previous field declaration above ...
    AppPanel panel;
    AppPlayer player = null;

    public AppOverlay(Window owner) {
        //previous constructor instructions above...

        panel = new AppPanel();
        add(panel);
    }

    public void createAndShowGUI(AppPlayer player) {
        setVisible(true);

        /*
        Thread thread = new Thread(this);
        thread.start();

        String path = "Drive:\\path\\to\\image.png";
        try {
            img = ImageIO.read(new java.io.FileInputStream(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        */

        Thread panelThread = new Thread(panel);
        panelThread.start();
    }
}

Fazendo isso irá exibir os gráficos do JPanel e animá-los, conforme necessário.

Se você sabe uma maneira de fazer o fundo JPanel transparente (para que possamos ver através dele) enquanto ainda deixá-lo mostrar seus gráficos. Isso resolveria o problema, com certeza.

segunda:

Eu brinquei um pouco com o seu exemplo e veio com algo de trabalho, mas eu não chamaria isso de uma solução agradável.

O principal problema parece ser que não há nenhuma maneira de dizer a sobreposição para atualizar (ou eu simplesmente não tê-lo encontrado). Apenas repaintinga sobreposição não atualizá-lo na tela, então a solução que eu usei é para ocultar e mostrar-lo novamente.

Para o timeing do intervalo de atualização eu usei um javax.swing.Timer. (Em uma versão real você provavelmente deseja iniciar e parar o temporizador via MediaPlayerEventListener).

Como um efeito colateral do repaintmétodo é chamado e a xcoordenada é ajustado para mover a imagem do ecrã.

No exemplo simplificado abaixo (use sua mainpara executá-lo), mudei-me um retângulo vermelho com a coordenada x em vez de alguma imagem desconhecido.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.Timer;

import com.sun.jna.platform.WindowUtils;

import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;

public class AppFrame extends JFrame {

    private static final long serialVersionUID = -1569823648323129877L;

    public class Overlay extends Window {

        private static final long serialVersionUID = 8337750467830040964L;

        private int x, y;
        private boolean ltr = true;

        public Overlay(Window owner) throws HeadlessException {
            super(owner, WindowUtils.getAlphaCompatibleGraphicsConfiguration());
            setBackground(new Color(0,0,0,0));
        }

        @Override
        public void paint(Graphics g) {

            super.paint(g);

            if (ltr) {
                if (x < 1180)
                    x += 1;
                else
                    ltr = false;
            } else {
                if (x < 0)
                    ltr = true;
                else
                    x -= 1;
            }

            g.setColor(Color.RED);
            g.fillRect(x, y, 100, 100);

            String s = Integer.toString(x);
            g.setColor(Color.WHITE);
            g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
        }
    }

    private EmbeddedMediaPlayerComponent appPlayer;

    public void createAndShowGUI() {

        appPlayer = new EmbeddedMediaPlayerComponent();
        appPlayer.setPreferredSize(new Dimension(1280, 800));
        getContentPane().add(appPlayer);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("App");
        setVisible(true);
        pack();

        Overlay overlay = new Overlay(this);

        OverlayApi api = appPlayer.mediaPlayer().overlay();
        api.set(overlay);
        api.enable(true);

        //appPlayer.mediaPlayer().media().play(" ... ");

        Timer timer = new Timer(0, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                api.enable(false);
                api.enable(true);
            }
        });
        timer.setRepeats(true);
        timer.setDelay(200);
        timer.start();
    }
}

Se isso é uma opção para você, pode ser muito mais fácil de usar uma animated gifvez. Pelo menos isso está trabalhando em sua própria (sem necessidade do temporizador).


Atualizar:

Como você descobriu usando um JPanelparece funcionar melhor. Basta usar setOpaque(false)para torná-lo transparente.

Aqui um exemplo ajustado.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

import uk.co.caprica.vlcj.player.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.OverlayApi;

public class AppFrame2 extends JFrame {

    private static final long serialVersionUID = -1569823648323129877L;

    public class OverlayPanel extends JPanel {

        private static final long serialVersionUID = 8070414617530302145L;

        private int x, y;
        private boolean ltr = true;

        public OverlayPanel() {
            this.setOpaque(false);
        }

        @Override
        public void paint(Graphics g) {

            super.paint(g);

            if (ltr) {
                if (x < 1180)
                    x += 1;
                else
                    ltr = false;
            } else {
                if (x < 0)
                    ltr = true;
                else
                    x -= 1;
            }

            g.setColor(Color.RED);
            g.fillRect(x, y, 100, 100);

            String s = Integer.toString(x);
            g.setColor(Color.WHITE);
            g.drawChars(s.toCharArray(), 0, s.length(), x+10, y+50);
        }
    }

    public class Overlay extends Window {

        private static final long serialVersionUID = 8337750467830040964L;

        OverlayPanel panel;

        public Overlay(Window owner) throws HeadlessException {
            super(owner);
            setBackground(new Color(0,0,0,0));

            panel = new OverlayPanel();
            this.add(panel);
        }
    }

    private EmbeddedMediaPlayerComponent appPlayer;

    public void createAndShowGUI() {

        appPlayer = new EmbeddedMediaPlayerComponent();
        appPlayer.setPreferredSize(new Dimension(1280, 800));
        getContentPane().add(appPlayer);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("App");
        setVisible(true);
        pack();

        Overlay overlay = new Overlay(this);

        OverlayApi api = appPlayer.mediaPlayer().overlay();
        api.set(overlay);
        api.enable(true);

        //appPlayer.mediaPlayer().media().play(" ... ");

        Timer timer = new Timer(0, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                overlay.panel.repaint();
            }
        });
        timer.setRepeats(true);
        timer.setDelay(17);
        timer.start();
    }
}

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=313253&siteId=1
Recomendado
Clasificación