2012-05-07 22 views
11

如果您创建的视口大于JScrollPane的组件,那么它会在左上角显示该组件。Swing:创建一个显示其组件居中的JScrollPane?

有什么方法可以改变这种行为,所以它显示组件居中?

下面的示例程序。


澄清

我有具有(宽度,高度)=(CW,CH)的成分。我有一个带有(宽度,高度)=(vw,vh)视口的JScrollPane。

组件可能会变大或变小。我想用一种方法来使用滚动条将组件的中心点相对于视口的中心点定位,所以如果组件的一个或两个尺寸小于视口,则组件显示在视口的中心。

默认的滚动窗格行为将组件的左上角相对于视口的左上角定位。

我在问的是如何改变参考点。我不确定这对于默认的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); 
    } 
} 
+0

请张贴你正在拉你的头发的代码:-)。感谢上帝,因为“我不拉我的头发(还)”,例子会很好,有些事情可以尝试一下,非常感谢:-) –

+0

我不拉我的头发,我希望发布我的代码,但我可以拿出一个例子。 –

+0

你想在JScrollPane – mKorbel

回答

12
  1. 将一个JPanel到滚动窗格
  2. 面板的布局设置为一个GridBagLayout
  3. 将一个组件放入没有约束的面板中。它将被集中。

这是在Nested Layout Example中使用的技术,它将红色/橙色图像置于父项的中心。

+0

我认为,OP的想绘画的东西到JViewport,也许设置这个东西到所需的点 – mKorbel

+0

我不想绘制到JViewport,至少不是直接 - 我真正的代码是一个组件从子类JPanel,如我的例子,但它也有其他的GUI元素。 –

+0

@Andrew Thompson(@Jason S)是一个很常见的问题:-) – mKorbel

4

我只是增加了一个JPanelJScrollPane到我增加了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

+1

+1 ......这正是工作原理我希望它能够在水平维度上工作,而不是在垂直维度上。 –

3

接受你的这两个意见,但

是...虽然我很想

随意放置它有

避免闪烁或跳跃上的JViewport

JViewport.setScrollMode重要的方法(的JViewport .BLIT_SCROLL_MODE); JViewport.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE); JViewport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);

  • 使用GlassPane(很简单,为possition设定所需的点或/和Dimmension)

我不想画的JViewport的,在至少不是直接的 - 我的真实代码是从JPanel中分类的组件,如我的示例中所示,但它也包含其他GUI元素。

  • 可以使用JXLayer(的Java6)或方法的部分从JXLayer落实到JLayer(Java7)直接

  • 可能是太硬了,但在所有情况下,您可以覆盖任何与JLabel的

通知

所有我的建议,消耗的MouseEvent默认情况下,J(X)层和一个JLabel用的KeyEvents过,但那里再发运的事件没有问题的--->到另一个JComponent的

编辑

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

  • 您的JPanel能比的JViewport更宽默认

一)的JPanel返回尺寸

B)的JViewport返回Dimension

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

一个)可以定心Dimmension从JPanel的(点),以的JViewport的中心(点)

b)如果存在的JComponent可以移动的JViewport到任何的getBounds()THA从JPanel的返回的JComponent或点内JScrollPane

3

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

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

http://www.randelshofer.ch/multishow

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

相关问题