这是我正在构建https://github.com/chrisbramm/LastFM-History-Graph的应用程序。
以下是src/lastfmhistoryclasses
中控制器类的一部分。创建OutputGUIView
后,它会创建三个组件JPanel graphPanel
,这会添加到JScrollPane graphScrollPanel
和另一个JPanel autocompletePanel
。然后将这些全部添加到JFrame OutputGUIView
。然后,下面的监听器会更改graphPanel
的首选大小,并且当您第一次按下按钮时,UI会更新,以显示graphPanel
的大小已增加且graphScrollPanel
的滚动条已更改。< / p>
但是现在,如果按另一个按钮,首选大小会更改,但UI不会更新,如果您更改窗口尺寸,则会执行此操作,让我们说最大化它。
class Zoom2000 implements ActionListener{
public void actionPerformed(ActionEvent e){
outputGUIView.graphPanel.setPreferredSize(new Dimension(screenWidth, 2000));
outputGUIView.graphScrollPanel.updateUI();
}
}
class ZoomDefault implements ActionListener{
public void actionPerformed(ActionEvent e){
outputGUIView.graphPanel.setPreferredSize(new Dimension(screenWidth, screenHeight));
outputGUIView.graphScrollPanel.updateUI();
}
}
class Zoom6000 implements ActionListener{
public void actionPerformed(ActionEvent e){
outputGUIView.graphPanel.setPreferredSize(new Dimension(screenWidth, 6000));
outputGUIView.graphScrollPanel.updateUI();
}
}
我已经尝试了不同的东西,例如invalidate/validate/revalidate
(并重新绘制)各种组件,而graphPanel只是坐在那里,只有在你改变窗口尺寸时才重新绘制。
任何想法我做错了什么?
编辑更新: 这是GraphPanel类:
package lastfmhistoryguis;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
import de.umass.lastfm.*;
import lastfmhistoryclasses.*;
SuppressWarnings("serial")
public class GraphPanel extends JPanel {
private LastFMHistory graphData;
private int graphHeight;
private int graphWidth;
private int zoom;
private final int PAD = 20;
public GraphPanel(LastFMHistory model, int zoom){
this.graphData = model;
if (zoom != 1){
this.zoom = zoom;
}else{
this.zoom = 1;
System.out.println("getHeight() returning:" + getHeight());
}
System.out.println("Width" + getWidth() + "Height" + getHeight());
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Drawing");
Graphics2D graph = (Graphics2D) g;
if (graphData == null) {
System.err.println("No data found");
} else {
System.out.println("paintComponent Width" + getWidth() + "Height" + getHeight());
graphWidth = getWidth() - 5 * PAD;
//graphHeight = getHeight() - 2 * PAD;
graphHeight = 6000 - 2* PAD;
System.out.println(graphWidth + ", " + graphHeight);
int x0 = graphWidth + PAD;
graph.draw(new Rectangle2D.Double(PAD, PAD, graphWidth, graphHeight));
double xInc = (double) (graphWidth) / (graphData.dayMax);
double secondHeight = (double) (graphHeight) / 86400;
for (int i = 0; i <= 86400; i++) {
if (i % 3600 == 0) {
graph.draw(new Line2D.Double(x0, (i * secondHeight) + PAD,
x0 + 10, (i * secondHeight) + PAD));
String hour = Integer.toString(i / 3600);
graph.drawString(hour, x0 + 15,
(int) ((i * secondHeight) + PAD));
}
}
for (Track t : graphData.history) {
if (t.getPlayedWhen() != null) {
Color color = t.getColour();
int duration = t.getDuration();
int day = Math.abs(t.getDay());
double dayOrigin = x0 - ((day + 1) * xInc);
double timeOrigin = t.getGraphHeight() * secondHeight + PAD;
double trackHeight = duration * secondHeight;
graph.setColor(color);
// System.out.println("PLOTTING TRACK, " + day + ", " +
// dayOrigin + ", " + t.getGraphHeight() + ", " + timeOrigin
// + ", " + trackHeight);
// graph.draw(new Rectangle2D.Double(dayOrigin, timeOrigin,
// xInc, trackHeight));
graph.fillRect((int) dayOrigin, (int) timeOrigin,
(int) xInc, (int) trackHeight);
}
}
for (int i = 0; i < graphData.dayMax;){
graph.draw(new Line2D.Double(x0 - i * xInc, PAD, x0 - i * xInc, graphHeight + PAD));
i = i + 7;
}
}
}
public void zoom(int zoom){
this.zoom = zoom;
repaint();
}
}
它创建一个Graphics2D对象,在该对象上绘制一个大的轮廓矩形,然后将每个轨道矩形绘制到此Graphics2D图形对象的某个位置。现在我已经删除了setPreferredSize as recommended here的使用但现在我遇到的问题是当我手动将GraphPanel中的graphHeight设置为高度为6000时,graphScrollPanel没有意识到它包含的graphPanel实际上是更大的所有graphHeight正在绘制一个~6000px高的矩形。那么在这种情况下我应该使用setPreferredSize还是有另一种方法来设置Graphics2D对象的大小?
答案 0 :(得分:4)
请勿致电updateUI
这与UI外观和API相关,与重新绘制无关。
您尝试/正在使用哪些布局管理器?
调用invalidate()
,repaint()
应该影响父容器布局管理器并使它们相应地重新布局组件,但是你需要记住,布局管理器只使用min / max / pref尺寸信息作为指南。
我的例子中最好的客人是你应该试着打电话
outputGUIView.graphPanel.invalidate();
outputGUIView.graphPanel.repaint();
和/或
outputGUIView.invalidate();
outputGUIView.repaint();
在滚动窗格中调用invalidate可能不会实现很多,因为视口负责布局内容,而不是滚动窗格。
如果你真的很绝望,你可以试试
outputGUIView.graphScrollPanel.getViewport().invalidate();
outputGUIView.graphScrollPanel.getViewport().repaint();