Swing: creating a JScrollPane that displays its component centered?

前端 未结 4 1228
别那么骄傲
别那么骄傲 2021-02-08 02:52

If you create a JScrollPane that has a viewport larger than the JScrollPane\'s component, it displays that component in the upper left.

Is there any way to change this b

相关标签:
4条回答
  • 2021-02-08 03:25
    1. Put a JPanel into the scroll-pane
    2. Set the layout of the panel to a GridBagLayout.
    3. Put one component into the panel with no constraint. It will be centered.

    This is the technique used in the Nested Layout Example, which places the red/orange image into the center of the parent.

    0 讨论(0)
  • 2021-02-08 03:37

    I simply added a JPanelto the JScrollPane to which I added the THINGY JPanel. Hope this is what you wanted :

    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);
        }
    }
    

    Here is the output :

    SIMPLE SCROLLER

    0 讨论(0)
  • 2021-02-08 03:37

    With the suggestion from Andrew, you can't have the view smaller than the viewport (and still centered).

    The cleanest way is doing it directly from the layout manager, overriding ViewportLayout. There is an implementation in the source of:

    http://www.randelshofer.ch/multishow

    Look for the class ZoomableViewportLayout, which does the job perfectly.

    0 讨论(0)
  • 2021-02-08 03:43

    Accepting your both comments, but

    yes... although I'd really like to arbitrarily position it

    there are

    • extract or to create own JViewport

    important methods to avoiding flickering or jumping on the JViewport

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

    • use GlassPane (is very simple to set for possition to the desired Point or/and Dimmension)

    and

    I don't want to paint to the JViewport, at least not directly -- My real code is a component subclassed from JPanel, as in my example, but it also has other GUI elements in it.

    • you can use JXLayer (Java6) or parts of methods from JXLayer implemented to the JLayer (Java7) directly

    • could be too hard, but in all cases you can overlay whatever with JLabel

    Notice

    all my suggestion to consume MouseEvent by default, J(X)Layer and JLabel with KeyEvents too, but there no issue with redispatch events from ---> to another JComponent

    EDIT

    wait: no, I don't want to paint the spiral (what you called "snake") in the center of the JScrollPane; I want to paint my component and have my component be displayed in the center of the JScrollPane.

    • your JPanel could be wider than JViewport by default

    a) JPanel returns Dimension

    b) JViewport return Dimension

    • then without any issue, flickering or freeze

    a) you can centering Dimmension from JPanel (Point) to the center of JViewport (Point)

    b) if is there JComponent you can move the JViewport to any getBounds() tha returned JComponent or Point from JPanel inside JScrollPane

    0 讨论(0)
提交回复
热议问题