# Nur den Bereich des JPanels zeichen der im Viewport des JScrollPane angezeigt wird



## stKev (16. Aug 2012)

Hi,

ich bin auf der Suche nach einem guten Beitrag, wie ich das im Titel gegannte Problem lösen kann.
Falls es so eine Beitrag hier schon im Forum gibt, habe ich ihn leider über die Suchfunktion nicht gefunden.
Bin schon relativ weit mit meinem Map-Editor, nur ab einer Rastergröße von 1000x1000 wird es doch recht laggy.  Das Raster ist ein Rectangle[][].
Wenn ich dort nun noch Objekte, die alle Bilder enthalten, einfüge. Ja dann gute Nacht.
Kennt jemand einen guten Beitrag zu dem Problem, wo ich mich ein wenig einlesen kann? :rtfm:

LG Kevin


----------



## SlaterB (16. Aug 2012)

ich möchte in erste Linie das Stichwort 'Clipping' einbringen, falls noch nicht bekannt
Clipping (Computergrafik) ? Wikipedia

zusammen mit Swing kurz gesucht, Scroll gar nicht extra erwähnt, hier eine Seite die sogar gut passen könnte:
A Scrolly, Clippy Swing Optimization - O'Reilly ONJava Blog


----------



## stKev (16. Aug 2012)

Danke für die schnelle Antwort erstmal. Ich wurd nicht recht fündig bei google. Wusste aber auch nicht wie ich google mein Problem beschreiben sollte.


----------



## stKev (16. Aug 2012)

Ok, habe mir beide Beiträge mal durchgelesen. Bei dem zweiten muss ich gestehen, das mir das wohl zu komplex ist. Aber beim lesen kam mir eine gute Idee, nur bin ich mir da bei einer Kleinigkeit nicht ganz sicher, wie ich das implementiere.


Idee:
Ich erzeuge ein Rectangle, das so groß ist wie der Viewport des JScrollPane, dies soll sich jedoch beim scrollen nicht bewegen. Sonder das Raster und die Objekte auf dem Raster bewegen sich in dieses Rectangle...intersected ein Objekt mit dem großen Rectangle wird es gezeichnet sonst nicht.
Die Abfrage sollte kein Problem sein. Aber das Rectangle, welches sich nicht bewegen soll, da bin ich mir nicht ganz sicher. Hab vorhin noch irgendetwas von einem JGlassPane oder Panel gelesen im Zuge mit JScrollPane. Aber wie kann ich Komponetenkollision auf verschieden Panels abfragen?
Oder jemand eine andere Idee, wie ich das mit dem großen Rectangle machen kann. Damit es sich nicht bewegt?

Ich glaube das Problem besteht mit der Klasse JScrollPane. Habe wohl nicht nicht so richtig verstanden, wie das hinzugfügte JPanel verwaltet wird. Wird es einfach unter dem Viewport hin und hergeschoben?
Hm, JScrollPane war mir von Anfang an unsympatisch, aber vllt wird auch die Klasse noch mein Freund.

Edit:
Konnte nun in Erfahrung bringen wieso es so laggt, die JScrollPane ruft immer wieder repaint(); auf sobald ich 1mm scrolle... In dem Zuge habe ich noch die Methode   Rectangle getViewRect(); von JViewport gefunden. Das müsste doch genau das Rectangle sein, welches ich haben möchte.

Habe es zeichnen lassen, ist es anscheinend nicht, scheint wohl ein Rectangle um dem JPanel zu sein.


----------



## stKev (16. Aug 2012)

Der JViewport scheint das Panel zu sein. Hmmm, ich hatte mir das so erklärt, dass der Viewport der Bereich des JPanels wäre den man grade sieht.


----------



## SlaterB (16. Aug 2012)

JViewport ist nicht direkt das Panel sondern eine eigene Komponente, 
mit Methoden wie getViewPosition() solltest du berechnen können, was vom View, deinem JPanel, zu zeichen ist

JViewport (Java Platform SE 6)

dafür müsstest du aber diese JPanel schon in Originalgröße haben und in paint auch genau an passende Position malen,
scheint mir denkbar,


----------



## stKev (17. Aug 2012)

Die aktuelle Größe könnte ich über das Raster ermitteln. Insofern das JPanel zu Beginn so groß ist wie das JScrollPane und dann durch das Raster "wächst"?

Meinte auch nicht, dass der JViewport das JPanel ist. Sondern eher, dass dieser das JPanel repräsentiert in seiner Größe. Ich hatte bevor ich nun ein wenig darüber gelesen habe, gedacht, dass der JViewport eher den Bereich der derzeit angezeigt wird repräsentiert.

Kann ich nicht irgendwie abfragen, welcher Bereich des Rasters im JScrollPane derzeit angezeigt wird?
Dann hätte ich entweder die Indizes, die gezeichnet werden müssten, oder ich kann vllt irgendwie ein Bereich zeichnen lassen von dem Raster das mit dm Bereich kollidiert.

Oder wie meinst du das? Ich kann mir grade nicht richtig vorstellen wie ich das implementieren soll. Magst du mir vllt ein Ansatz geben? Interessante Probleme die bei so einem WorldEditor anfallen, daran hatte ich vorher gar nicht gedacht. Wobei ich mit repaint(); aufrufen gespart habe 

Nur das JScrollPane meint ja es müsst bei jedem Event repainten...


----------



## Marco13 (17. Aug 2012)

Ein schneller (und ziemlich unschöner) Test, vielleicht hilft's ja


```
package javaforum;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ClipTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new GridLayout(1,0));
        
        JScrollPane scrollPane = new JScrollPane();
        final JPanel panel = new ClipTestPanel(scrollPane);
        scrollPane.setViewportView(panel);
        scrollPane.getViewport().addChangeListener(new ChangeListener()
        {
            
            @Override
            public void stateChanged(ChangeEvent e)
            {
                panel.repaint();
            }
        });
        
        f.getContentPane().add(scrollPane);
        f.setSize(1000,1000);
        f.setVisible(true);
    }
}

class ClipTestPanel extends JPanel
{
    private JScrollPane scrollPane;
    
    ClipTestPanel(JScrollPane scrollPane)
    {
        this.scrollPane = scrollPane;
        setPreferredSize(new Dimension(3000,3000));
    }
    
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Rectangle viewRect = scrollPane.getViewport().getViewRect();
        System.out.println("Paint "+viewRect);
        g.drawString("View rect: "+viewRect, viewRect.x + 15, viewRect.y + 25);
        g.drawRect(viewRect.x + 5, viewRect.y + 5, viewRect.width - 10, viewRect.height - 10);
        
    }
}
```

(Den Effekt, der auftritt, wenn man den ChangeListener wegläßt, kann ich mir im Moment nicht erklären... vermutlich wird das ViewRect nicht rechzeitig vor dem Zeichnen aktualisiert :bahnhof: )


----------



## stKev (17. Aug 2012)

Danke für den kleinen Einblick. Weshalb hast du das JPanel final gesetzt? Was final bedeutet weiß ich. Kann ich die größe des Panels dann nicht mehr verändern bzw. wächst es dann nicht mehr dynamisch mit meinem Raster?

Hm, gebe ich dir Recht, das mit dem weglassen des ChangeListeners ist merkwürdig. Ohne ihn 5 repaint(); Aufrufe mit ihm nur 2. Ok!^^

Habe nun ein wenig rumprobiert. Danke das ist genau was ich gesucht habe. Kann daraus einiges transferieren.


----------

