如何实现图形到JScrollPane?
How to implement graphics to JScrollPane?
objective 是在 window 上绘制几十万条垂直线,因此我需要一个滚动条,缩小不是一个选项,因为 space分隔每条线甚至不是一个像素。我采用了在 class 中使用绘画方法并将 class 和 JScrollPane 添加到 JFrame 的方法。没有解决这就是为什么我采用使用 NetBeans JFrame 表单的方法。基本上,我如何将我的图形方法实现到具有滚动条的面板中?我遇到的问题是我的值在打印机上很好,但根本没有 window 出现。如果需要任何其他信息,请告诉我。谢谢
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
的 class 的 paintComponent
来实现的。您不想做的是尝试覆盖 JScrollPane
的 paint/paintComponent
并且肯定不会使用 getGraphics
.
getGraphics
returns 绘制到组件的最后一个东西的快照,如果你尝试绘制到这个,它将在下次绘制组件时被丢弃,因为 Swing使用被动渲染算法,这可能会立即或在将来的某个随机时间完成(这就是为什么你应该使用 paintComponent
)
绘制也是破坏性的,也就是说,你应该从头开始重新绘制组件的状态。
JScrollPane
也是一个复合组件,也就是说,还有一些其他的组件用来实现它的功能(即JViewport
)
您可能应该做的是创建一个自定义组件,从类似 JPanel
的东西扩展,并覆盖它的 paintComponent
方法并从中生成您的图表。
此示例还使用了 Scrollable
接口,它允许 JScrollPane
最初的布局小于组件的首选大小,这很好,因为组件可能是很宽。
这个例子也只是生成一个简单的直方图,但你明白了要点
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;
}
}
}
有关详细信息,请参阅 Painting in AWT and Swing, Performing Custom Painting and How to Use Scroll Panes
objective 是在 window 上绘制几十万条垂直线,因此我需要一个滚动条,缩小不是一个选项,因为 space分隔每条线甚至不是一个像素。我采用了在 class 中使用绘画方法并将 class 和 JScrollPane 添加到 JFrame 的方法。没有解决这就是为什么我采用使用 NetBeans JFrame 表单的方法。基本上,我如何将我的图形方法实现到具有滚动条的面板中?我遇到的问题是我的值在打印机上很好,但根本没有 window 出现。如果需要任何其他信息,请告诉我。谢谢
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
的 class 的 paintComponent
来实现的。您不想做的是尝试覆盖 JScrollPane
的 paint/paintComponent
并且肯定不会使用 getGraphics
.
getGraphics
returns 绘制到组件的最后一个东西的快照,如果你尝试绘制到这个,它将在下次绘制组件时被丢弃,因为 Swing使用被动渲染算法,这可能会立即或在将来的某个随机时间完成(这就是为什么你应该使用 paintComponent
)
绘制也是破坏性的,也就是说,你应该从头开始重新绘制组件的状态。
JScrollPane
也是一个复合组件,也就是说,还有一些其他的组件用来实现它的功能(即JViewport
)
您可能应该做的是创建一个自定义组件,从类似 JPanel
的东西扩展,并覆盖它的 paintComponent
方法并从中生成您的图表。
此示例还使用了 Scrollable
接口,它允许 JScrollPane
最初的布局小于组件的首选大小,这很好,因为组件可能是很宽。
这个例子也只是生成一个简单的直方图,但你明白了要点
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;
}
}
}
有关详细信息,请参阅 Painting in AWT and Swing, Performing Custom Painting and How to Use Scroll Panes