首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Java中刷新窗口类的图形

如何在Java中刷新窗口类的图形
EN

Stack Overflow用户
提问于 2019-10-11 14:28:13
回答 3查看 1.2K关注 0票数 3

我试图在vlcj ( VLC库的java绑定)面板上绘制,这样我就可以播放视频并绘制它。我遇到了一些问题。下面是完整的基本代码:

代码-清单1: AppOverlay.java

代码语言:javascript
复制
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);
    }
}

代码-清单2: AppPlayer.java

代码语言:javascript
复制
package app;

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

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

}

代码-清单3: AppFrame.java

代码语言:javascript
复制
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();
    }
}

代码-清单4: Main.java

代码语言:javascript
复制
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();
            }
        });
    }

}

有了这个库和vlcj-4库,您应该能够亲自测试我的代码。我的问题是叠加(扩展窗口类的AppOverlay类)不会显示或刷新动画,除非我取消选择窗口(我单击另一个窗口或桌面或OS工具栏),以便窗口(应用程序)不活动,然后再次选择窗口(应用程序)。它只加载一个框架,仅此而已。为了加载另一帧,我必须取消选择并重新选择窗口(这只是覆盖层的情况,也就是说,如果我在AppPlayer类中播放视频,视频就会播放得很好。

我想要的是能够在覆盖层上绘制一些动画图形。我知道,对于JPanel类,有paintComponent()方法,但是Window类没有该方法(只有()和there ()方法可用)。

我该怎么做才能解决这个问题?

编辑:

我尝试添加一个JPanel,而不是直接在AppOverlay上绘图。

代码-清单5: AppPanel.java

代码语言:javascript
复制
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();
        }
    }
}

然后将其添加到AppOverlay中。

代码-清单6:部分修改的AppOverlay.java

代码语言:javascript
复制
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();
    }
}

这样做将显示JPanel的图形,并根据需要将其动画化。

如果您知道一种使JPanel背景透明的方法(这样我们就可以看穿它),同时仍然让它显示其图形。这肯定能解决这个问题。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-10-16 15:25:02

我试了一下你的例子,想出了一些有用的东西,但我不认为它是一个很好的解决方案。

主要的问题似乎是,没有办法告诉覆盖刷新(或者我只是没有找到它)。只是repainting覆盖没有更新它在屏幕上,所以我使用的解决办法是隐藏和再次显示它。

对于更新间隔的时间,我使用了一个javax.swing.Timer。(在真正的版本中,您可能希望通过MediaPlayerEventListener启动和停止计时器)。

作为副作用,调用repaint方法,调整x坐标,使图像在屏幕周围移动。

在下面的简化示例(使用您的main运行它)中,我移动了一个带有x坐标的红色矩形,而不是一些未知的图像。

代码语言:javascript
复制
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();
    }
}

如果这是您的选择,那么使用animated gif可能要容易得多。至少它是独立工作的(不需要计时器)。

更新:

正如您所理解的那样,使用JPanel似乎更有效。只需使用setOpaque(false)使其透明。

这里是一个调整的例子。

代码语言:javascript
复制
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();
    }
}
票数 1
EN

Stack Overflow用户

发布于 2019-10-13 23:54:41

你已经完成了大部分工作。每次您通过调用app.repaint();绘制框架时,只需重新绘制它

票数 0
EN

Stack Overflow用户

发布于 2019-10-14 03:34:17

您可以使用JComponent中的下列方法:( http://download.oracle.com/javase/6/docs/api/javax/swing/JComponent.html )

代码语言:javascript
复制
void    repaint(long tm, int x, int y, int width, int height)
 //**Adds the specified region to the dirty region list if the component is showing.*//
void    repaint(Rectangle r)
 /**Adds the specified region to the dirty region list if the component is showing.*//
You can call those before redraw()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58343385

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档