JScrollPane & Graphics2D

痴心易碎 提交于 2019-12-11 05:17:30

问题


I am trying to draw graphics that is bigger than the JFrame and use JScrollPane to scroll the entire graphics. I created a simple example with two lines. The scroll bars appear but the graphics do not show.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Test extends JPanel{

public static void main(String... args) {
    Test test = new Test();
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    panel.add(test);
    JScrollPane scrollPane = new JScrollPane(panel);
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPane.setBounds(0, 0, 1350, 700);
    JPanel contentPane = new JPanel(null);
    contentPane.setPreferredSize(new Dimension(1400, 700));
    contentPane.add(scrollPane);
    frame.setContentPane(contentPane);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
}

@Override
protected void paintComponent(Graphics g) 
{
    Graphics2D g2 = (Graphics2D)g;

    g2.drawLine(30,30,30,3000);
    g2.drawLine(30, 400, 500, 3000);
}
}

回答1:


Welcome to a wonderful example of why null layouts suck...

Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

Also see Why is it frowned upon to use a null layout in SWING? for more details...

The basic problem is, the JScrollPane, has a JViewport, which actually contains your component. The JViewport uses your components sizing hints to make determinations about how big it should be and the JScrollPane uses the decisions the JViewport makes to make determinations about whether it needs to display the scrollbars or not.

The JViewport is taking a look at your component and has decided, because you've not told it otherwise, that it should be 0x0 in size.

You can prove this by adding a LineBorder to your component, setBorder(new LineBorder(Color.RED));, you won't see it either (or if you do, it will be a little red square)

Start by overriding the getPrefferedSize method of the Test panel and return some appropriate size

Next, call super.paintComponent before you perform any custom painting, otherwise you'll end up with some awesome, but annoying, paint artifacts...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test extends JPanel {

    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Test test = new Test();
                JFrame frame = new JFrame();
                JScrollPane scrollPane = new JScrollPane(test);
                frame.add(scrollPane);
                frame.pack();
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(3000, 3000);
    }



    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        g2.drawLine(30, 30, 30, 3000);
        g2.drawLine(30, 400, 500, 3000);
    }
}

You'll probably want to take a look at the Scrollable interface next, so you can control the default size of the JViewport, so it won't try and fill the entire screen.

Take a look at Implementing a Scrolling-Savvy Client for more details




回答2:


The problem comes from the lines

JPanel panel = new JPanel();
panel.add(test);
JScrollPane scrollPane = new JScrollPane(panel);

You are adding test to panel which uses FlowLayout by default. This layout does not strech the components in it, so test on which you draw has dimensions 0x0 and what you see in the scroll pane is the empty panel.

To fix this you can set panel to use BorderLayout which stretches the center component:

JPanel panel = new JPanel(new BorderLayout());
panel.add(test);
JScrollPane scrollPane = new JScrollPane(panel);

or add test directly to the scroll pane:

JScrollPane scrollPane = new JScrollPane(test);

Additionally:

  • Always call super.paintComponent(g) as the first line when overriding paintComponent.
  • Don't use null layouts (and consequently don't set bounds on components).
  • When you use setPreferredSize remember that if the dimensions are too large they will "flow off" the screen.


来源:https://stackoverflow.com/questions/26415863/jscrollpane-graphics2d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!