gpt4 book ai didi

java - 如何在 Java 中刷新 Window 类的图形

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:43:29 25 4
gpt4 key购买 nike

我正在尝试绘制一个 vlcj(VLC 库的 java 绑定(bind))面板,以便我可以播放视频并在其上绘制。我遇到了一些问题。这是完整的基本代码:

代码 list 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);
}
}

代码 list 2:AppPlayer.java

package app;

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

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

}

代码 list 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();
}
}

代码 list 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();
}
});
}

}

有了它和 vlcj-4 库,您应该能够自己测试我的代码。我的问题是 Overlay(扩展 Window 类的 AppOverlay 类)不显示或刷新动画,除非我取消选择窗口(我单击另一个窗口或桌面或操作系统工具栏)以便窗口(应用程序)处于非 Activity 状态,然后再次选择窗口(应用程序)。它只会加载一帧,仅此而已。我必须再次取消选择并重新选择窗 Eloquent 能加载另一个帧(这只是 Overlay 的情况,即如果我在 AppPlayer 类中播放视频,视频将播放得很好。

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

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

编辑:

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

代码 list 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();
}
}
}

然后将其添加到 AppOverlay。

代码 list 6:AppOverlay.java 部分修改

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 背景透明(以便我们可以透过它看到)的方法,同时仍然让它显示其图形。这肯定会解决问题。

最佳答案

我试了一下你的例子,想出了一些可行的方法,但我不认为它是一个好的解决方案。

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

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

作为副作用,调用了 repaint 方法并调整了 x 坐标以在屏幕上移动图像。

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

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) 使其透明。

这里是一个调整后的例子。

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();
}
}

关于java - 如何在 Java 中刷新 Window 类的图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58343385/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com