【问题标题】:JPanel inside JScrollPane with graphics glitches while scrollingJScrollPane 内的 JPanel 在滚动时出现图形故障
【发布时间】:2016-12-11 05:00:28
【问题描述】:

所以我制作了一个简单的图形 GUI,其中最右边的部分是一个 JScrollPane,里面有一个 JPanel(画布)(mainGUI 类)。当我尝试绘制一些框(使用 Box 类)并运行它时,滚动时我得到这个重复的 windowsXP 图形错误,其中框的渲染速度太慢或其他东西,有点难以解释。滚动后如何获得统一的无故障绘图?有没有渲染选项之类的?

代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class Grafin{
    public static void main(String args[]){
        mainGUI gui = new mainGUI();
    }
}

class mainGUI{
    private JFrame mainFrame;
    private JPanel toolsPanel;
    private JPanel canvasPanel;

    public mainGUI(){
        try{
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
        }catch(Exception e){
            System.out.println(e.getMessage());
        }

        mainFrame = new JFrame("Grafin | untitled");
        mainFrame.setLayout(new GridBagLayout());
        mainFrame.setSize(920, 580);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setLocationRelativeTo(null);
        mainFrame.setVisible(true);     

        loadGUI();
    }

    public void loadGUI(){
        GridBagConstraints c = new GridBagConstraints();

        //toolsPanel (izq) y canvasPanel (der) dentro de mainFrame
        toolsPanel = new JPanel(new GridBagLayout());
        toolsPanel.setPreferredSize(new Dimension(250,580));

        c.gridx = 0;
        c.gridy = 0;
        c.weightx = 0.1;
        c.weighty = 1;
        c.fill = GridBagConstraints.BOTH;
        mainFrame.add(toolsPanel, c);


        canvasPanel = new JPanel(new GridBagLayout());
        canvasPanel.setBackground(Color.white);
        canvasPanel.setPreferredSize(new Dimension(1500,1000));

        JScrollPane canvasScroll = new JScrollPane(canvasPanel);
        canvasScroll.setPreferredSize(new Dimension(670,580));

        c.gridx = 1;
        c.gridy = 0;
        c.weightx = 0.9;
        mainFrame.add(canvasScroll, c);
        canvasScroll.setSize(canvasScroll.getPreferredSize());
        canvasScroll.setBackground(Color.white);

        //CanvasPanel:
        c.gridx = 0;
        c.gridy = 0;
        c.weightx = 1;
        c.weighty = 1;

        Box b1 = new Box(10, 200, 30, 128);
        Box b2 = new Box(200, 10, 120, 40);
        canvasPanel.add(b1, c);
        canvasPanel.add(b2, c);
        mainFrame.pack();
    }
}

    class Box extends JPanel{
    private Color borderColor;
    private Color fillColor;
    public int x;
    public int y;
    public int width;
    public int height;

    public Box(){
        borderColor = Color.black;
        fillColor = new Color(242, 242, 242);
        x = y = 1;
        width = height = 30;
    }

    public Box(int px, int py, int w, int h){
        x = px;
        y = py;
        borderColor = Color.black;
        fillColor = new Color(242, 242, 242);
        width = w;
        height = h; 
    }

    public void changeFillColor(Color c){
        fillColor = c;
    }

    public void changeBorderColor(Color c){
        borderColor = c;
    }

    public void paint(Graphics g){
        g.setColor(fillColor);
        g.fillRect(x, y, width, height);
        g.setColor(borderColor);
        g.drawRect(x, y, width, height);
    }
}

提前致谢 节日快乐

【问题讨论】:

    标签: java swing graphics jscrollpane


    【解决方案1】:

    首先,您覆盖了错误的绘画方法。您不应该重写 JPanel 的 paint 方法,而应该重写它的 paintComponent 方法,因为这是一种更具体的绘画方法,并且默认情况下具有双缓冲,在制作动画时是一个加分项(您在滚动时会这样做)。

    更重要的是你没有在你的覆盖中调用超级的绘画方法,super.paintComponent(g)如果覆盖paintComponent,或者super.paint(g)如果(错误地)覆盖paint。这可以防止您的 JPanel 清理脏像素。

    其他问题:您将两个组件添加到使用 GridBagLayout 的组件中,但两者都使用相同的 GridBagConstraints,这是您不应该做的事情。

    此外,您的 Box 类应该是 logical 类,而不是 component 类。换句话说,它不应该扩展任何 Swing GUI 组件,而应该在 canvasPanel 中绘制。

    例如:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class Grafin2 extends JPanel {
        private static final int PREF_W = 920;
        private static final int PREF_H = 580;
        private static final Dimension TOOLS_SIZE = new Dimension(250, PREF_H);
        private static final Dimension CANVAS_SIZE = new Dimension(1500, 1000);
        private JPanel toolsPanel = new JPanel();
        private CanvasPanel canvasPanel = new CanvasPanel();
    
        public Grafin2() {
            MyBox box1 = new MyBox(10, 200, 30, 128);
            MyBox box2 = new MyBox(200, 10, 120, 40);
    
            box1.changeFillColor(new Color(255, 120, 120));
            box2.changeFillColor(new Color(220, 220, 255));
    
            canvasPanel.addMyBox(box1);
            canvasPanel.addMyBox(box2);
    
            toolsPanel.setPreferredSize(TOOLS_SIZE);
            canvasPanel.setBackground(Color.white);
            canvasPanel.setPreferredSize(CANVAS_SIZE);
            JScrollPane canvasScroll = new JScrollPane(canvasPanel);
    
            setLayout(new BorderLayout());
            add(toolsPanel, BorderLayout.LINE_START);
            add(canvasScroll, BorderLayout.CENTER);
        }
    
        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet()) {
                return super.getPreferredSize();
            }
            return new Dimension(PREF_W, PREF_H);
        }
    
        private class CanvasPanel extends JPanel {
            // a collection to hold all the boxes
            private List<MyBox> boxes = new ArrayList<>();
    
            public void addMyBox(MyBox myBox) {
                boxes.add(myBox);
            }
    
            @Override // again, this is the proper painting method
            protected void paintComponent(Graphics g) {
                super.paintComponent(g); // never forget this!
                for (MyBox myBox : boxes) {
                    myBox.draw(g); // draw all the boxes that we hold
                }
            }
        }
    
        private static void createAndShowGui() {
            Grafin2 mainPanel = new Grafin2();
    
            JFrame frame = new JFrame("Grafin2");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    
    // this is a logical class, **not** a component class.
    class MyBox {
        private Color borderColor;
        private Color fillColor;
        public int x;
        public int y;
        public int width;
        public int height;
    
        public MyBox() {
            borderColor = Color.black;
            fillColor = new Color(242, 242, 242);
            x = y = 1;
            width = height = 30;
        }
    
        public MyBox(int px, int py, int w, int h) {
            x = px;
            y = py;
            borderColor = Color.black;
            fillColor = new Color(242, 242, 242);
            width = w;
            height = h;
        }
    
        public void changeFillColor(Color c) {
            fillColor = c;
        }
    
        public void changeBorderColor(Color c) {
            borderColor = c;
        }
    
        public void draw(Graphics g) {
            // no need to call a super method
            // because there is none for this class
            g.setColor(fillColor);
            g.fillRect(x, y, width, height);
            g.setColor(borderColor);
            g.drawRect(x, y, width, height);
        }
    }
    

    【讨论】:

    • 抱歉回复晚了,一直忙于期末考试。非常感谢您的回答,打算试试看是否有效。
    • @Luis_V:感谢您回复我,很高兴它正在工作。
    猜你喜欢
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多