问题描述
目标是在窗口上绘制几十万条垂直线,因此,我需要滚动条,因为将每一行分开的空间甚至都不是像素,所以不能选择缩小.我采用了在类中使用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
来实现绘画.您不想做的是尝试覆盖JScrollPane
的paint/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中实现图形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!