Swing:创建一个显示其组件居中的JScrollPane?

时间:2012-05-07 17:12:25

标签: java 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);
    }
}

4 个答案:

答案 0 :(得分:12)

  1. JPanel放入滚动窗格
  2. 将面板的布局设置为GridBagLayout
  3. 将一个组件放入面板中,没有约束。它会居中。
  4. 这是Nested Layout Example中使用的技术,它将红色/橙色图像放置在父图像的中心。

答案 1 :(得分:4)

我只是在我添加JPanel的{​​{1}}添加了JScrollPane。希望这是你想要的:

THINGY JPanel

这是输出:

SIMPLE SCROLLER

答案 2 :(得分: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

  

修改

     

等待:不,我不想在JScrollPane的中心画出螺旋(你称之为“蛇”);我想绘制我的组件并让我的组件显示在JScrollPane的中心。

  • 默认情况下,您的JPanel可能比JViewport宽

a)JPanel返回Dimension

b)JViewport返回Dimension

  • 然后没有任何问题,闪烁或冻结

a)你可以将Dimmension从JPanel(Point)居中到JViewport(Point)的中心

b)如果有JComponent,您可以将JViewport移动到任何getBounds(),从JScrollPane中的JPanel返回JComponent或Point

答案 3 :(得分:3)

根据Andrew的建议,您不能让视图小于视口(并且仍然居中)。

最干净的方法是直接从布局管理器执行,覆盖ViewportLayout。源代码中有一个实现:

http://www.randelshofer.ch/multishow

查找ZoomableViewportLayout类,它完美地完成了这项工作。