如何在JPanel更新时滚动JScrollPane

时间:2016-03-18 09:48:33

标签: java swing user-interface

我正在尝试实现一个JPanel(添加到JScrollPane)。我们的想法是在JPanel上绘制一系列矩形。这些矩形中的一个具有不同的颜色。我的想法是,当应用程序运行时,我应该能够添加更多这些矩形(如果需要)或在当前绘制的矩形之间移动。我有左/右移动按钮,允许我在矩形之间移动。现在的问题是,当我可以在按钮之间移动时,但JScrollPane在更新JPanel时不会移动。如下图所示,假设我在值为[a]的矩形中,其颜色为橙色。现在我可以向左或向右移动,但JScrollPane保持不变。如何使JScrollPane与矩形一起移动? The panel screenshot

我有一个文件(TapeArea)来完成所有绘图,还有一个文件(TapePanel)将3个TapeArea实例捆绑在一起。

import java.awt.Color;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;


import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

public class TapeArea extends JPanel {

    private final Color BG_COLOR = new Color(200,200,200);
    private final Color DEFAULT_CELL_COLOR = Color.white;
    private final Color CURRENT_CELL_COLOR = Color.orange;
    private final Color CELL_INDEX_COLOR = new Color(0, 130, 0);
    private final int FONT_STYLE = Font.BOLD;
    private final String FONT_NAME = "Monotype";
    private final double INITIAL_OFFSET = -1.5;


    int cellWidth = 40;
    int cellHeight = 40;
    int fontSize = 20;
    boolean tapeInit = false;
    int leftMostCell = 0, rightMostCell = 0;
    double newLeftCellWidth = 0, newRightCellWidth = 0;
    boolean newLeftCell = false, newRightCell = false;
    Color currentTextColor = Color.black;
    double offset = INITIAL_OFFSET;
    int origin = 0;

    Dimension areaSize;
    int filler;
    Tape tape;
    FlowLayout layout;

    int x   = 10;   //Start Drawing from X=10   
    int delay   = 500;  //milliseconds

    public TapeArea(Tape t){
        tape = t;
        layout = new FlowLayout();
        setLayout(layout);
        setPreferredSize(new Dimension(1200,50));


//       ActionListener counter = new ActionListener() {
//              public void actionPerformed(ActionEvent evt) 
//              { 
//                  stepOneTapeCell();
//                    repaint();
//                    x++;
//              }};
//           new Timer(delay, counter).start();
    }




    public void paintComponent(Graphics g){
        int i,drawPos;
        int yAlign;
        int fontScalingFactor;
        int stringWidth, stringHeight;
        int index = 0, startAt, cellsToDraw, currentPosition;
        int tapeLength;
        String symbol;
        FontRenderContext DEFAULT_FONT_RENDER_CONTEXT =
                new FontRenderContext(null, false, false);
        Rectangle2D charBounds;

        Graphics2D g2d = (Graphics2D) g;
        super.paintComponent(g2d);

        if(tape == null)
            return;


        g2d.setColor(BG_COLOR);
        g2d.fillRect(0,0,getWidth(), getHeight());

        tapeLength = tape.getSize();

        if(areaSize != null)
            if(areaSize.width != getSize().width || areaSize.height != getSize().height)
                tapeInit = false;

        areaSize = getSize();
        yAlign = areaSize.height / 2;

        cellWidth = getHeight() - 2;
        if(cellWidth > 40) {
            cellWidth = 40;
        }
        cellHeight = cellWidth;
        fontSize = cellWidth / 2;



        if(newLeftCell) {
            startAt = 1;
            cellsToDraw = tapeLength - 1;
            currentPosition = 0;
        } else if(newRightCell) {
            startAt = 0;
            cellsToDraw = tapeLength - 1;
            currentPosition = tapeLength - 2;
        } else {
            startAt = 0;
            cellsToDraw = tapeLength;
            currentPosition = tape.getCurrentPosition();
        }
        currentPosition = tape.getCurrentPosition();

        //determine the number of cells to left and right on the tape
        if(!tapeInit){
            for(filler = 0; cellWidth * (1 + 2*filler) <= areaSize.width; filler++);
            filler += 2;

            leftMostCell = currentPosition - filler;
            rightMostCell = leftMostCell + 2*filler;

            while(-leftMostCell < rightMostCell - tapeLength - 1 && 0 < rightMostCell - tapeLength - 1) {
                leftMostCell--;
                rightMostCell--;
            }
            while(-leftMostCell > rightMostCell - tapeLength + 1 && leftMostCell < 0) {
                leftMostCell++;
                rightMostCell++;
            }

        }//end of if(!tapeInit)



        if(origin != tape.getOrigin()){
            leftMostCell++;
            rightMostCell++;
        }
        origin = tape.getOrigin();
        tapeInit = true;

        //draw tape cells
        for(drawPos = 0, i = leftMostCell; i <= rightMostCell; i++, drawPos++){

            //what symbol to be drawn on the cell
            if(i >= 0 && i < tapeLength)
                symbol = (String) tape.getSymbolAt(i);
            else
                symbol = tape.getFillSymbol();

            //indicate current tape cell by coloring it
            if(i == currentPosition)
                g2d.setColor(CURRENT_CELL_COLOR);
            else 
                g2d.setColor(DEFAULT_CELL_COLOR);

            g2d.fillRect((int)((newLeftCellWidth + drawPos + offset) * cellWidth), yAlign - cellHeight/2, 
                       cellWidth, cellHeight);

            g2d.setColor(Color.black);
            g2d.drawRoundRect((int)((newLeftCellWidth + drawPos + offset) * cellWidth), yAlign - cellHeight/2, 
                       cellWidth, cellHeight, 10, 10);

            //draw symbols on cells
            charBounds = g.getFont().getStringBounds(symbol, 
                     DEFAULT_FONT_RENDER_CONTEXT);

            stringWidth  = (int)Math.ceil(charBounds.getWidth());
            stringHeight = (int)Math.ceil(charBounds.getHeight());

            //if symbol is multi-character, font may be adjusted so it will fit
            fontScalingFactor = (int)Math.ceil((double)stringWidth/(double)cellWidth);
            g.setFont(new Font(FONT_NAME, FONT_STYLE, fontSize/fontScalingFactor));

            charBounds = g.getFont().getStringBounds(symbol, 
                                 DEFAULT_FONT_RENDER_CONTEXT);

            stringWidth  = (int)Math.ceil(charBounds.getWidth());
            stringHeight = (int)Math.ceil(charBounds.getHeight());

            if(i == tape.getCurrentPosition()) {
                g.setColor(currentTextColor);
            }

            g.drawString(symbol, 
                 (int)((newLeftCellWidth + drawPos + 0.5 + offset) * cellWidth - (stringWidth/2)), 
                     (int)(yAlign + (stringHeight/4)));

            g.setFont(new Font(FONT_NAME, Font.PLAIN, fontSize/(2 * fontScalingFactor)));
            g.setColor(CELL_INDEX_COLOR);

            g.drawString(Integer.toString(i - origin), 
                     (int)((newLeftCellWidth + drawPos + 0.3 + offset) * cellWidth - (stringWidth/2)), 
                     (int)(yAlign + 0.45 * cellHeight));
            index++;

        }//end of for() drawing tape cells



    }

    void setTapeData(String m, Tape p){
        p.removeAllTapeData();
        p.addDataToTape(m);
    }


    void stepOneTapeCell(String direction){
        switch(direction){
        case "L":
            if(tape.getCurrentPosition() > tape.getOrigin()){
                tape.setCurrentPosition(tape.getCurrentPosition() - 1);
                revalidate();
                repaint();
            }
            //tape.shiftLeft();
            break;
        case "R":
            if(tape.getCurrentPosition() < tape.getSize()-1){
                tape.setCurrentPosition(tape.getCurrentPosition() + 1);
                revalidate();
                repaint();
            }
//          tape.setCurrentPosition(tape.getCurrentPosition() + 1);
//          repaint();
//          tape.shiftRight();
//          repaint();
            break;
        }   
    }


}//end of class TapePanel

TapePanel文件:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

public class TapePanel extends JPanel implements MyJPanel{

    private final int ROWS = 3;
    private final int COLS = 1;
    private final int TAPE_ORIGINAL_POSITION = 0;
    private int NUM_TAPES = 3;
    GridLayout layout;
    Tape [] tapes;
    TapeArea [] tapeArea;
    JScrollPane sp1, sp2, sp3;

    Border blackLine, border,margin;
    TitledBorder title;

    public TapePanel(Tape t1, Tape t2, Tape t3){

        tapes = new Tape[NUM_TAPES];
        tapes[0] = t1;
        tapes[1] = t2;
        tapes[2] = t3;
        initiateComps();
        addCompsToLayout();
    }


    public void initiateComps() {
        // TODO Auto-generated method stub
        layout = new GridLayout(ROWS,COLS);
        setLayout(layout);

        blackLine = BorderFactory.createLineBorder(Color.BLACK);
        title = BorderFactory.createTitledBorder(blackLine,"Tapes");
        title.setTitleJustification(TitledBorder.LEFT);
        border = title.getBorder();
        margin = new EmptyBorder(15,15,15,15);
        title.setBorder(new CompoundBorder(margin,border));
        setBorder(title);

        tapeArea = new TapeArea[NUM_TAPES];
        tapeArea[0] = new TapeArea(tapes[0]);
        tapeArea[1] = new TapeArea(tapes[1]);
        tapeArea[2] = new TapeArea(tapes[2]);

        sp1 = new JScrollPane(tapeArea[0],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        sp1.setPreferredSize(new Dimension(200,70));
        sp2 = new JScrollPane(tapeArea[1],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        sp2.setPreferredSize(new Dimension(200,70));
        sp3 = new JScrollPane(tapeArea[2],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        sp3.setPreferredSize(new Dimension(200,70));

        //setBorder(new EmptyBorder(20,15,15,15));
    }

    @Override
    protected void paintComponent(Graphics g) {
        // TODO Auto-generated method stub
        super.paintComponent(g);

    }
    void repaintTapeArea(){
        for(int i = 0; i < NUM_TAPES;i++){
            tapeArea[i].revalidate();
            tapeArea[i].repaint();
        }

    }

    void resetAllTapes(){

        for(int i = 0; i < NUM_TAPES; i++){
            tapeArea[i].setTapeData("", tapes[i]);
            tapeArea[i].tape.setCurrentPosition(TAPE_ORIGINAL_POSITION);
        }

    }
    void setTapeData(String m, Tape p, int tapeNumber){
        tapeArea[tapeNumber].setTapeData(m, p);
    }

    void stepOneCell(int tapeNumber, String direction){
        tapeArea[tapeNumber].stepOneTapeCell(direction);
    }

    @Override
    public void addCompsToLayout() {
        // TODO Auto-generated method stub
        add(sp1);
        add(sp2);
        add(sp3);
    }


    @Override
    public void addComponent(Component comp, int zone, int row, int col, int width, int height) {
        // TODO Auto-generated method stub

    }

    public static void main(String [] args){

            JFrame f = new JFrame();
            f.add(new TapePanel(new Tape("a b c d"),new Tape("a b c d"),new Tape("a b")));
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);

            f.pack();

    }
}

磁带只是一个简单的链接列表。

1 个答案:

答案 0 :(得分:2)

  

我只能在屏幕上看到14个可以移动的矩形。如果我添加更多,那么它们将不可见。

滚动仅在添加到滚动窗格的组件的首选大小大于滚动窗格的大小时发生。

您需要覆盖自定义绘图面板的getPreferredSize()方法,以反映每个矩形所覆盖的区域。

因此,当您将矩形向右或向下移动时,您可能需要调整首选大小。