Background an Framegröße anpassen

Servus,

habe mal mein Hintergrundbild für mein Spiel soweit fertiggestellt, werde mich auch erst um alles andere kümmern. Würde aber gerne mal sehen wie es Ingame mit verschiedenen Monitorgrößen aussieht bevor ich das Backend anfange.

Ich habe einen JFrame, und dem möchte ich das Bild als Background einfügen. Das Bild hat eine Größe von 1920x1080 und soll sich eben an die Größe des Monitors anpassen. An meinem 23,5 Zoll geht es, auf meinem 17 Zoll wird nur noch gut die Hälfte angezeigt. Welche Möglichkeit gibt es, um es an dem Monitor anzupassen?

Vielen Dank im Vorraus.
 
An meinem 23,5 Zoll geht es, auf meinem 17 Zoll wird nur noch gut die Hälfte angezeigt.
Mit der Größe des Monitors hat das weniger zu tun als mit der Auflösung. Wenn Du ein 1920x1280 Bild auf einem 23,5"-Monitor anzeigst, der das Bild mit 1920x1280 auflöst nimmt das Bild den ganzen Bildschirm ein. Wenn Du das Bild auf einem 17"-Monitor anzeigst, der das Bild mit 1920x1280 auflöst, nimmt das Bild ebenfalls den ganzen Bildschirm ein.

Welche Möglichkeit gibt es, um es an dem Monitor anzupassen?
Ich verstehe die Frage nicht ganz. Du kannst
a) ein Bild mit möglichst passender Größe nehmen,
b) das Bild skalieren und
c) ein nicht-skaliertes Bild im Fenster platzieren.

Was und ggf. in welcher Kombination ist abhängig von Deinem Vorhaben. Willst Du z. B. dass das Bild einfach in das Fenster eingepasst wird: a) und b) (wenn Du nur ein Bild zur Verfügung hast, entfällt a) natürlich). Reicht es dagegen, wenn das Bild das Fenster ausfüllt, kann auch a) und c) verwendet werden. Möchtest Du, dass das Bild auf allen Geräten physikalisch halbwegs gleich groß erscheint? Dann musst Du ein Bild möglichst passender Größe anhand der Pixeldichte des Geräts skalieren und das Ergebnis im Fenster platzieren.
 
Mit der Größe des Monitors hat das weniger zu tun als mit der Auflösung. Wenn Du ein 1920x1280 Bild auf einem 23,5"-Monitor anzeigst, der das Bild mit 1920x1280 auflöst nimmt das Bild den ganzen Bildschirm ein. Wenn Du das Bild auf einem 17"-Monitor anzeigst, der das Bild mit 1920x1280 auflöst, nimmt das Bild ebenfalls den ganzen Bildschirm ein.



Ich verstehe die Frage nicht ganz. Du kannst
a) ein Bild mit möglichst passender Größe nehmen,
b) das Bild skalieren und
c) ein nicht-skaliertes Bild im Fenster platzieren.

Was und ggf. in welcher Kombination ist abhängig von Deinem Vorhaben. Willst Du z. B. dass das Bild einfach in das Fenster eingepasst wird: a) und b) (wenn Du nur ein Bild zur Verfügung hast, entfällt a) natürlich). Reicht es dagegen, wenn das Bild das Fenster ausfüllt, kann auch a) und c) verwendet werden. Möchtest Du, dass das Bild auf allen Geräten physikalisch halbwegs gleich groß erscheint? Dann musst Du ein Bild möglichst passender Größe anhand der Pixeldichte des Geräts skalieren und das Ergebnis im Fenster platzieren.
Danke dir für die konkrete Antwort. Was mein Vorhaben ist: Ich habe ein Bild erstellt, wie oben beschrieben. Und das soll der Spielhintergrund werden. Auf einer Auflösung mit 1920x1080 wird alles perfekt dargestellt, ich möchte aber, dass andere Auflösungen auch passend angezeigt werden. Sprich wenn jemand anders dieses Spiel öffnet mit z.B. 1080x720 das es dann auch passend dargestellt wird.
 
Ja, soweit habe ich es schon probiert. Hier mal mein Code soweit:

Java:
static BufferedImage bg;
 
 public Label() {
  try {
   bg = ImageIO.read((getClass().getResourceAsStream("(1) Spiellandschaft.png")));
  } catch (IOException e) {
   e.printStackTrace();
  }
  paintComponent(bg.createGraphics());
 }
 
 protected void paintComponent(Graphics g) {
     super.paintComponent(g);
     
     double scaleFactor = Math.min(1d, LoggedInPage.getScaleFactorToFit(new Dimension(bg.getWidth(), bg.getHeight()), getSize()));
     int scaleWidth = (int) Math.round(bg.getWidth() * scaleFactor);
     int scaleHeight = (int) Math.round(bg.getHeight() * scaleFactor);
     Image scaled = bg.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);
     int width = getWidth() - 1;
     int height = getHeight() - 1;
     int x = (width - scaled.getWidth(this)) / 2;
     int y = (height - scaled.getHeight(this)) / 2;
     g.drawImage(scaled, x, y, FrameCreator.loggedIn);
 }
Kriege aber immer diesen Fehler:
Code:
Eception in thread "main" java.lang.IllegalArgumentException: Width (0) and height (0) must be non-zero
 
Was machst Du da? Dein Code macht einfach keinen Sinn!

Was Du da machst:
- Du erzeugst ein Buffered Image und lädst da ein Bild rein. (Soweit ok)
- Dann rufst Du paintComponent auf mit einem Graphics Objekt des Bildes?

=> Das Graphics Objekt dient dem "Malen" von Dingen. Somit erzeugst Du ein Graphics Objekt, mit dem Du in das Bild malen könntest. Wäre also super, wenn du auf das Bild noch was malen / schreiben wolltest. Aber damit veränderst Du das Bild und malst das Bild nicht irgendwo!

=> paintComponent wird nicht aufgerufen von Dir (Einfach als einfache Regel merken! Wenn Du im Detail weisst, was Du machst und Du tief im System eingreifen willst, dann ändert sich das evtl. mal, aber so am Anfang: never!). Das ist eine Funktion, die sozusagen vom System aufgerufen wird. Wenn Du willst, dass die Komponente irgendwas macht, dann kannst Du die paintComponent Funktion überschreiben um da dann irgendwas drin zu machen. Diese Funktion bekommt ein Graphics Object übergeben, welches die Komponente nutzen kann, um sich selbst zu malen.

Nebenbei: Was für Code zeigst Du da? Wenn es Deine Komponente ist, dann sollte das Bild nicht statisch sein!

Ansonsten sieht die überschriebene Funktion schon recht gut aus. Du berechnest aus bg ein scaled Image und das wird dann angezeigt. Zumindest auf den ersten Blick sieht das gut aus.

Notwendige Änderungen: Evtl. reicht es aus, wenn Du einfach den paintComponent Aufruf raus löschst. Dann wird das Bild beim erstellen vom Label geladen. Das Label, das Du erstellt hast, wirst Du ja irgendwo hinzufügen zu einem JFrame oder so ...
 
Ich würde aus Gründen der Geschwindigkeit zwei Bilder halten: das unskalierte und das skalierte und bei Größenänderungen der Komponente das skalierte Bild erzeugen, in paintComponent dann nur noch das skalierte Bild zeichnen. Also etwa so:

Java:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

// for testing purposes
import javax.imageio.ImageIO;
import java.net.URL;

public class ImagePanel extends JPanel {
    private BufferedImage image;
    private Image scaled;

    public ImagePanel(BufferedImage image) {
        this.image = image;
    }

    @Override
    public Dimension getPreferredSize() {
        Insets insets = getInsets();
        int width = insets.left + insets.right + image.getWidth();
        int height = insets.top + insets.bottom + image.getHeight();
        return new Dimension(width, height);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Insets insets = getInsets();
        g.drawImage(getScaled(), insets.left, insets.top, null);
    }

    private Image getScaled() {
        Insets insets = getInsets();                
        int w = getWidth() - insets.left - insets.right;
        int h = getHeight() - insets.top - insets.bottom;

        if (scaled == null || scaled.getWidth(null) != w || scaled.getHeight(null) != h) {
            scaled = image.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        }

        return scaled;
    }


    public static void main(String[] args) throws Exception {
        BufferedImage img = ImageIO.read(new URL("https://upload.wikimedia.org/" +
                "wikipedia/commons/thumb/7/77/Wikipedia_svg_logo.svg/" +
                "768px-Wikipedia_svg_logo.svg.png"));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.add(new ImagePanel(img));
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}
 
Danke euch beiden. Werde es dann heute Abend mal probieren

@JustNobody Ja, wo ich dann in die Arbeit gefahren bin dachte ich mir auch was ich da eigentlich gemacht hab.
 
Habe nun mal das paintComponent entfernt, und über den PaintComponent-Teil ein @Override zum überschreiben. Allerdings wird dieser Teil trotzdem nicht ausgeführt.
 
Ich würde aus Gründen der Geschwindigkeit zwei Bilder halten: das unskalierte und das skalierte und bei Größenänderungen der Komponente das skalierte Bild erzeugen, in paintComponent dann nur noch das skalierte Bild zeichnen. Also etwa so:

Java:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

// for testing purposes
import javax.imageio.ImageIO;
import java.net.URL;

public class ImagePanel extends JPanel {
    private BufferedImage image;
    private Image scaled;

    public ImagePanel(BufferedImage image) {
        this.image = image;
    }

    @Override
    public Dimension getPreferredSize() {
        Insets insets = getInsets();
        int width = insets.left + insets.right + image.getWidth();
        int height = insets.top + insets.bottom + image.getHeight();
        return new Dimension(width, height);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Insets insets = getInsets();
        g.drawImage(getScaled(), insets.left, insets.top, null);
    }

    private Image getScaled() {
        Insets insets = getInsets();               
        int w = getWidth() - insets.left - insets.right;
        int h = getHeight() - insets.top - insets.bottom;

        if (scaled == null || scaled.getWidth(null) != w || scaled.getHeight(null) != h) {
            scaled = image.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        }

        return scaled;
    }


    public static void main(String[] args) throws Exception {
        BufferedImage img = ImageIO.read(new URL("https://upload.wikimedia.org/" +
                "wikipedia/commons/thumb/7/77/Wikipedia_svg_logo.svg/" +
                "768px-Wikipedia_svg_logo.svg.png"));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.add(new ImagePanel(img));
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}
Haut bei mir komischerweise nicht hin, kriege in der main Methode beim Laden des Bildes immer diesen Fehler:
Code:
Exception in thread "main" java.net.MalformedURLException: no protocol: resources/(1) Spiellandschaft.png
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben