JScrollPane中的JPanel在滚动

时间:2016-12-11 05:00:28

标签: java swing graphics jscrollpane

所以我做了一个简单的图形GUI,其中rigth部分是一个内部有JPanel(canvas)的JScrollPane(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);
    }
}

提前致谢 节日快乐

1 个答案:

答案 0 :(得分:4)

首先,你要重写错误的绘画方法。你不应该重写JPanel的paint方法,而应该覆盖它的paintComponent方法,因为这是一个更具体的绘画方法,默认情况下有双缓冲,做动画时有一个加号(你对你的做法很有用)滚动)。

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

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

此外,您的Box类应该是逻辑类,而不是组件类。换句话说,它不应该扩展任何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);
    }
}