简体   繁体   中英

Manually movable JComponent in a JScrollPane

I'm trying to make a program that lets the user manually place and resize components within a JScrollPane, a bit of a special-case UI Builder. I managed to make a custom JPanel class that allows the user to move it around manually however when it's added to the JScrollPane and moved around, if it goes outside of the visual bounds of the JScrollPane the scrollbars don't appear or adjust.

Here is my main class that includes the JFrame and JScrollPane.

package quickscrolltest;

import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class QuickScrollTest {

    JFrame wnd;
    JScrollPane scroll;
    JPanel pnl;
    MovablePanel pnl1;

    public QuickScrollTest() {
        wnd = new JFrame();
        scroll = new JScrollPane();
        pnl = new JPanel();
        pnl.setLayout(null);
        scroll.setViewportView( pnl );
        wnd.setContentPane(scroll);
        wnd.pack();
        pnl1 = new MovablePanel();
        Dimension dim1 = new Dimension( 300, 400 );
        pnl1.setSize( dim1 );        
        pnl1.setPreferredSize(dim1);
        pnl1.setBackground( Color.CYAN );
        pnl1.setLocation( 10, 10 );
        /*scroll.getViewport().add(pnl1,null);*/
        pnl.add(pnl1);
        wnd.setSize( 800, 600 );
        wnd.setLocationRelativeTo(null);
        wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        wnd.setVisible(true);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new QuickScrollTest();
    }

}

Here is the MovablePanel class

package quickscrolltest;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JPanel;

public class MovablePanel extends JPanel implements MouseListener, MouseMotionListener {

    Color bg = Color.GRAY;
    Point clickPoint;

    public MovablePanel() {
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    @Override
    public void setBackground( Color col ) {
        super.setBackground(col);
        bg = col;
    }

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        clickPoint = e.getPoint();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        setCursor( Cursor.getDefaultCursor() );
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        setCursor( Cursor.getPredefinedCursor(Cursor.HAND_CURSOR) );
        super.setBackground( Color.RED );
    }

    @Override
    public void mouseExited(MouseEvent e) {
        setCursor( Cursor.getDefaultCursor() );
        super.setBackground( bg );
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        setCursor( Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR) );
        int lastX = getX() - (int) clickPoint.getX();
        int lastY = getY() - (int) clickPoint.getY();
        setLocation(lastX + e.getX(), lastY + e.getY() );
    }

    @Override
    public void mouseMoved(MouseEvent e) {}  

}

How can I make it so that users can freely move components around in the JScrollPane and have the scrollbars update as required?

My final code will have a standalone mouselistener/mousemotionlistener class that generically works on a given JComponent but I coded the listeners directly into the JPanel for simplicity.

Thanks

Scrollbars automatically appear/disappear when the preferred size of the component displayed in the viewport of the scroll panes changes.

You can use the Drag Layout . This class is a custom layout manager and will automatically recalculate the preferred size of the panel as components are dragged around the panel.

You will need to handle the mouseReleased event so you can revalidate() the panel, and invoke the DragLayout once you are finished dragging the component so the preferred size can be reset. Or you could use the ComponentMover class which is referenced in the blog article to do the dragging of the component for you. It supports an auto resize property which will do the revalidate() for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM