Я новичок в Java и создал простое приложение Swing, которое работает в полноэкранном режиме, постоянно проверяет источник данных с регулярными интервалами и показывает разные выходные данные в зависимости от указанного источника данных. Я создал короткий MCVE, чтобы продемонстрировать, что я делаю.
Моя проблема в двух словах: у меня есть фоновое изображение, которое должно всегда отображаться, и изображение переднего плана, которое должно отображаться только при определенных обстоятельствах. К сожалению, кажется, что им требуется всего несколько секунд для загрузки в первый раз, что означает, что экран белый, пока он не будет загружен, и экран будет перекрашен. Чтобы решить это, я отслеживаю количество "циклов" с частным членом и при определенных значениях к началу, я заставляю его пытаться рисовать эти изображения. Однако это кажется очень "взломанным", и я бы скорее научился правильно загружать и отображать изображения в приложениях Swing.
Main.java
import javax.swing.*;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
try {
final MyDisplay myDisplay = new MyDisplay();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
MyDisplay.java
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;
public class MyDisplay extends Thread {
private long cycleCounter = 0;
private MyDataSource dataSource;
private MyFrame myFrame;
public MyDisplay() throws IOException {
dataSource = new MyDataSource();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
myFrame = new MyFrame(device);
final int windowWidth = myFrame.getWindowWidth();
final int windowHeight = myFrame.getWindowHeight();
final URL bgPath = this.getClass().getResource("/bg.png");
final ImageIcon bgLoader = new ImageIcon(bgPath);
final Image bgImage = bgLoader.getImage().getScaledInstance(windowWidth, windowHeight, Image.SCALE_SMOOTH);
myFrame.setBgImage(bgImage);
final URL fgPath = this.getClass().getResource("/fg.png");
final ImageIcon fgLoader = new ImageIcon(fgPath);
final Image fgImage = fgLoader.getImage().getScaledInstance(200, 85, Image.SCALE_SMOOTH);
myFrame.setFgImage(fgImage);
start();
}
@Override
public void run() {
try {
while (true) {
if (dataSource.hasData()) {
myFrame.showData();
} else {
myFrame.clearData();
}
// THIS IS THE "HACKY" PART
cycleCounter++;
if (cycleCounter == 20) {
myFrame.showData();
} else if (cycleCounter == 21) {
myFrame.clearData();
}
// END OF HACK
Thread.sleep(100);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
MyFrame.java
import javax.swing.*;
import java.awt.*;
public class MyFrame extends JFrame {
private GraphicsDevice device;
private MyPanel myPanel;
public MyFrame(GraphicsDevice device) {
super(device.getDefaultConfiguration());
this.device = device;
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ignored) { }
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setUndecorated(true);
setResizable(false);
setVisible(true);
myPanel = new MyPanel();
add(myPanel);
pack();
device.setFullScreenWindow(this);
}
public void setBgImage(Image bgImage) {
myPanel.setBgImage(bgImage);
}
public void setFgImage(Image fgImage) {
myPanel.setFgImage(fgImage);
}
public int getWindowHeight() {
final Double height = device.getDefaultConfiguration().getBounds().getHeight();
return height.intValue();
}
public int getWindowWidth() {
final Double width = device.getDefaultConfiguration().getBounds().getWidth();
return width.intValue();
}
public void showData() {
myPanel.showData();
}
public void clearData() {
myPanel.clearData();
}
}
MyPanel.java
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel {
private boolean showData = false;
private Image bgImage;
private Image fgImage;
public MyPanel() {
setFocusable(true);
requestFocusInWindow();
}
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
setBackground(Color.WHITE);
if (bgImage != null) {
graphics.drawImage(bgImage, 0, 0, null, null);
}
if (showData) {
if (fgImage != null) {
graphics.drawImage(fgImage, 0, 0, 200, 85, null, null);
}
}
}
public void showData() {
if (showData == false) {
showData = true;
repaint();
}
}
public void clearData() {
if (showData == true) {
showData = false;
repaint();
}
}
public void setBgImage(Image bgImage) {
this.bgImage = bgImage;
}
public void setFgImage(Image fgImage) {
this.fgImage = fgImage;
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
}
MyDataSource.java
public class MyDataSource {
public boolean hasData() {
return false;
}
}
TL; DR: Посмотрите на конец файла MyDisplay.java. Вы увидите часть, в которую я взломал, чтобы она работала. Пожалуйста, помогите мне понять, как это сделать правильно.
EDIT: добавлено в MyDataSource.java, по предложению Эндрю Томпсона.
Попробуйте развиться из чего-то вроде этого..
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
public class Main {
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("FullScreen Demo");
frame.setUndecorated(true);
frame.add(new Component() {
BufferedImage bg = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Neige_dans_le_djebel_Ch%C3%A9lia.JPG/1920px-Neige_dans_le_djebel_Ch%C3%A9lia.JPG"));
BufferedImage fg = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/commons/thumb/f/f5/W1769-Vallet_BMX_N_82131.JPG/1920px-W1769-Vallet_BMX_N_82131.JPG"));
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
g.drawImage(fg, 50, 50, getWidth()/10, getHeight()/10, this);
}
});
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
gs.setFullScreenWindow(frame);
frame.validate();
}
}
Если вы не хотите видеть пустой экран при запуске, покажите Frame только тогда, когда изображения полностью загружены. Вы можете загрузить изображение в конструкторе Panel
Или, если вы хотите быстро отобразить, сразу загрузите изображение с низким разрешением, а затем запустите Thread, который загрузит большое изображение в фоновом режиме, и установите его на панели, когда закончите.
SwingWorker
, например , для загрузки изображений при запуске.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
должно бытьUIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
.. 2) Для более быстрой помощи, опубликуйте MCVE ( пример минимальной полной проверки ) или SSCCE (короткий, самодостаточный , правильный пример).