Java >> Java tutorial >  >> Java

Hvordan får man JScrollPane til dynamisk at rulle til slutningen efter tilføjelse af komponenter?

Her er min kode til ScrollPane

    public class CustomScrollPane extends JScrollPane {

    private static CustomScrollPane instance = null;

    public CustomScrollPane () {
        super(panel.getInstance()); // a panel that the scrollpane wraps around
        this.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        // hide the vertical scroll bar
        this.getVerticalScrollBar().setPreferredSize(new Dimension(0, 0));
    }

    public static CustomScrollPane getInstance() {
        if (instance == null)
            instance = new CustomScrollPane ();
        return instance;
    }

Jeg prøvede at gøre getVerticalScrollbar.setValue(getVerticalScrollbar().getMaximum()) men det ruller ikke til slutningen, når jeg tilføjer JLabels til det. Jeg forsøger at gøre det, så det altid vil rulle til bunden af ​​skærmen, når en ny JLabel bliver tilføjet til panelet. Jeg bruger ikke JTextArea, da jeg ønsker, at hver linje skal have en anden forgrundsfarve, så jeg brugte JLabels.

Jeg prøvede også at tilføje denne metode

public void scrollToBottom() { getVerticalScrollbar().getMaximum(); }

men det fryser bare ScrollPane, og jeg kan ikke rulle.

Enhver hjælp ville blive værdsat!

Svar

Jeg er ikke sikker på, hvad du håber at opnå ved at forlænge JScrollPane , ikke sikker på, at det virkelig er dens kerneansvar, trods alt kunne du få dens "viewport view" til at gøre det selv, for eksempel...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            JPanel contentPane = new JPanel(new GridLayout(-1, 8));
            for (int index = 0; index < 1000; index++) {
                contentPane.add(new SqaurePane());
            }
            add(new JScrollPane(contentPane));

            JButton top = new JButton("Top");
            JButton bottom = new JButton("Bottom");

            JPanel actionPane = new JPanel();
            actionPane.add(top);
            actionPane.add(bottom);

            add(actionPane, BorderLayout.SOUTH);

            top.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    contentPane.scrollRectToVisible(new Rectangle(0, 0, 1, 1));
                }
            });
            bottom.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    contentPane.scrollRectToVisible(new Rectangle(0, contentPane.getHeight(), 0, 0));
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }

    static List<Color> COLORS = new ArrayList<>(Arrays.asList(new Color[] {
        Color.BLACK,
        Color.BLUE,
        Color.CYAN,
        Color.DARK_GRAY,
        Color.GRAY,
        Color.GREEN,
        Color.LIGHT_GRAY,
        Color.MAGENTA,
        Color.ORANGE,
        Color.PINK,
        Color.RED,
        Color.WHITE,
        Color.YELLOW,
    }));

    public class SqaurePane extends JPanel {

        public SqaurePane() {
            Collections.shuffle(COLORS);
            setBackground(COLORS.get(0));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(50, 50);
        }        
    }
}

Magien er lige her...

top.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        contentPane.scrollRectToVisible(new Rectangle(0, 0, 1, 1));
    }
});
bottom.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        contentPane.scrollRectToVisible(new Rectangle(0, contentPane.getHeight(), 0, 0));
    }
});

Her spørger jeg contentPane (som er beholderen, der indeholder alle firkanterne) for at "rulle til et synligt rektangel" baseret på mine behov

Nu, i dit tilfælde, når du tilføjer en ny komponent til "beholderen", skal du instruere komponenten til at rulle til en position, der viser den nye komponent.

Dette bliver lidt mere kompliceret, da du først skal udløse et layoutpas, så du kan få den nye størrelse af containeren

Dynamisk tilføjelse til beholderen...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            JPanel contentPane = new JPanel(new GridLayout(-1, 8));
            add(new JScrollPane(contentPane));

            for (int index = 0; index < 8 * 8; index++) {
                contentPane.add(new SqaurePane());
            }

            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    SqaurePane sqaurePane = new SqaurePane();
                    contentPane.add(sqaurePane);
                    contentPane.revalidate();
                    // There is an issue with how the layout pass runs, this 
                    // "seems" to be getting pushed onto the EDT later, which
                    // is messing up the scroll logic.
                    // So, instead, we push this on to the EDT to be executed
                    // "later" after the layout pass has run.  Yes, I tried
                    // calling doLayout directly, but, for the first element
                    // of each row, it wouldn't work correctly
                    EventQueue.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            contentPane.scrollRectToVisible(new Rectangle(0, sqaurePane.getY(), 1, sqaurePane.getHeight()));
                        }
                    });
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }

    static List<Color> COLORS = new ArrayList<>(Arrays.asList(new Color[]{
        Color.BLACK,
        Color.BLUE,
        Color.CYAN,
        Color.DARK_GRAY,
        Color.GRAY,
        Color.GREEN,
        Color.LIGHT_GRAY,
        Color.MAGENTA,
        Color.ORANGE,
        Color.PINK,
        Color.RED,
        Color.WHITE,
        Color.YELLOW,}));

    public class SqaurePane extends JPanel {

        public SqaurePane() {
            Collections.shuffle(COLORS);
            setBackground(COLORS.get(0));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(50, 50);
        }
    }
}

Hvis du virkelig ville afkoble konceptet, kunne du bruge en ContainerListener og reagere på den nye komponent, der er blevet tilføjet via den


Java tag