如何在JScrollPane中实现图形? [英] How to implement graphics to JScrollPane?

查看:84
本文介绍了如何在JScrollPane中实现图形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目标是在窗口上绘制几十万条垂直线,因此,我需要滚动条,因为将每一行分开的空间甚至都不是像素,所以不能选择缩小.我采用了在类中使用paint方法并将类和JScrollPane都添加到JFrame的方法.无法解决,这就是为什么我采用了使用NetBeans JFrame Form的方法.基本上,如何将我的图形方法实现到具有滚动条的面板中?我遇到的问题是我的值在打印机上正常,但是根本没有窗口出现.如果需要任何其他信息,请告诉我.谢谢.

The objective is to draw a couple hundred thousand vertical lines to a window, for which reason I need a scroll bar, zooming out is not an option as the space separating each individual line is not even a pixel. I have taken the approach of using paint methods in a class and adding both the class and JScrollPane to a JFrame. Didn't work out which is why I took the approach of using the NetBeans JFrame Form. Basically, how do I implement my graphics method into the panel that has the scroll bar? The problem I'm having is that my values are being printer just fine, but the no window appears at all. If any additional information is required, let me know. Thanks.

public class PedroGUI extends javax.swing.JFrame {
    public PedroGUI() {
        initComponents();
        draw();
    }
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        scroll = new javax.swing.JScrollPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        scroll.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        scroll.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(scroll, javax.swing.GroupLayout.PREFERRED_SIZE, 429, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(123, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(scroll, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(86, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        


    public void draw() {
        Graphics g = scroll.getGraphics();
        g.setColor(Color.red);
        int bytes, samples, frequency;
        try {
            FileInputStream fis = new FileInputStream("./pepe.wav");
            BufferedInputStream bis = new BufferedInputStream(fis);
            byte[] data = new byte[128];
            bis.skip(44);
            samples = 0;
            while ((bytes = bis.read(data)) > 0) {
                for (int i = 0; i < bytes; i++) {
                    frequency = data[i] & 0xFF; 
                    System.out.println(samples + " " + frequency);
                    g.drawLine(samples, frequency + 300, samples, -frequency + 300);
                    samples++;
                }

            }
            bis.read(data);
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                PedroGUI a = new PedroGUI();
                a.draw();
            }
        });
    }

    private javax.swing.JScrollPane scroll;

}

推荐答案

通常通过重写基于JComponent的类的paintComponent来实现绘画.您不想做的是尝试覆盖JScrollPanepaint/paintComponent,并且最肯定不使用getGraphics.

Painting is typically achieved by overriding paintComponent of a JComponent based class. What you don't want to do is to try and either override paint/paintComponent of the JScrollPane and most certainly not use getGraphics.

getGraphics返回组件上最后绘制的快照,如果尝试对其进行绘制,则下次绘制组件时将丢弃该快照,因为Swing使用被动渲染算法,这可能立即完成或在将来的某个随机时间完成(这就是为什么要使用paintComponent的原因)

getGraphics returns a snap shot of the last thing that was painted to the component, if you try and paint to this it will be discard the next time the component is painted, because Swing uses a passive rendering algorithm, this might be done immediately or at some random time in the future (this is why you should use paintComponent)

绘画也具有破坏性,也就是说,您应该从头开始重新绘制组件的状态.

Painting is also destructive, that is, you are expected to repaint the state of the component from scratch.

JScrollPane也是一个复合组件,也就是说,还有许多其他组件用于实现其功能(即JViewport)

JScrollPane is also a composite component, that is, there are a number of other components which are used to implement it's functionality (namely the JViewport)

您可能应该做的是创建一个自定义组件,该组件从类似JPanel的内容扩展,并覆盖它的paintComponent方法,并从其中生成图形.

What you should probably do, is create a custom component, extending from something like JPanel, and override it's paintComponent method and generate your graph from within in it.

此示例还利用了Scrollable接口,该接口允许JScrollPane最初的布局小于组件的首选大小,这很好,因为组件可能非常宽.

This example also makes use of the Scrollable interface, which allows the JScrollPane to be laid out initially smaller then the preferred size of the component, which is good, as the component might be VERY wide.

此示例还只是生成了一个简单的直方图,但您会得到jist

This example also just generates a simple histogram, but you get the jist

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;

public class Main {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });
    }

    public Main() {
        // For this example, I just randomised some data, you would
        // Need to load it yourself...
        int width = 256;
        int height = 256;
        int[][] data = new int[width][height];
        for (int c = 0; c < height; c++) {
            for (int r = 0; r < width; r++) {
                data[c][r] = (int) (256 * Math.random());
            }
        }
        Map<Integer, Integer> mapHistory = new TreeMap<Integer, Integer>();
        for (int c = 0; c < data.length; c++) {
            for (int r = 0; r < data[c].length; r++) {
                int value = data[c][r];
                int amount = 0;
                if (mapHistory.containsKey(value)) {
                    amount = mapHistory.get(value);
                    amount++;
                } else {
                    amount = 1;
                }
                mapHistory.put(value, amount);
            }
        }
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new JScrollPane(new Graph(mapHistory)));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    protected class Graph extends JPanel implements Scrollable {

        protected static final int MIN_BAR_WIDTH = 4;
        private Map<Integer, Integer> mapHistory;

        public Graph(Map<Integer, Integer> mapHistory) {
            this.mapHistory = mapHistory;
        }

        @Override
        public Dimension getPreferredSize() {
            int width = (mapHistory.size() * MIN_BAR_WIDTH) + 11;
            return new Dimension(width, 256);
        }

        @Override
        public Dimension getMinimumSize() {
            int width = (mapHistory.size() * MIN_BAR_WIDTH) + 11;
            return new Dimension(width, 128);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (mapHistory != null) {
                int xOffset = 5;
                int yOffset = 5;
                int width = getWidth() - 1 - (xOffset * 2);
                int height = getHeight() - 1 - (yOffset * 2);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(Color.DARK_GRAY);
                g2d.drawRect(xOffset, yOffset, width, height);
                int barWidth = Math.max(MIN_BAR_WIDTH,
                                (int) Math.floor((float) width
                                                / (float) mapHistory.size()));
                int maxValue = 0;
                for (Integer key : mapHistory.keySet()) {
                    int value = mapHistory.get(key);
                    maxValue = Math.max(maxValue, value);
                }
                int xPos = xOffset;
                for (Integer key : mapHistory.keySet()) {
                    int value = mapHistory.get(key);
                    int barHeight = Math.round(((float) value
                                    / (float) maxValue) * height);
                    g2d.setColor(new Color(key, key, key));
                    int yPos = height + yOffset - barHeight;
                    Rectangle2D bar = new Rectangle2D.Float(
                                    xPos, yPos, barWidth, barHeight);
                    g2d.fill(bar);
                    g2d.setColor(Color.DARK_GRAY);
                    g2d.draw(bar);
                    xPos += barWidth;
                }
                g2d.dispose();
            }
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return new Dimension(512, 256);
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 128;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 128;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return getPreferredSize().width
                            <= getParent().getSize().width;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return getPreferredSize().height
                            <= getParent().getSize().height;
        }
    }
}

请参见 AWT和Swing中的绘画执行自定义绘画

See Painting in AWT and Swing, Performing Custom Painting and How to Use Scroll Panes for more details

这篇关于如何在JScrollPane中实现图形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆