JScrollPane mit JPanelBMP

Status
Nicht offen für weitere Antworten.
S

SenioreFamicom

Gast
Hallo Leute,
erstmal mein Quellcode voran:
Die erste Klasse:

Code:
package SN32.Editor.LowClass;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.JComponent;
import javax.swing.JPanel;


public class KBitmap extends JPanel {
    private int scaleXY = 2;
    private int width   = 480;
    private int height  = 256;
    
    public KBitmap() {
        this.setLayout(null);
        this.setSize(this.width * this.scaleXY, this.height * this.scaleXY);
        this.setLocation(0, 0);
        this.setVisible(true);
        this.repaint();
        
    }
    public void paintComponent(Graphics g) {
        Image img;
        img = getToolkit().getImage("C:/Games/Sprites/Harvest Moon/hmkuhstall.png");
        this.setPreferredSize(new Dimension(this.width * scaleXY, this.height * scaleXY));
        this.setMinimumSize  (new Dimension(this.width * scaleXY, this.height * scaleXY));
        this.setMaximumSize  (new Dimension(this.width * scaleXY, this.height * scaleXY));
        Graphics2D g2D = (Graphics2D) g;
        g2D.scale(scaleXY, scaleXY);
        g2D.drawImage(img, 0, 0, this);
    }
    public int getScaleXY() {
        return this.scaleXY;
    }
    public int getWidth() {
        return this.width;
    }
    public int getHeight() {
        return this.height;
    }
}

Die zweite Klasse:
Code:
package SN32.Editor.TabTile;

import SN32.Editor.Constants;
import SN32.Editor.LowClass.KBitmap;

import SN32.Editor.ReferenceBook.ReferenceBook;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerNumberModel;


public class TilePropReader extends JDialog implements ActionListener {
    private static final int    HINZUF  =   0;  // Button
    private static final int    SEQDEL  =   1;  // Button
    private static final int    ALLDEL  =   2;  // Button
    private static final int    ANWEND  =   3;  // Button
    private static final int    NEWSET  =   4;  // Button
    private static final int    HILFE   =   5;  // Button
    private static final int    ABBRCH  =   6;  // Button
    private static final int    RIGHT_O =   1;  // Panel
    private static final int    RIGHT_I =   2;  // Panel
    private static final int    LEFT_0L =   0;  // Panel
    private static final int    JLIST   =   0;  // ScrollPane
    private static final int    JVIEW   =   1;  // ScrollPane
    
    private File            file        =   null;   
    
    private KBitmap         bitmap      =   null;
    
    public Vector           animation   =   null;
    public JButton      []  button      =   new JButton[7];
    public JLabel       []  label       =   new JLabel[2];
    public DefaultListModel model       =   new DefaultListModel();
    public JList            list        =   new JList(model);
    public JPanel       []  panel       =   new JPanel[3];
    public JScrollPane  []  scrollPane  =   new JScrollPane[2];
    public JSpinner     []  spinner     =   new JSpinner[4];
    public JTextField       textField   =   new JTextField("()");
    
    public TilePropReader(final javax.swing.JFrame parent, final File file) {
        super(parent, true);
        
            this.file   = file;
            bitmap      = new KBitmap();
            
            // .....................................................................
            panel[LEFT_0L] = new JPanel();
            panel[RIGHT_O] = new JPanel();
            panel[RIGHT_I] = new JPanel();
            // links, inneres
            panel[LEFT_0L].setLayout(null);
            panel[LEFT_0L].setSize(480*2, 256*2);
            panel[LEFT_0L].setLocation(0, 0);
            panel[LEFT_0L].add(bitmap);
            panel[LEFT_0L].setVisible(true);
            
            //rechts, äußeres
            panel[RIGHT_O].setLayout(null);
            panel[RIGHT_O].setSize(456 + 16, 480 + 24);
            panel[RIGHT_O].setLocation(328, 16);
            panel[RIGHT_O].setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Tileset-Konfigurationen"));
            panel[RIGHT_O].setVisible(true);
            // rechts, inneres (Ani.seq.)
            panel[RIGHT_I].setLayout(null);
            panel[RIGHT_I].setSize(440, 404);
            panel[RIGHT_I].setLocation(16, 84);
            panel[RIGHT_I].setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Animationssequenzen"));
            panel[RIGHT_I].setVisible(true);
            // .....................................................................
            scrollPane[JLIST] = new JScrollPane(list);
            scrollPane[JLIST].setSize(256 + 24 - 16, 256);
            scrollPane[JLIST].setLocation(16, 56);
            scrollPane[JLIST].setBorder(BorderFactory.createEtchedBorder());
            scrollPane[JLIST].setAutoscrolls(true);
            scrollPane[JLIST].setWheelScrollingEnabled(true);
            scrollPane[JLIST].setVisible(true);
            
            scrollPane[JVIEW] = new JScrollPane(bitmap, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            scrollPane[JVIEW].setSize(256 + 20, 480);
            scrollPane[JVIEW].setLocation(16, 16);
            scrollPane[JVIEW].getViewport().setView(bitmap);
            scrollPane[JVIEW].setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Vorschau"));
            scrollPane[JVIEW].setAutoscrolls(true);
            scrollPane[JVIEW].setWheelScrollingEnabled(true);
            scrollPane[JVIEW].setVisible(true);
            // .................................................................
            label[0] = new JLabel("Tile-Größe: ");
            label[1] = new JLabel("Transparenz-RGB: ");
            // Tile-Größe
            label[0].setSize(128, 24);
            label[0].setLocation(16, 32);
            label[0].setVisible(true);
            // Transparenz-RGB
            label[1].setSize(128, 24);
            label[1].setLocation(16, 60);
            label[1].setVisible(true);
            // .....................................................................
            spinner[0] = new JSpinner(new SpinnerNumberModel(16, 4, 64, 2));
            spinner[1] = new JSpinner(new SpinnerNumberModel(0, 0, 255, 1));
            spinner[2] = new JSpinner(new SpinnerNumberModel(0, 0, 255, 1));
            spinner[3] = new JSpinner(new SpinnerNumberModel(0, 0, 255, 1));
            // Tile-Größe
            spinner[0].setSize(40, 24);
            spinner[0].setLocation(160, 32);
            spinner[0].setBorder(BorderFactory.createEtchedBorder());
            spinner[0].setVisible(true);
            // R
            spinner[1].setSize(40, 24);
            spinner[1].setLocation(160, 58);
            spinner[1].setBorder(BorderFactory.createEtchedBorder());
            spinner[1].setVisible(true);
            // G
            spinner[2].setSize(40, 24);
            spinner[2].setLocation(208, 58);
            spinner[2].setBorder(BorderFactory.createEtchedBorder());
            spinner[2].setVisible(true);
            // B
            spinner[3].setSize(40, 24);
            spinner[3].setLocation(256, 58);
            spinner[3].setBorder(BorderFactory.createEtchedBorder());
            spinner[3].setVisible(true);
            // .....................................................................
            button[HINZUF] = new JButton("Hinzufügen");
            button[SEQDEL] = new JButton("Seq. löschen");
            button[ALLDEL] = new JButton("Alle löschen");
            button[ANWEND] = new JButton("Anwenden");
            button[NEWSET] = new JButton("Neues Set laden");
            button[HILFE] = new JButton("Hilfe");
            button[ABBRCH] = new JButton("Abbrechen");

            button[HINZUF].setSize(128, 32);
            button[SEQDEL].setSize(128, 32);
            button[ALLDEL].setSize(128, 32);
            button[ANWEND].setSize(128, 32);
            button[NEWSET].setSize(128, 32);
            button[HILFE].setSize(128, 32);
            button[ABBRCH].setSize(128, 32);

            button[HINZUF].setLocation(296, 20);
            button[SEQDEL].setLocation(296, 68);
            button[ALLDEL].setLocation(296, 116);
            button[ANWEND].setLocation(112, 552);
            button[NEWSET].setLocation(256, 552);
            button[HILFE].setLocation(400, 552);
            button[ABBRCH].setLocation(544, 552);

            button[0].addActionListener(this);
            button[1].addActionListener(this);
            button[2].addActionListener(this);
            button[3].addActionListener(this);
            button[4].addActionListener(this);
            button[5].addActionListener(this);
            button[6].addActionListener(this);
            button[0].setVisible(true);
            button[1].setVisible(true);
            button[2].setVisible(true);
            button[3].setVisible(true);
            button[4].setVisible(true);
            button[5].setVisible(true);
            button[6].setVisible(true);
            // .....................................................................
            textField.setSize(256 + 8, 24);
            textField.setLocation(16, 24);
            textField.setVisible(true);
            // .....................................................................
            list.setSize(256 + 24 - 16, 256);
            list.setLocation(16, 56);
            list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            list.setVisible(true);
            // .....................................................................


            // ===============================
            this.add(scrollPane[JVIEW]);

            panel[RIGHT_I].add(textField);
            panel[RIGHT_I].add(scrollPane[JLIST]);
            panel[RIGHT_I].add(button[0]);
            panel[RIGHT_I].add(button[1]);
            panel[RIGHT_I].add(button[2]);

            panel[RIGHT_O].add(label[0]);
            panel[RIGHT_O].add(label[1]);
            panel[RIGHT_O].add(spinner[0]);
            panel[RIGHT_O].add(spinner[1]);
            panel[RIGHT_O].add(spinner[2]);
            panel[RIGHT_O].add(spinner[3]);
            panel[RIGHT_O].add(panel[2]);
            // ===============================
            this.setLayout(null);
            this.setSize(816, 640);
            this.setLocation(256, 192);
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            //this.add(panel[LEFT]);
            this.add(panel[RIGHT_O]);
            this.add(button[3]);
            this.add(button[4]);
            this.add(button[5]);
            this.add(button[6]);
            this.setVisible(true);
    }    
}
Das geladene Bild hat die Maße 480x256 Pixel.
Jetzt meine Frage: Wieso zeigt mein Programm beim Ausführen von der zweiten Klasse die Bitmap nur teilweise (genauer nur die oberen 128 Pixel) an? Erst beim Scrollen mit JScrollPane wird der Rest übermalt.
 

Marco13

Top Contributor
Code:
public void paintComponent(Graphics g) {
        Image img;
        img = getToolkit().getImage("C:/Games/Sprites/Harvest Moon/hmkuhstall.png"); 
...
Das Bild wird bei jedem Neuzeichnen neu geladen (und was meinst du, wie oft er neu zeichnet, wenn man scrollt!)

Du solltest das Bild EINmal im Konstruktor laden. Und dort solltest du dann einen MediaTracker http://java.sun.com/j2se/1.4.2/docs/api/java/awt/MediaTracker.html drumwickeln, um sicherzustellen, dass das Bild vollständig geladen ist, bevor es angezeigt wird.

EDIT: Das setPreferredSize usw. sollte AUCH im Konstruktor stehen!


EDIT2: Und wenn du das Bild auch gleich im Konstruktor skalierst, braucht das auch nicht bei jedem Zeichen neu gemacht zu werden, und es wird vmtl. deutlich schneller!
 

Marco13

Top Contributor
Kein EDIT mehr, sondern ein Nachtrag: Wenn du irgendwann mal eine deiner Components entfernen (d.h. nichtmher anzeigen) willst, wirst du mit diesen Arrays vermutlich keine Freude haben....
 
S

SenioreFamicom

Gast
Erstmal Danke für die schnelle Antwort :)

:oops: Okay, sind ja einige Performance-Probleme. Man merkt, dass ich Anfänger bin :autsch:
Aber da muss ich gleich nochmal nachfragen: Wie sieht das aus, wenn ich im Konstrukter skalieren möchte? Und was meintest du mit den Arrays? Die Komponenten in der TilePropReader?
 

Marco13

Top Contributor
Im Konstruktor skalieren geht am einfachsten mit Image#getScaledInstance. Für "ausgefeiltere" Sachen kannst du auch mal hier schauen: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html


Das mit den Arrays ... naja, du hast z.B.
Code:
private static final int    SEQDEL  =   1;  // Button 
...
public JButton      []  button      =   new JButton[7]; 
...
button[SEQDEL] = new JButton("Seq. löschen"); 
...
panel[RIGHT_I].add(button[1]);
Dort wird jetzt am Ende der "Seq. Löschen" button zum Panel hinzugefügt. Wenn nun irgendwann zwischen "Hinzufügen" und "Seq. Löschen" ein weiterer Button eingefügt werden soll (oder der "Hinzufügen"-Button gelöscht werden soll) musst du
1. Die final-Konstanten anpassen (SEHR unübersichtlich!)
2. Die Array-Größen anpassen
3. Die Indizes bei allen Zugriffen wie "button[1]" ändern - aber wie? Da ist Chaos vorprogrammiert.

Üblicherweise benennt man die Components explizit, also z.B.

private JButton addButton;
private JButton deleteButton;
....

Bei solchen Sachen wie den RGB-Spinnern kann man natürlich einen Array verwenden

private JSpinner rgbSpinners[] = new JSpinner[3];

Wenn dadurch "zu viele" Components auf einer anderen liegen, sollte man sich über eine Gruppierung Gedanken machen. Was da sinnvoll ist, muss derjenige Wissen, der das ganze schreibt. Aber vielleicht sowas wie
Code:
class TilePropReader
{
    private ControlPanel controlPanel;
    private ColorsPanel colorsPanel;
...
}

class ControlPanel
{
    private JButton addButton;
    private JButton deleteButton;
    ...
}

private ColorsPanel
{
    private JSpinner rgbSpinners[] = new JSpinner[3];
    ...
}
aber das muss man sich dann halt überlegen....
 
S

SenioreFamicom

Gast
Das mit getScaledInstance ist ganz nett. Also tust du von Graphics2D abraten?
Habe jetzt alles im Konstruktor eingebaut (Img laden, MediaTracker & Skalierung), trotzdem will der nicht so ganz beim Initialisieren der Image im JScrollPane auf Anhieb alles anzeigen:

So sieht es aus, wenn das Fenster geöffnet wird (der untere Teil fehlt):
state1.jpg


Scrollt man ein Stück weiter:
state2.jpg


Scrollt man wieder zurück, wird alles (wie es sein sollte) angezeigt:
state3.jpg



Der neue Code:
Code:
package SN32.Editor.LowClass;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import javax.swing.JPanel;


public class KBitmap extends JPanel {
    private int     scaleXY = 2;
    private int     width   = 480;
    private int     height  = 256;
    private Image   img;
    
    public KBitmap() {
        img = getToolkit().getImage("C:/Games/Sprites/Harvest Moon/hmkuhstall.png");
        img = img.getScaledInstance(480*2, 256*2, 1);
        MediaTracker mTracker = new MediaTracker(this);
        mTracker.addImage(img, 0);
        
        try {
            mTracker.waitForAll();
        } catch (InterruptedException exc) {
            
        }
        setPreferredSize(new Dimension(480*2, 512));
        setMinimumSize(new Dimension(480*2, 512));
        this.setLayout(null);
        this.setSize(this.width * this.scaleXY, this.height * this.scaleXY);
        this.setLocation(0, 0);
        this.setVisible(true);
    }
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, this);
    }
   
    public int getScaleXY() {
        return this.scaleXY;
    }
    public int getWidth() {
        return this.width;
    }
    public int getHeight() {
        return this.height;
    }
}
 

Marco13

Top Contributor
Aaaaaaaaaahhhhhhh.... Jetzt hab ich bestimmt ne Stunde übelst rumprobiert, gesucht, verändert, Code von JScrollPane und JViewPost gelesen, drawModes und ClipBound gesetzt und bis zum Erbrechen debug-Ausgaben eingebaut ... um dann zu merken, dass du lügst :wink: Er zeichnet natürlich nur das, was er zeichnen muss. Und er muss nur das KBitmap zeichnen. Und das KBitmap hat eine feste Größe von 480 * 256 Pixeln. (Wenn ich das nicht die ganze Zeit in TextPad, sondern in einer IDE gemacht hätte, wäre es mir durch die farbige Hervorhebung vielleicht schon früher aufgefallen :roll: ). Also .. du hast (absichtlich? Oder versehentlich?) die getWidth/getHeight-Methoden in der KBitmap überschrieben - daher hat er am Anfang immer zu wenig gezeichnet..... :idea:
 
S

SenioreFamicom

Gast
Verzeih mir xD Ich habe es mittlerweile auch bemerkt. Es war versehentlich. Mit zunehmenden Quellcode verlier ich sehr schnell die Übersicht ?___? und übersehe manchmal primtive Fehler.
Auch ein Grund warum ich die Komponenten in Arrays mit markanten Konstanten-Name zusammenfasse.
Übrigens, da ich die Komponenten nicht einzeln abändern, lösche, etc. werde (und wenn dann das ganze Fenster dispose), sind die Performance-Probleme nicht weiter diskutabel, oder?

Trotzdem danke für deine Bemühungen ;)

Das Ding hier kann geschlossen werden.
 

Marco13

Top Contributor
Hmja, was heißt die Übersicht: Man muss erstmal den kausalen Zusammenhang herstellen, zwischen den überschriebenen width/height-Methoden, und dem SEHR seltsamen paint-Verhalten, das damit bewirkt wurde....

Performance? Das mit den Variablennamen bezog sich auf die Übersichtlichkeit. Und das mit den Skalieren ... schon auf die Peformance ... wobei es bei einer ScrollPane, die nur ein Bild anzeigt, nicht so kritisch wäre, wie etwa später in einem Tile-based game oder so.

SenioreFamicom hat gesagt.:
Also tust du von Graphics2D abraten?
Das hatte ich nocht nicht beantwortet: Nein, davon abzuraten macht keinen Sinn. Bestimmte Sachen gehen einfach nur (vernünftig) mit Graphics2D. In diesem speziellen Fall war aber das skalieren nicht notwendig (dass man dann auch nichtmehr auf Graphics2D casten muss, ist nur ein Kollateraleffekt...)
 
S

SenioreFamicom

Gast
Okay, aber noch eins:
Ich möchte jedes Tile mit einer kleinen Fußnummer versehen. Soll ich über jedes ein JLabel drüberlegen oder mit g.drawString()? Das Problem ist, dass 480*256 JLabels doch recht viel sind.
 
S

SenioreFamicom

Gast
PS: Außerdem soll bei Mausklick auf ein Tile eine primitive Grafik (Rechteckt) drüber gelegt werden :/
 

Marco13

Top Contributor
Wenn es nur um ein bißchen Text an einer bestimmten Stelle geht, solltest du auf jeden Fall g.drawString verwenden. Abgesehen davon: Von 480*256 tiles wird ja nur ein verschwindend kleiner Bruchteil gezeichnet.

Wenn (durch skalierung) alle Tiles gleichzeitig sichtbar sind, ist das drawString zwar auch langsam, aber 1. Kann man den Text dann eh nichtmehr lesen, 2. Wäre es mit Labels noch VIEL langsamer, und 3. braucht der Text vermutlich zumindest weniger Zeit, als die Tiles selbst...
 
S

SenioreFamicom

Gast
Macht es denn Sinn, eine neues (temporär existierendes) Image anzulegen, in der das alte skalierte Image reinkopiert wird und ein String drübergemalt wird, sodass dieses angezeigt werden kann? Wenn ja, wie lässt sich das realisieren?
Problem ist eben auch, dass über diverse Tiles auch noch 32x32 große Images per Mausklick drübergelegt werden können. Gibt es nicht Möglichkeiten das so umzusetzen, dass der Rechner dabei nicht in die Knie geht?
 

Marco13

Top Contributor
Hm :? möglich - bisher ging es um EIN Bild in einer ScrollPane - wie komplex das ganze noch werden soll (also was noch alles gemacht werden können soll) weiß man ja jetzt erstmal nicht - darum ist es auch schwer, zu sagen, WAS man WIE am günstigsten macht. Als Beispiel: Wenn man das Bild frei zoomen will (mit dem Mausrad zum Beispiel) dann würde man vermutlich NICHT getScaledInstance bei jedem Zoom-Schritt aufrufen usw. Wenn du jetzt noch einzelne Tiles ... "aufwerten" willst (mit irgendwelchen Markierungen und Text) wirst du dir sowieso über eingie Datenstrukturen Gedanken machen müssen - im Moment hast du ja EIN Bild, ohne irgendwelche Informationen, wo darin welche Tiles (und welche Markierungen) liegen. Ob diese Markierungen später dann das Bild verändern sollen, oder nur rein Informativ angezeigt werden, oder in eine "Level-Datei" oder so geschrieben werden sollen ist auch alles nicht klar, hat aber evtl. Einfluß darauf, was die günstigste Lösung wäre....

Also... Text oder ein kleines Rechteck könnte mit drawString bzw. drawRect gemacht werden. Ggf. würde das dann nicht direkt in der KBitmap-Klasse gemacht werden, sondern vielleicht in einer "Tile"-Klasse.... (wer weiß...? :wink: )

Macht es denn Sinn, eine neues (temporär existierendes) Image anzulegen, in der das alte skalierte Image reinkopiert wird und ein String drübergemalt wird, sodass dieses angezeigt werden kann?
Das KANN Sinn machen ... insbesondere, weil Text Zeichnen ziemlich aufwändig ist. Allerdings ist der Aufwand, sie in ein neu angelegtes Bild reinzumalen, und nachher dieses neue Bild zu malen, erstmal größer, als sie einfach nur "on the fly" von der paintComponent aus zu malen. Wenn der Text also nur einmal (oder "selten") neu gezeichnet wird, lohnt sich sowas vielleicht, ansonsten eher nicht...

Wenn ja, wie lässt sich das realisieren?

Eigentlich ganz einfach:
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(theImage);
g.drawString("Hello",200,200);

Dieses BufferedImage (mit dem anderen Image und dem Text drauf) kann man dann in der paintComponent zeichnen.
 
S

SenioreFamicom

Gast
Okay, das klingt schonmal alles gut und hilft mir auch weiter.
Und um mal das Verständis zu erweitern:
- Die Nummerierung soll einmal getätigt werden. Diese müssen auch nicht verändert werden während des Programms.
- Das Rechteck hingegen ist variabel von der Position (ein Auswahlrechteck eben).
- Genauso die kleinen Images welche über einzelne Tiles drüber gelegt werden können.
- Eine Zoom-Fkt. habe ich in dem fenster nicht geplant.
- Das Fenster dient auch nur um irgendwelche Voreinstellungen für das Tileset vorzunehmen. An sich soll nach disposen des Fensters das Tileset eh gesplittet werden und jedes Tile bekommt die zugewiesenen Eigenschaften aus dem TilePropEditor ausgehändigt.

Da fällt mir spontan ein, ob man vielleicht schon in diesem Fenster das Tileset in die einzelnen Tiles splitten soll, jedes einzelne von JComponent ableitet, die Eigenschaften jetzt schon in die Tileklasse schreibt und alle auf ein JPanel platziert oder so wie es bisher geplant war, d.h. erstmal die ganze KBitmap laden und alle 32x32 Felder bei Bedarf Eigenschaften festlegt, die beim disposen des Fensters erst den Tiles zuteilt.
Also letztlich zielt die Frage darauf ab, ob mein Programm nicht im Schneckentempo rattert, wenn ich soviele einzelne Tiles für den Editor einführe. Nach schließen des Fenster wollte ich eh die Tiles alle seperat als JComponent, da doch zu viele Eigenschaften unterzubringen sind. Oder wäre es besser, die KBitmap überhaupt nicht zu splitten, für jede Eigenschaft ein Array mit [Bitmapbreite/32][Bitmaphöhe/32] Elemnten anzulegen? Also z.B.

boolean [][] enableTile = new boolean[Bitmaphöhe/32][Bitmapbreite/32];

int [][] flag1 = new int[Bitmapbreite/32][Bitmaphöhe32];
int [][] flag2 = ...

usw.

Die Tiles der Bitmap werden dann im eigentlichen Editor in Abhängigkeit der Cursorposition mit seiner Breite(32, 32) einfach nur aus der Bitmap rauskopiert.

Eigentlich sollten primitive Datentypen weit weniger Speicher beanspruchen, aber nimmt es sich letztlich so viel, wenn bei der Menge alle Tiles in einzelne JComponent-Ableitungen überführt werden? Wenn nein, kannst du abschätzen, ab welchen Mengen von Tiles das kritisch werden könnte?

^^ ohje, soviele Fragen xD
 

Marco13

Top Contributor
Hm... also vorneweg: Ich würde NICHT Tile von JComponent erben lassen. Abgesehen davon, dass eine JComponent schon verdammt viel "unnötigen Mist" enthält (eine Auflistung hatte ich mal hier http://www.java-forum.org/de/viewtopic.php?p=401548 im zweiten Beitrag gepostet), würde ich ggf. eher eine Klasse "Tile" erstellen, die NUR das enthält, was ein Tile ausmacht. Damit wäre auch deine Frage nach den Arrays beantwortet: Man würde sicher NICHT sowas machen wie

boolean [][] enableTile = new boolean[Bitmaphöhe/32][Bitmapbreite/32];
int [][] flag1 = new int[Bitmapbreite/32][Bitmaphöhe32];
int [][] flag2 = ...

sondern eben eine Klasse
Code:
class Tile
{
    private boolean enabled;
    private int flag1;
    private int flag2;
    ...
}
und dann einen
Tile tiles[][] = new Tile[Bitmaphöhe/32][Bitmapbreite/32];
anlegen.

Man könnte dann in den Tiles auch eine Methode anbieten wie
public void draw(Graphics g) { ... }
die das jeweilige Tile malt. WAS dort gemalt wird, bleibt dann den Tile überlassen. Es gäbe da verschiedene Strategien, z.B.

- Es gibt eine Klasse "TileMap" (wie deine KBitmap), die EIN großes Bild enthält. Die Tiles bekommen eine referenz auf dieses Bild übergeben, und "ihre" koordinaten. Sie malen dann in ihrer draw-Methode "ihren" Teil des Bildes

- Eine andere (vmtl. bessere) Möglichkeit (die IMHO recht naheliegend ist) könnte sein, den Tiles nur ihren Bildausschnitt als kleines 32x32-BufferedImage zu übergeben. Ggf. können sie dort dann auch "ihre" Zahlen reinmalen, so dass die dann sehr effizient angezeigt werden können. Die "Veränderlichen" Dinge (wie Markierungen) könnten dann in der tile.draw(...) Methode "on the fly" mit g.drawRect usw. gemalt werden.

Es gibt sicher noch 1000 andere Möglichkeiten. Welche davon am günstigsten ist, muss man sich halt überlegen.

So eine Tile-Klasse würde ich dir aber auf jeden Fall empfehlen. Die fasst einfach und praktisch alle Informationen zusammen, die für ein Tile relevant sind, und kann dann zum Beispiel(!) auch solche Methoden anbieten wie
public String createTheStringThatWillBeWrittenToTheFileForThisTile() { ... }
falls du sowas brauchst....
 
S

SenioreFamicom

Gast
... und tile.draw(Graphics g) in (z.B.) TileMap innerhalb der paint aufrufen? Wenn ich Sequenzen definiere, muss ich update(Graphics g) in der Klasse Tiles oder TileMap oder im Fenster implementieren?

sry, wenn ich ständig so noob-Fragen stellen muss xD An sich komme ich halbwegs klar. Aber irgendwie kann ich mich mit den paint-Angelegenheiten nicht ganz anfreunden. Vielleicht habe ich immer einen falschen Vorstellungsansatz was das Überschreiben angeht...
 

Marco13

Top Contributor
.. und tile.draw(Graphics g) in (z.B.) TileMap innerhalb der paint aufrufen?

Irgendwo von der paintComponent-Methode aus... z.B.
Code:
class TileMapPanel
{
     private TileMap tileMap = ...

     public void paintComponent(Grpahics g)
     {
        super.paintComponent(g);
        tileMap.draw(g);
     }
}

class TileMap
{
    private Tile tiles[][] = ...

    public void draw(Gaphics g)
    {
        for (alle tiles) tile.draw(g);
        zeichneNochMarkeirungenUndSo(g);
    }
}

class Tile
{
    public void draw(Gaphics g)
    {
         g.drawImage(...);
        zeichneNochMarkeirungenUndSo(g);
    }
}
(nur zur Verdeutlichung)

Wenn ich Sequenzen definiere, muss ich update(Graphics g) in der Klasse Tiles oder TileMap oder im Fenster implementieren?
:bahnhof: Sequenzen? Hm. Mit Swing hat man mit der Methode "update(Graphics g)" i.a. NICHTS mehr zu tun. Oder meintest du irgendeine eigene Methode (die dann besser NICHT update(Graphics g) heißen sollte .... versehentlich Methoden zu überschreiben, kann verheerende Auswirkungen haben :wink: )
 
S

SenioreFamicom

Gast
Ja, Tilesequenzen (=Tileanimationen, Hintereinanderschaltung mehrerer Tiles) :)
Wenn es unkomplizierter ist, gibt es Möglichkeiten gif's zu erstellen?
 

Marco13

Top Contributor
Ja, falls es da eine Frage gibt, musst du sie stellen. Ob/wie man ein Animiertes GIF erstellt, kannst über websuche (oder ggf. in einem eigenen Thread) erfragen.
 
S

SenioreFamicom

Gast
Ok, jetzt muss ich dich nochmal heranziehen :oops:
Ich habe das mal so umgesetzt wie von dir beschrieben, allerdings sind die Ladezeiten des JTilePropReaders bei 4 dargestellten Tiles enorm (3 - 4 Sekunden).

Der aktuelle Code:

Code:
package SN32.Editor.TabTile;

import java.awt.Graphics;
import java.awt.Image;
import java.util.Vector;

class Proporties {
    public boolean      enabled     = true;
    public int          ID;
    public int          scale       = 2;
    public int          seqCounter  = 0;
    public int          tileSize    = 16;
    public int          x, y;
    public Image        img         = null;
    public Vector<Tile> sequence    = new Vector();    
}

public class Tile extends Proporties {    
    private Proporties prop = new Proporties();
    
    public Tile(Image img, int ID) {
        this.ID     = ID;
        this.img    = img;
    }
    
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
    public void setLocation(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void reset() {
        this.enabled    = true;
        this.scale      = 2;
        this.seqCounter = 0;
        this.tileSize   = 16;
        this.img        = null;
        this.sequence.clear();
    }
    public void draw(Graphics g) {
        if (img != null) {
            g.drawImage(img, x, y, null);
            g.drawString("" + ID, x, y);
        }
    }
}

Code:
package SN32.Editor.TabTile;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

public class TileMap {
    private int         cnt     = 0;
    private int         height;
    private int         width;
    private Tile [][]   tile;
    
    public TileMap(File f) {
        try {
            this.height = ImageIO.read(f).getHeight() / 16;
            this.width  = ImageIO.read(f).getWidth () / 16;
        } catch (IOException ex) {
            System.out.println("ERR");
        }
        tile = new Tile[this.width+1][this.height+1];
        BufferedImage bufImg = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
        for (int y = 0; y < this.height; y++) {
            for (int x = 0; x < this.width; x++) {
                try {
                    tile[x][y] = new Tile(ImageIO.read(f).getSubimage(x*16, y*16, 16, 16).getScaledInstance(32, 32, 0), cnt);
                    tile[x][y].setLocation(x*32, y*32);
                } catch (IOException ex) {
                    Logger.getLogger(TileMap.class.getName()).log(Level.SEVERE, null, ex);
                }
                cnt++;
            }
        }
    }
    
    public void draw(Graphics g) {
       tile[0][0].draw(g);
       tile[0][1].draw(g);
       tile[0][2].draw(g);
       tile[0][3].draw(g);
    }
}

Code:
package SN32.Editor.LowJClass;

import SN32.Editor.TabTile.*;
import java.awt.Graphics;
import java.io.File;
import javax.swing.JPanel;

public class JTileMapPanel extends JPanel {
    private TileMap tileMap = null;
    
    public JTileMapPanel(File f) {
        tileMap = new TileMap(f);
        setVisible(true);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (tileMap != null) {
            tileMap.draw(g);
        }
    }
    
}
 

Marco13

Top Contributor
Du hast also erkannt, dass man das ImageIO.read(f) nur EINmal machen sollte, und nicht width*height = 20000 mal :wink:
 
S

SenioreFamicom

Gast
Nochmals vielen Dank. Hat mir einiges geholfen was ich auch in Zukunft gut verwerten kann ;)
 
S

SenioreFamicom

Gast
Okay, es lahmt trotzdem :x verflixt. Liegt das an swing? Vielleicht räume ich den Müll nicht auf?!?: Werden denn in einer Klasse, die mit dispose geschlossen wird, auch die inneren Variablen, die ich in der Klasse einführte, aus dem Speicher geschmissen? Habe jetzt eine Mausabfrage in JTilemapPanel installiert, die ein Popup öffnet. Die Verzögerung liegt bei einer bis zwei Sekunden. Muss man mit sowas in swing leben oder sollte das eigentlich nicht so sein? ???:L
 

Marco13

Top Contributor
Am besten mal alles so zusammen klatschen, dass man es einfach mit Copy&Paste hier rauskopieren und compilieren kann, dann kann man vielleicht den Grund finden.
 

Marco13

Top Contributor
Hm. Das System.gc sollte man i.a. nicht per Hand aufrufen. Eine 2-Sekunden-Verzögerung ..? Das Popup mit "Bearbeiten" und "Enabed" geht bei mit sofort und ohne Verzögerung auf...?! Das meintests du?
 
S

SenioreFamicom

Gast
Hm... Dann liegt es an meiner mieserablen Rechnerleistung. Das System.gc() habe ich nur testweise aufgerufen, um zu sehen, ob das was ändert. Gibt es sonst noch Dinge, die ich beachten soll (von dem was vorliegt), die die Perfomance erhöhen?
 

Marco13

Top Contributor
Hab natürlich nicht alles gelesen, aber Performancetechnisch ist mir da jetzt nichts ins Auge gesprungen. Eher strukturell (public fields, "interface inheritance" (die Constants), teilweise etwas unübersichtlich....) aber naja...
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
volcanos Scrollen: JScrollPane mit Graphics g und Java-Fonts extends Frame ? AWT, Swing, JavaFX & SWT 5
E JScrollPane mit JPanel verbinden AWT, Swing, JavaFX & SWT 1
B Swing JScrollPane scrollt nicht AWT, Swing, JavaFX & SWT 10
P JTextarea (in JScrollPane) zeigt nur die beiden letzten Einträge an? AWT, Swing, JavaFX & SWT 0
O Swing "Eigenes" JPanel wird dem JScrollPane nicht hinzugefügt AWT, Swing, JavaFX & SWT 5
E Komponenten von JScrollPane werden nicht richtig ermittelt AWT, Swing, JavaFX & SWT 2
E wie in JScrollPane auf JTextArea zugreifen AWT, Swing, JavaFX & SWT 12
N Swing JScrollPane mit Tastatur bedienen? AWT, Swing, JavaFX & SWT 0
F JScrollPane anzeige AWT, Swing, JavaFX & SWT 7
K Swing JScrollPane wird nicht angezeigt wenn man Components darstellt. AWT, Swing, JavaFX & SWT 2
M Swing JPanel in JScrollPane AWT, Swing, JavaFX & SWT 3
M Problem mit Add JScrollPane AWT, Swing, JavaFX & SWT 25
P Swing JEditorPane in Kombination mit JScrollPane AWT, Swing, JavaFX & SWT 29
S Swing jScrollPane - pro Eintrag der Liste, die jCheckBoxes Speichern die in dem Eintrag aktiviert wurden AWT, Swing, JavaFX & SWT 2
T Swing Probleme mit repaint() bzw. JScrollPane AWT, Swing, JavaFX & SWT 7
D JScrollPane in JTabbedPane AWT, Swing, JavaFX & SWT 3
MaxG. Swing JScrollPane AWT, Swing, JavaFX & SWT 10
Soloeco Swing JScrollPane AWT, Swing, JavaFX & SWT 6
A Swing Probleme mit dem adden von JButtons zur JScrollPane AWT, Swing, JavaFX & SWT 2
A JScrollPane soll JPanel mit JButtons enthalten und eine Scollbar anzeigen AWT, Swing, JavaFX & SWT 1
J JScrollPane funktioniert nicht AWT, Swing, JavaFX & SWT 5
B LayoutManager GridBagLayout und JScrollPane AWT, Swing, JavaFX & SWT 5
Thallius JScrollPane Scrollpos setzen nach Neuzeichnen AWT, Swing, JavaFX & SWT 3
P MalProgramm mit JScrollPane und Canvas AWT, Swing, JavaFX & SWT 2
D Swing JScrollPane Tabelle ändern (2 Tabellen) AWT, Swing, JavaFX & SWT 7
U JScrollPane -> JTabbedPane u.A. AWT, Swing, JavaFX & SWT 3
A Layout-Manager, JScrollPane, ... Chaos AWT, Swing, JavaFX & SWT 5
V JScrollPane im zur Laufzeit verändernden JFrame AWT, Swing, JavaFX & SWT 0
W Swing Größenänderung vom JPanel im JScrollPane und anschließendes positionieren AWT, Swing, JavaFX & SWT 2
X Swing JButton's zum JScrollPane hinzufügen geht nicht. Bitte um Hilfe. AWT, Swing, JavaFX & SWT 9
G JTextArea mit JScrollPane wird nicht angezeigt AWT, Swing, JavaFX & SWT 2
K Swing JScrollPane - JScrollBar anzeigen, wenn Frame verkleinert wird AWT, Swing, JavaFX & SWT 3
N Swing Problem beim Scrollen mit JScrollPane AWT, Swing, JavaFX & SWT 6
Bluedaishi JScrollpane AWT, Swing, JavaFX & SWT 0
L JScrollPane scrollt nicht !! AWT, Swing, JavaFX & SWT 3
F JScrollPane Position setzen (x=0, y=0) AWT, Swing, JavaFX & SWT 2
R JScrollPane überdeckt JPanel? AWT, Swing, JavaFX & SWT 7
H JTree in JScrollPane passt sich nicht an Größe von JPanel an AWT, Swing, JavaFX & SWT 2
S JScrollPane und BorderLayout AWT, Swing, JavaFX & SWT 1
M Mehrere Jpanel in einem JScrollPane (Layout) AWT, Swing, JavaFX & SWT 2
W Swing JScrollPane für mein Fenster AWT, Swing, JavaFX & SWT 4
A Swing Probleme mit JScrollPane AWT, Swing, JavaFX & SWT 6
F JTable mit JScrollPane AWT, Swing, JavaFX & SWT 4
I JPanel in JScrollPane verkleinert sich leider nicht .... AWT, Swing, JavaFX & SWT 2
G JScrollPane bricht am Ende der Anzeige nicht um AWT, Swing, JavaFX & SWT 2
J Swing JTextPane mit JScrollPane auf JPanel scrollen nicht AWT, Swing, JavaFX & SWT 6
W Sichtbarer Bereich JScrollPane vs. JList AWT, Swing, JavaFX & SWT 3
B Swing JPanel in JScrollPane einfügen AWT, Swing, JavaFX & SWT 2
S 2D-Grafik Transparentes JScrollPane AWT, Swing, JavaFX & SWT 0
S 3D-Grafik 3d Grafik auf einem JPanel oder im JScrollPane AWT, Swing, JavaFX & SWT 1
R Ändern Default-Verhalten von JScrollpane in einer JScrollpane AWT, Swing, JavaFX & SWT 1
S JScrollPane --> Programm hängt sich beim scrollen auf AWT, Swing, JavaFX & SWT 2
A JScrollPane - ScrollBar Buttongröße verändern AWT, Swing, JavaFX & SWT 1
J Bilder auf JPanel (im JScrollPane) nacheinander laden AWT, Swing, JavaFX & SWT 0
A Swing JScrollPane Problem AWT, Swing, JavaFX & SWT 6
H Swing JScrollPane mit "viel Inhalt" scrollt zu langsam (inkl. See-For-Yourself.jar :D) AWT, Swing, JavaFX & SWT 2
T Swing JScrollPane in JPanel - Breite dynamisch, Höhe fix - wie? AWT, Swing, JavaFX & SWT 2
D Swing JScrollPane in JScrollPane - Problem AWT, Swing, JavaFX & SWT 3
K Bug in JScrollPane? AWT, Swing, JavaFX & SWT 4
T Swing JScrollPane Farbe der Scrollbar AWT, Swing, JavaFX & SWT 3
M JScrollPane Header AWT, Swing, JavaFX & SWT 3
G JScrollPane über JScrollPane AWT, Swing, JavaFX & SWT 2
V LayoutManager JScrollPane verwirft Elementanordnung AWT, Swing, JavaFX & SWT 3
B JScrollPane Problem AWT, Swing, JavaFX & SWT 2
D Swing JScrollPane AWT, Swing, JavaFX & SWT 7
H cardlayout und jscrollpane AWT, Swing, JavaFX & SWT 14
F 2D-Grafik Skalieren der Scrollbars beim Zoomen einer JScrollPane AWT, Swing, JavaFX & SWT 4
B JScrollPane Horizontal klappt nicht. AWT, Swing, JavaFX & SWT 4
G JScrollPane reagiert nicht auf Änderung der JPanel-Größe AWT, Swing, JavaFX & SWT 4
C jPanel auf jScrollPane zentrieren AWT, Swing, JavaFX & SWT 3
M Swing JScrollPane (Parent JTextArea) aktualisieren + neue Zeile AWT, Swing, JavaFX & SWT 5
U Swing JPane und JScrollpane in JSplitpane-Seite: Scrollen funktioniert nicht AWT, Swing, JavaFX & SWT 3
A Swing Korrekte JTable.rowAt(point) für JTable in JScrollPane AWT, Swing, JavaFX & SWT 5
D Label über JScrollPane AWT, Swing, JavaFX & SWT 3
S JScrollPane reagiert nicht AWT, Swing, JavaFX & SWT 3
X JScrollPane zu JTable hinzufügen AWT, Swing, JavaFX & SWT 16
H JScrollPane - JEditorPane und HTML-Tabelle AWT, Swing, JavaFX & SWT 2
D LayoutManager JScrollPane mit dynamischem Inhalt AWT, Swing, JavaFX & SWT 8
P Swing JScrollpane AWT, Swing, JavaFX & SWT 2
B JScrollPane scrollt nicht immer automatisch AWT, Swing, JavaFX & SWT 2
V Swing JScrollPane Viewport verschieben AWT, Swing, JavaFX & SWT 2
J JScrollPane Probleme AWT, Swing, JavaFX & SWT 3
S Swing JScrollPane verliert Scrollbars AWT, Swing, JavaFX & SWT 5
D Swing JTable in JScrollpane beliebig verbreitern AWT, Swing, JavaFX & SWT 5
A Swing Anzeige Text in JScrollpane AWT, Swing, JavaFX & SWT 8
J Swing Unteren Abstand für JTable in JScrollPane festlegen AWT, Swing, JavaFX & SWT 10
xehpuk Swing Line-wrapping von JTextPane (in JScrollPane) AWT, Swing, JavaFX & SWT 3
M JScrollPane Problem AWT, Swing, JavaFX & SWT 6
S Swing JScrollpane und ViewPort AWT, Swing, JavaFX & SWT 4
D JScrollPane funktioniert nicht AWT, Swing, JavaFX & SWT 12
X JScrollPane funzt net... AWT, Swing, JavaFX & SWT 5
H jscrollpane AWT, Swing, JavaFX & SWT 12
RELAXccc Swing JTree + JScrollPane, refresh Problem AWT, Swing, JavaFX & SWT 17
A Problem mit JScrollPane in einer JScrollpane AWT, Swing, JavaFX & SWT 4
B JScrollPane Problem AWT, Swing, JavaFX & SWT 25
T Swing JScrollPane- und Tabelle-Header Problem AWT, Swing, JavaFX & SWT 25
P Swing JScrollPane-Inhalt: Grösse anpassen AWT, Swing, JavaFX & SWT 6
G Swing Höhe des View eines JScrollPane fest auf Höhe des JScrollPane setzen! AWT, Swing, JavaFX & SWT 4
A JScrollPane AWT, Swing, JavaFX & SWT 16
C Swing JScrollPane und Scroll-Geschwindigkeit AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen

Neue Themen


Oben