Ответ 1
Существует несколько способов достижения этой цели.
Вы могли...
Cavet, используя JLabel
для этой цели, может привести к тому, что содержимое переливается на континенте, подробнее см. ниже.
Создайте JLabel
, примените к нему образ icon
и установите его как панель содержимого фреймов. Затем вам необходимо соответствующим образом настроить диспетчер компоновки, так как JLabel
не имеет диспетчера компоновки по умолчанию
JFrame frame = ...;
JLabel background = new JLabel(new ImageIcon(ImageIO.read(...)));
frame.setContentPane(background);
frame.setLayout(...);
frame.add(...);
Обновление с полным примером
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LabelBackground {
public static void main(String[] args) {
new LabelBackground();
}
public LabelBackground() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
// Load the background image
BufferedImage img = ImageIO.read(new File("/path/to/your/image/on/disk"));
// Create the frame...
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set the frames content pane to use a JLabel
// whose icon property has been set to use the image
// we just loaded
frame.setContentPane(new JLabel(new ImageIcon(img)));
// Supply a layout manager for the body of the content
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
// Add stuff...
frame.add(new JLabel("Hello world"), gbc);
frame.add(new JLabel("I'm on top"), gbc);
frame.add(new JButton("Clickity-clackity"), gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
}
Проблема с этим: JLabel
не будет изменять размер изображения при изменении размера рамки
ПРЕДУПРЕЖДЕНИЕ. Использование JLabel
может вызвать проблемы, если требуемое пространство дочерних компонентов превышает размер фонового изображения, так как JLabel
не вычисляет его предпочтительный размер на основе его содержимого, но на основе его свойств icon
и text
Вы могли...
Создайте пользовательский компонент, простирающийся от чего-то вроде JPanel
и переопределите его paintComponent
, покрасьте фон по своему усмотрению.
Посмотрите Выполнение пользовательской живописи для более подробной информации.
Это дает вам возможность решить, как лучше масштабировать изображение при изменении свободного пространства. Несмотря на то, что это может быть достигнуто, вы должны прочитать The Perils of Image.getScaledInstance(), чтобы понять плюсы и минусы из них.
Это вызывает множество новых вопросов, вам нужно масштабировать их и сохранять соотношение сторон? Если да, хотите ли вы поместить изображение в доступную область или заполнить его (чтобы он всегда охватывал доступное пространство)?
Взгляните на Java: поддерживаем соотношение сторон JPanel background image для более подробной информации.
Другие соображения
Изображения обычно лучше всего загружаются через API ImageIO
, так как он способен загружать широкий спектр изображений, но также будет бросать IOException
, когда что-то пойдет не так.
Подробнее см. Чтение/Загрузка изображения.
Также важно расположение изображения. Если изображение является внешним для приложения (где-то в файловой системе), вы можете использовать ImageIO.read(new File("/path/to/image"))
. Однако, если изображение встроено в ваше приложение (например, в Jar), вам нужно будет использовать нечто вроде ImageIO.read(getClass().getResource("/path/to/image"))
вместо этого...
Например...
- Проблема с настройкой фонового изображения
- Добавить фоновое изображение в панель
- Java: фон JPanel не масштабируется
Пример
В этом примере демонстрируется использование настраиваемого компонента, который действует как фоновый компонент. Когда размер компонентов превышает размер фонового изображения, изображение масштабируется для заполнения доступной области содержимого.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleBackground {
public static void main(String[] args) {
new SimpleBackground();
}
public SimpleBackground() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
BackgroundPane background = new BackgroundPane();
background.setBackground(ImageIO.read(new File("/path/to/your/image/on/your/disk")));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(background);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
frame.add(new JLabel("Hello world"), gbc);
frame.add(new JLabel("I'm on top"), gbc);
frame.add(new JButton("Clickity-clackity"), gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
});
}
public class BackgroundPane extends JPanel {
private BufferedImage img;
private BufferedImage scaled;
public BackgroundPane() {
}
@Override
public Dimension getPreferredSize() {
return img == null ? super.getPreferredSize() : new Dimension(img.getWidth(), img.getHeight());
}
public void setBackground(BufferedImage value) {
if (value != img) {
this.img = value;
repaint();
}
}
@Override
public void invalidate() {
super.invalidate();
if (getWidth() > img.getWidth() || getHeight() > img.getHeight()) {
scaled = getScaledInstanceToFill(img, getSize());
} else {
scaled = img;
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled != null) {
int x = (getWidth() - scaled.getWidth()) / 2;
int y = (getHeight() - scaled.getHeight()) / 2;
g.drawImage(scaled, x, y, this);
}
}
}
public static BufferedImage getScaledInstanceToFill(BufferedImage img, Dimension size) {
double scaleFactor = getScaleFactorToFill(img, size);
return getScaledInstance(img, scaleFactor);
}
public static double getScaleFactorToFill(BufferedImage img, Dimension size) {
double dScale = 1;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
double dScaleWidth = getScaleFactor(imageWidth, size.width);
double dScaleHeight = getScaleFactor(imageHeight, size.height);
dScale = Math.max(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
Было бы просто, чтобы изображение уменьшилось, когда пространство уменьшилось, но я намеренно решил сохранить изображение на нем наименьшего размера.
В этом примере также используется пользовательский алгоритм масштабирования и масштабирования, чтобы генерировать высококачественный масштабированный результат.