Swing: создание JScrollPane, отображающего его компонент в центре?

Если вы создаете JScrollPane, у которого окно просмотра больше, чем компонент JScrollPane, оно отображает этот компонент в левом верхнем углу.

Есть ли способ изменить это поведение, чтобы отобразить компонент с центром?

пример программы ниже.


пояснение:

У меня есть компонент, который имеет (ширина, высота) = (cw, ch).

У меня есть JScrollPane с видовым окном, которое имеет (ширина, высота) = (vw, vh).

Компонент может стать больше или меньше. Я хотел бы использовать полосы прокрутки для размещения центральной точки компонента относительно центральной точки просмотра, поэтому, если один или оба размера компонента меньше, чем область просмотра, компонент отображается в центре области просмотра.

По умолчанию поведение прокрутки положено в верхнем левом углу компонента относительно верхнего левого угла окна.

Все, что я прошу, - это изменить контрольную точку. Я не уверен, насколько это легко связано с JScrollPane по умолчанию, поэтому, если это нелегко, тогда я узнаю, что могу, и подумаю о другом подходе.


package com.example.test.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SimpleScroller extends JFrame {
    static class Thingy extends JPanel
    {
        private double size = 20.0;

        @Override public Dimension getPreferredSize() {
            int isize = (int) this.size;
            return new Dimension(isize, isize);
        }
        @Override protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int[] x = {0, 100, 100, 0, 0, 75, 75, 25, 25, 50};
            int[] y = {0, 0, 100, 100, 25, 25, 75, 75, 50, 50};

            Graphics2D g2d = (Graphics2D) g;
            AffineTransform at0 = g2d.getTransform();
            g2d.scale(size/100, size/100);
            g.drawPolyline(x, y, x.length);
            g2d.setTransform(at0);
        }
        public void setThingySize(double size) { 
            this.size = size;
            revalidate();
            repaint();
        }
        public double getThingySize() { return this.size; }
    }

    public SimpleScroller(String title) { 
        super(title);
        final Thingy thingy = new Thingy();
        setLayout(new BorderLayout());      
        add(new JScrollPane(thingy), BorderLayout.CENTER);

        final SpinnerNumberModel spmodel = 
            new SpinnerNumberModel(thingy.getThingySize(),
                10.0, 2000.0, 10.0);
        spmodel.addChangeListener(new ChangeListener() {
            @Override public void stateChanged(ChangeEvent e) {
                thingy.setThingySize((Double) spmodel.getNumber());
            }           
        });
        add(new JSpinner(spmodel), BorderLayout.NORTH);
    }
    public static void main(String[] args) {
        new SimpleScroller("simple scroller").start();
    }
    private void start() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

Ответ 1

  • Поместите a JPanel в область прокрутки
  • Установите макет панели на GridBagLayout.
  • Поместите один компонент в панель без ограничений. Он будет сосредоточен.

Это метод, используемый в Вложенном примере макета, который помещает красное/оранжевое изображение в центр родителя.

RljPH.png

Ответ 2

Я просто добавил JPanel к JScrollPane, к которому я добавил THINGY JPanel. Надеюсь, это то, что вы хотели:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SimpleScroller extends JFrame {
    static class Thingy extends JPanel
    {
        private double size = 20.0;

        @Override public Dimension getPreferredSize() {
            int isize = (int) this.size;
            return new Dimension(isize, isize);
        }
        @Override protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int[] x = {0, 100, 100, 0, 0, 75, 75, 25, 25, 50};
            int[] y = {0, 0, 100, 100, 25, 25, 75, 75, 50, 50};

            Graphics2D g2d = (Graphics2D) g;
            AffineTransform at0 = g2d.getTransform();
            g2d.scale(size/100, size/100);
            g.drawPolyline(x, y, x.length);
            g2d.setTransform(at0);
        }
        public void setThingySize(double size) { 
            this.size = size;
            revalidate();
            repaint();
        }
        public double getThingySize() { return this.size; }
    }

    public SimpleScroller(String title) { 
        super(title);
        final Thingy thingy = new Thingy();
        setLayout(new BorderLayout());  
        JPanel panel = new JPanel();
        panel.add(thingy);
        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(panel);  
        add(scroll, BorderLayout.CENTER);

        final SpinnerNumberModel spmodel = 
            new SpinnerNumberModel(thingy.getThingySize(),
                10.0, 2000.0, 10.0);
        spmodel.addChangeListener(new ChangeListener() {
            @Override public void stateChanged(ChangeEvent e) {
                thingy.setThingySize((Double) spmodel.getNumber());
            }           
        });
        add(new JSpinner(spmodel), BorderLayout.NORTH);
    }
    public static void main(String[] args) {
        new SimpleScroller("simple scroller").start();
    }
    private void start() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

Вот результат:

SIMPLE SCROLLER

Ответ 3

Принимая ваши оба комментария, но

да... хотя я действительно хотел бы произвольно установить его

есть

важные методы, чтобы избежать мерцания или прыжка на JViewport

JViewport.setScrollMode(JViewport.BLIT_SCROLL_MODE); JViewport.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE); JViewport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);

  • используйте GlassPane (очень просто установить для получения нужной точки или/и Dimmension)

и

Я не хочу рисовать JViewport, по крайней мере, не напрямую. Мой реальный код является компонентом, подклассифицированным из JPanel, как и в моем примере, но в нем также есть другие элементы GUI.

  • вы можете использовать JXLayer (Java6) или части методов из JXLayer, реализованные непосредственно в JLayer (Java7)

  • может быть слишком сложным, но во всех случаях вы можете накладывать все с помощью JLabel

Примечание

все мое предложение по умолчанию использовать MouseEvent, J (X) Layer и JLabel с KeyEvents тоже, но нет проблем с событиями redispatch от --- > к другому JComponent

ИЗМЕНИТЬ

wait: нет, я не хочу рисовать спираль (то, что вы назвали "змея" ) в центре JScrollPane; Я хочу нарисовать свой компонент и отобразить компонент в центре JScrollPane.

  • ваш JPanel может быть шире, чем JViewport по умолчанию

a) JPanel возвращает размер

b) JViewport return Dimension

  • затем без каких-либо проблем, мерцание или замораживание

a) вы можете центрировать Dimmension от JPanel (Point) до центра JViewport (Point)

b) Если есть JComponent, вы можете переместить JViewport в любой getBounds(), который возвратил JComponent или Point из JPanel внутри JScrollPane

Ответ 4

С предложением от Andrew вы не можете иметь представление меньше, чем окно просмотра (и по-прежнему центрировано).

Самый чистый способ выполняется непосредственно из диспетчера компоновки, переопределяя ViewportLayout. Существует реализация в источнике:

http://www.randelshofer.ch/multishow

Ищите класс ZoomableViewportLayout, который отлично выполняет работу.