Java 在JScrollPane中滚动水平和垂直滚动条时未调用paintComponent

Java 在JScrollPane中滚动水平和垂直滚动条时未调用paintComponent,java,swing,jscrollpane,paintcomponent,repaint,Java,Swing,Jscrollpane,Paintcomponent,Repaint,我在Swing和JScrollPane方面遇到了问题。 我有一种奇怪的行为 我扩展了JScrollPane。我在其中显示一个图像,并在其上绘制矩形以定义区域。 对于大图像,我有一个水平和一个垂直的滚动条 我-好-当我移动一个滚动条或另一个滚动条时,我看到我的图像也在移动。 II-不正常-当我移动一个滚动条并将其保持在最大和最小位置之间时,然后当我移动第二个滚动条时,我的图像消失 通过一些调试打印,我发现在案例II中,paintComponent没有被调用 我想知道它为什么不调用paintComp

我在Swing和JScrollPane方面遇到了问题。 我有一种奇怪的行为

我扩展了
JScrollPane
。我在其中显示一个图像,并在其上绘制矩形以定义区域。 对于大图像,我有一个水平和一个垂直的滚动条

我-好-当我移动一个滚动条或另一个滚动条时,我看到我的图像也在移动。 II-不正常-当我移动一个滚动条并将其保持在最大和最小位置之间时,然后当我移动第二个滚动条时,我的图像消失

通过一些调试打印,我发现在案例II中,
paintComponent
没有被调用

我想知道它为什么不调用
paintComponent
,以及如何修复它

下面是我的课堂:

package GUI;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import javax.swing.JScrollPane;

public class DrawingPanel extends JScrollPane {

    private static final long serialVersionUID = 1L;
    private static final Color DRAWING_COLOR = new Color(255, 100, 200);
    private static final Color FINAL_DRAWING_COLOR = Color.red;
    private static final double ZOOMING_STEP = 1.1;

    private Image sImg;
    private Point startPt;
    private Point endPt;
    private Point currentPt;

    private int prefW;
    private int prefH;
    private double zoomFactor = 1;
    private boolean zoomer    = false;
    private boolean loaded    = false;

    public DrawingPanel() {
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public void loadImage(Image img) {
        sImg       = img;
        prefW      = sImg.getWidth(null);
        prefH      = sImg.getHeight(null);
        zoomFactor = getSize().getWidth() / prefW;
        zoomer     = true;
        loaded     = true;

        repaint();
        revalidate();
    }

    int countPaint = 0;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println("paintComponent " + countPaint);

        if (loaded) {
            int zoomWidth  = (int) (prefW * zoomFactor);
            int zoomHeight = (int) (prefH * zoomFactor);

            if (zoomer) {
                ((Graphics2D) g).scale(zoomFactor, zoomFactor);
                setSize(zoomWidth, zoomHeight);
                zoomer = false;
            }

            g.drawImage(sImg, 0, 0, zoomWidth, zoomHeight, null);
            drawRectangle(g);
        }

        g.dispose();
        countPaint++;
    }

    @Override
    public Dimension getPreferredSize() {
        return loaded ?
            this.getSize() :
            new Dimension((int) (prefW*zoomFactor), (int) (prefH*zoomFactor));
    }

    private void drawRectangle(Graphics g) {
        Point secondPoint = (currentPt != null) ? currentPt : endPt;
        Color color       = (currentPt != null) ? DRAWING_COLOR : FINAL_DRAWING_COLOR;

        if (startPt!=null && secondPoint!=null) {
            int x = Math.min(startPt.x, secondPoint.x);
            int y = Math.min(startPt.y, secondPoint.y);
            int rectangleWidth = Math.abs(startPt.x - secondPoint.x);
            int rectangleHeight = Math.abs(startPt.y - secondPoint.y);

            g.setColor(color);
            g.drawRect(x, y, rectangleWidth, rectangleHeight);
        }
    }

    public void deleteRectangle(){
        startPt = null;
        endPt   = null;
    }

    public void increaseZoom(Point p) {
        double oldZoom = zoomFactor;
        zoomFactor    *= ZOOMING_STEP;

        repositonPointAfterZoom(oldZoom, zoomFactor);
    }

    public void decreaseZoom(Point p) {
        double oldZoom = zoomFactor;
        zoomFactor    /= ZOOMING_STEP;

        repositonPointAfterZoom(oldZoom, zoomFactor);
    }

    public void repositonPointAfterZoom(double oldZoom, double newZoom) {
        double evolution = newZoom/oldZoom;

        if (startPt!=null) {
            startPt.setLocation(startPt.x * evolution, startPt.y * evolution);
        }

        if (endPt!=null) {
            endPt.setLocation(endPt.x * evolution, endPt.y * evolution);
        }

        repaint();
    }

    // Getter et setter

    public void setStartPt(Point startPt) {
        this.startPt = startPt;
    }

    public void setEndPt(Point endPt) {
        this.endPt = endPt;
    }

    public void setCurrentPt(Point currentPt) {
        this.currentPt = currentPt;
    }

    public int getZoomCalculateX(int value){
        return (int) (value / zoomFactor);
    }

    public int getZoomCalculateY(int value){
        return (int) (value / zoomFactor);
    }

    public void setZoomer(boolean zoomer) {
        this.zoomer = zoomer;
    }
}
编辑:Bellow是使用DrawingPanel的类(简化),这样您就可以有一个可复制的示例

package GUI;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.apache.commons.io.FilenameUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import fileHandler.*;

public class GUI {

    private JFrame frame;
    private MenuBar menubar;
    private DrawingPanel panelImage;
    private JScrollPane scroll;
    private GroundTruth openFile;
    private int[] panelImageDown = new int[2];
    private int[] panelImageUp   = new int[2];
    private Menu CoordinateMenu1 = new Menu();
    private Menu CoordinateMenu2 = new Menu();
    private int actualPagePdf;
    private PDFRenderer renderer;

    public static void main(String[] args) throws IOException {
        new GUI();
    }

    public GUI() throws IOException {
        JFrame frame = CreateFrame();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JFrame CreateFrame() throws IOException {
        frame = new JFrame();

        frame.setMenuBar(CreateMenuBar());
        frame.setContentPane(SplitScreen());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("GTA - Ground Truth Annotator");
        frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);

        return frame;
    }

    private MenuBar CreateMenuBar() {
        menubar = new MenuBar();

        menubar.add(CreateFileMenu());
        menubar.add(new Menu("Selection coordinates:"));
        menubar.add(CoordinateMenu1);
        menubar.add(new Menu("Width/Height:"));
        menubar.add(CoordinateMenu2);

        return menubar;
    }

    private Menu CreateFileMenu() {
        Menu mFile = new Menu("File");
        MenuItem miOpenImage = new MenuItem("Open Image/PDF File");
        mFile.add(miOpenImage);
        miOpenImage.addActionListener(OpenFileActionListener);
        mFile.addSeparator();
        MenuItem miExit = new MenuItem("Exit Program");
        mFile.add(miExit);
        miExit.addActionListener(ExitActionListener);

        return mFile;
    }

    private JPanel SplitScreen() throws IOException {
        JPanel splittedScreen = new JPanel(new GridLayout(1, 2));

        splittedScreen.add(CreateLeftPanel());
        splittedScreen.add(CreateRightPanel());

        return splittedScreen;
    }

    private JLayeredPane CreateLeftPanel() throws IOException {
        JLayeredPane panel = new JLayeredPane();

        panel.setLayout(new BorderLayout());
        panel.setBorder(BorderFactory.createLineBorder(Color.gray));
        panel.add(CreateImageScrollPane());

        return panel;
    }

    private JScrollPane CreateImageScrollPane() throws IOException {
        scroll  = new JScrollPane(CreateImagePanel((String) null));

        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scroll.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);

        return scroll;
    }

    private DrawingPanel CreateImagePanel(String path) throws IOException {
        if (panelImage == null) {
            panelImage = new DrawingPanel();
        }

        if (path != null) {
            panelImage.loadImage(ImageIO.read(new File(path)));
        }

        panelImage.addMouseListener(PanelImageMouseListener);
        panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
        panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
        panelImage.setOpaque(false);
        panelImage.revalidate();
        panelImage.repaint();
        panelImage.requestFocus();

        return panelImage;
    }

    private DrawingPanel CreateImagePanel(Image image) throws IOException {
        if (panelImage == null) {
            panelImage = new DrawingPanel();
        }

        panelImage.loadImage(image);
        panelImage.addMouseListener(PanelImageMouseListener);
        panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
        panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
        panelImage.setOpaque(false);
        panelImage.revalidate();
        panelImage.repaint();

        return panelImage;
    }

    private JPanel CreateRightPanel() {
        JPanel panel = new JPanel(new GridLayout(0, 1));

        //...

        return panel;
    }

    ActionListener OpenFileActionListener = new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
           OpenFile();
        }
    };

    ActionListener ExitActionListener = new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            Object[] options = {"Yes, quit now", "No, go back"};
            int n = JOptionPane.showOptionDialog(
                    frame, "ATTENTION: closing without saving will cause any unsaved files to be lost. Do you want to proceed?",
                    "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]
            );

            switch (n) {
                case JOptionPane.YES_OPTION:
                    System.exit(0);
                case JOptionPane.NO_OPTION:

                case JOptionPane.CANCEL_OPTION:
            }
        }

    };

    MouseListener PanelImageMouseListener = new MouseListener() {
        public void mousePressed(MouseEvent me) {
            panelImageDown = new int[]{
                    panelImage.getZoomCalculateX(me.getX()), panelImage.getZoomCalculateY(me.getY())
            };
            panelImageUp = null;

            CoordinateMenu1.setLabel(String.format("%s:%s", panelImageDown[0],  panelImageDown[1]));
            CoordinateMenu2.setLabel("");
            panelImage.setStartPt(me.getPoint());
            panelImage.repaint();
        }

        public void mouseReleased(MouseEvent me) {
            panelImageUp = new int[]{
                    Math.abs(panelImage.getZoomCalculateX(me.getX()) - panelImageDown[0]),
                    Math.abs(panelImageDown[1] - panelImage.getZoomCalculateY(me.getY()))
            };

            CoordinateMenu2.setLabel(String.format("%s:%s", panelImageUp[0], panelImageUp[1]));
            panelImage.setEndPt(me.getPoint());
            panelImage.setCurrentPt(null);
            panelImage.repaint();
        }

        public void mouseClicked(MouseEvent arg0) {
        }

        public void mouseEntered(MouseEvent arg0) {
        }

        public void mouseExited(MouseEvent arg0) {
        }
    };


    MouseMotionAdapter PanelImageMouseMotionAdapter = new MouseMotionAdapter() {
        @Override
        public void mouseDragged(MouseEvent me) {
            panelImageUp = new int[]{
                    Math.abs(panelImage.getZoomCalculateX(me.getX()) - panelImageDown[0]),
                    Math.abs(panelImageDown[1] - panelImage.getZoomCalculateY(me.getY()))
            };

            CoordinateMenu2.setLabel(String.format("%s:%s", panelImageUp[0], panelImageUp[1]));
            panelImage.setCurrentPt(me.getPoint());
            panelImage.repaint();
        }
    };

    MouseWheelListener PanelImageMouseWheelListener = new MouseWheelListener() {
        public void mouseWheelMoved(MouseWheelEvent me) {
            if (me.isAltDown()) {
                if (me.getWheelRotation() < 0) {
                    panelImage.setZoomer(true);
                    panelImage.increaseZoom();
                    panelImage.repaint();
                    panelImage.requestFocus();
                    //scroll.repaint();
                //Zoom out
                } else if(me.getWheelRotation() > 0) {
                    panelImage.setZoomer(true);
                    panelImage.decreaseZoom();
                    panelImage.repaint();
                    panelImage.requestFocus();
                    //scroll.repaint();
                }
            }
        }
    };

    private void OpenFile() {
        openFile                 = new GroundTruth();
        JFileChooser fileChooser = new JFileChooser();

        fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.addChoosableFileFilter(new FileNameExtensionFilter(
                "Images / PDF Scan",
                "bmp", "jpeg", "jpg", "png", "tif", "tiff", "pdf"
        ));

        if (fileChooser.showOpenDialog(frame) != 0) {
            return;
        }

        openFile.setFilename(fileChooser.getSelectedFile().getAbsolutePath());

        if (getExtension(fileChooser.getSelectedFile().getName()).equals("pdf")) {
            try {
                PDDocument doc = PDDocument.load(fileChooser.getSelectedFile());
                numberPagePdf  = doc.getNumberOfPages();
                actualPagePdf  = 0;
                renderer       = new PDFRenderer(doc);

                setPdfPage(actualPagePdf);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            try {
                CreateImagePanel(fileChooser.getSelectedFile().getAbsolutePath());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void setPdfPage(int pageNumber){
        try {
            BufferedImage bim = renderer.renderImageWithDPI(pageNumber, 300);

            refreshInfoPageSection();
            CreateImagePanel(bim);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // refresh the label who indicate the page display and set visible or inivisble the previous and next button
    private void refreshInfoPageSection(){
        panelImage.deleteRectangle();
    }

    public String getExtension(String filename) {
        return FilenameUtils.getExtension(filename);
    }
}
packagegui;
导入java.awt.*;
导入java.awt.event.*;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入javax.imageio.imageio;
导入javax.swing.*;
导入javax.swing.filechooser.FileNameExtensionFilter;
导入org.apache.commons.io.FilenameUtils;
导入org.apache.pdfbox.pdmodel.PDDocument;
导入org.apache.pdfbox.rendering.PDFRenderer;
导入fileHandler.*;
公共类GUI{
私有JFrame;
私人菜单栏菜单栏;
私人绘图面板面板图像;
私有JScrollPane滚动条;
私有开放文件;
私有int[]panelImageDown=新int[2];
私有int[]panelImageUp=新int[2];
私有菜单协调U1=新菜单();
私有菜单协调U2=新菜单();
私人文件;
专用PDF渲染器;
公共静态void main(字符串[]args)引发IOException{
新GUI();
}
公共GUI()引发IOException{
JFrame=CreateFrame();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
私有JFrame CreateFrame()引发IOException{
frame=新的JFrame();
setMenuBar(CreateMenuBar());
frame.setContentPane(SplitScreen());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
帧。设置标题(“GTA-地面真相注释器”);
frame.setExtendedState(frame.getExtendedState()| JFrame.MAXIMIZED_两者);
返回框;
}
私有菜单栏CreateMenuBar(){
菜单栏=新菜单栏();
添加(CreateFileMenu());
添加(新菜单(“选择坐标:”);
菜单栏添加(CoordinationU1);
菜单栏。添加(新菜单(“宽度/高度:”);
菜单栏添加(协调2);
返回菜单栏;
}
私有菜单CreateFileMenu(){
菜单文件=新菜单(“文件”);
MenuItem miOpenImage=新MenuItem(“打开图像/PDF文件”);
添加文件(miOpenImage);
添加ActionListener(OpenFileActionListener);
mFile.addSeparator();
MenuItem miExit=新MenuItem(“退出程序”);
mFile.add(miExit);
miExit.addActionListener(ExitActionListener);
返回mFile;
}
私有JPanel SplitScreen()引发IOException{
JPanel splittedScreen=新的JPanel(新的网格布局(1,2));
添加(CreateLeftPanel());
添加(CreateRightPanel());
返回分割屏幕;
}
私有JLayeredPane CreateLeftPanel()引发IOException{
JLayeredPane panel=新的JLayeredPane();
panel.setLayout(新的BorderLayout());
panel.setOrder(BorderFactory.createLineBorder(Color.gray));
添加(CreateImageScrollPane());
返回面板;
}
私有JScrollPane CreateImageScrollPane()引发IOException{
scroll=newJScrollPane(CreateImagePanel((字符串)null));
scroll.setHorizontalScrollBarPolicy(JScrollPane.HorizontalScrollBar,根据需要);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL\u SCROLLBAR\u根据需要);
scroll.getViewport().setScrollMode(JViewport.BLIT_scroll_MODE);
返回滚动条;
}
私有DrawingPanel CreateImagePanel(字符串路径)引发IOException{
if(panelImage==null){
panelImage=新建DrawingPanel();
}
if(路径!=null){
loadImage(ImageIO.read(新文件(路径));
}
panelImage.addMouseListener(PanelImageMouseListener);
panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
panelImage.set不透明(false);
panelImage.revalidate();
panelImage.repaint();
panelImage.requestFocus();
返回面板图像;
}
私有DrawingPanel CreateImagePanel(图像图像)引发IOException{
if(panelImage==null){
panelImage=新建DrawingPanel();
}
panelImage.loadImage(图像);
panelImage.addMouseListener(PanelImageMouseListener);
panelImage.addMouseWheelListener(PanelImageMouseWheelListener);
panelImage.addMouseMotionListener(PanelImageMouseMotionAdapter);
panelImage.set不透明(false);
panelImage.revalidate();
panelImage.repaint();
返回面板图像;
}
私有JPanel CreateRightPanel(){
JPanel面板=新JPanel(新网格布局(0,1));
//...
返回面板;
}
ActionListener OpenFileActionListener=新建ActionListener(){
已执行的公共无效操作(操作事件arg0){
OpenFile();
}
};
ActionListener ExitActionListener=新ActionListener(){
已执行的公共无效操作(操作事件arg0){
Object[]选项={“是,现在退出”,“否,返回”};
int n=JOptionPane.showOptionDialog(
框架,“注意:不保存而关闭将导致任何未保存的文件丢失。是否继续
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class LargeDrawingPanel implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new LargeDrawingPanel());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Large Drawing Panel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createMainPanel(), BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createMainPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        panel.setPreferredSize(new Dimension(400, 400));
        
        JScrollPane scrollPane = new JScrollPane(new DrawingPanel());
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        public DrawingPanel() {
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(2000, 2000));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            g.setColor(Color.BLUE);
            int x = 100;
            int y = 100;
            for (int i = 0; i < 10; i++) {
                for (int j = 0; j < 10; j++) {
                    g.fillRect(x, y, 100, 100);
                    x += 200;
                }
                y += 200;
                x = 100;
            }
        }
        
    }
    
}