Java repaint()方法不调用paintComponent
我正试图编写一个程序,使用JavaSwing可视化简单的排序算法 我有一个带有按钮的菜单,让用户选择他们希望看到的排序算法。 我的问题是,repaint在每次索引交换后都不会调用paintComponent,因此我们无法看到数组被排序。相反,一旦面板可见,程序只显示数组,显示已排序的数组 我已经尝试添加frame.revalidate,但它没有任何作用,因为我没有调整任何帧或面板,只是调整数组 我错过了什么 谢谢大家! 这是我的主类和排序类,它们都很相似Java repaint()方法不调用paintComponent,java,swing,awt,Java,Swing,Awt,我正试图编写一个程序,使用JavaSwing可视化简单的排序算法 我有一个带有按钮的菜单,让用户选择他们希望看到的排序算法。 我的问题是,repaint在每次索引交换后都不会调用paintComponent,因此我们无法看到数组被排序。相反,一旦面板可见,程序只显示数组,显示已排序的数组 我已经尝试添加frame.revalidate,但它没有任何作用,因为我没有调整任何帧或面板,只是调整数组 我错过了什么 谢谢大家! 这是我的主类和排序类,它们都很相似 import java.awt.Colo
import java.awt.Color;
import java.awt.Dimension;
import java.awt.CardLayout;
import java.util.*;
import javax.swing.*;
import java.awt.event.*;
public class AlgVisualiser implements ActionListener {
static final int N = 100;
static Integer[] arr;
static final int CONTENT_WIDTH = 800;
static final int CONTENT_HEIGHT = 800;
static JFrame frame = new JFrame("Sorting Algorithms");
static JPanel buttonPanel = new JPanel();
static JPanel arrPanel = new JPanel();
static JButton bubbleButton;
static JButton insertionButton;
static JButton selectionButton;
static Bubble bubbleSort;
static Insertion insertSort;
static Selection selectionSort;
public static void main(String[] args) {
initializeVars();
setFrame();
}
public static void setFrame() {
frame.setLayout(new CardLayout());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
frame.setLocationRelativeTo(null);
buttonPanel.setVisible(true);
frame.add(buttonPanel);
frame.add(arrPanel);
frame.pack();
}
public static void initializeVars() {
arr = new Integer[N];
arr = fillArr(arr);
arr = shuffleArr(arr);
bubbleSort = new Bubble(arr);
bubbleSort.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
insertSort = new Insertion(arr);
insertSort.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
selectionSort = new Selection(arr);
selectionSort.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
AlgVisualiser alg = new AlgVisualiser();
bubbleButton = new JButton("Bubble Sort");
bubbleButton.setPreferredSize(new Dimension(200, 200));
bubbleButton.addActionListener(alg);
selectionButton = new JButton("Selection Sort");
selectionButton.setPreferredSize(new Dimension(200, 200));
selectionButton.addActionListener(alg);
insertionButton = new JButton("Insertion Sort");
insertionButton.setPreferredSize(new Dimension(200, 200));
insertionButton.addActionListener(alg);
bubbleButton.setBackground(Color.WHITE);
selectionButton.setBackground(Color.WHITE);
insertionButton.setBackground(Color.WHITE);
buttonPanel.setBackground(Color.DARK_GRAY);
buttonPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
buttonPanel.add(bubbleButton);
buttonPanel.add(selectionButton);
buttonPanel.add(insertionButton);
arrPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
arrPanel.add(bubbleSort);
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == bubbleButton) {
buttonPanel.setVisible(false);
arrPanel.setVisible(true);
bubbleSort.sort();
} else if (event.getSource() == selectionButton) {
buttonPanel.setVisible(false);
arrPanel.setVisible(true);
insertSort.sort();
} else if (event.getSource() == insertionButton) {
buttonPanel.setVisible(false);
arrPanel.setVisible(true);
selectionSort.sort();
}
}
public static Integer[] shuffleArr(Integer[] arr) {
arr = fillArr(arr);
List<Integer> list = Arrays.asList(arr);
Collections.shuffle(list);
arr = list.toArray(arr);
return arr;
}
public static Integer[] fillArr(Integer[] arr) {
for (int i = 0; i < N; i++) {
arr[i] = i + 1;
}
return arr;
}
}
发布的代码有几个问题:
frame.getContentPane().setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
...
frame.add(buttonPanel);
frame.add(arrPanel);
及
将3个不同的组件设置为相同的大小。它们不能都是相同的大小,因为框架的内容窗格包含多个组件
不要一直设置组件的首选尺寸。每个部件都有责任确定自己的首选尺寸
对于按钮之类的组件,如果希望按钮更大,可以使用setMargins。。。方法
在进行自定义绘制时,您将重写类的getPreferredSize,因为自定义绘制代码最清楚应该是什么大小
static JPanel buttonPanel = new JPanel();
static JPanel arrPanel = new JPanel();
static JButton bubbleButton;
static JButton insertionButton;
static JButton selectionButton;
static Bubble bubbleSort;
static Insertion insertSort;
static Selection selectionSort;
不要到处使用静态变量。这表明设计不当
public static void initializeVars() {
同样,不要使用静态方法。还有设计不当
public static void initializeVars() {
您需要使用实例变量和可以访问这些实例变量的方法创建一个类
graphics2d.fillRect(0, 0, AlgVisualiser.CONTENT_WIDTH, AlgVisualiser.CONTENT_HEIGHT);
进行绘制时,不要从其他类访问变量。相反,您可以使用getWidth和getHeight方法来确定组件的当前大小,以便可以在面板的背景中填充
AlgVisualiser.frame.revalidate();
AlgVisualiser.frame.repaint();
不要重新粉刷整个框架。您只需更改自定义组件,只需重新绘制组件,而不需要重新绘制整个框架。也不需要重新验证。revalidate方法用于调用布局管理器。您没有在面板中添加或删除组件
AlgVisualiser.frame.revalidate();
AlgVisualiser.frame.repaint();
一旦面板可见,程序只显示数组,显示已排序的数组
现在是最难的部分
repaint方法只是向RepaintManager添加一个绘制请求。然后,RepaitManager将合并请求,并将绘制请求添加到事件调度线程EDT,该线程将重新绘制帧
问题是循环代码执行得太快,以至于看不到各个步骤。所以你需要用一根线睡觉。。。因此,放慢处理速度,让GUI有机会绘制每个步骤
现在你有另一个问题了。如果在EDT上使用Thread.sleep,GUI在循环执行完成之前仍然无法重新绘制自身
因此,您需要在单独的线程上执行排序代码。然后,您可以告诉排序线程休眠,并告诉GUI重新绘制自己。一种方法是使用SwingWorker
有关EDT和SwingWorker的更多信息,请阅读上的Swing教程部分。Swing基于事件。在ActionListener返回之前,不会处理任何事件。这包括重新绘制事件。因此,在调用sort的ActionListener返回之前,所有重绘调用都不会生效。您需要使用一个或一个新线程,这样排序就不会占用AWT事件调度线程。在我的SwingWorker类中,doInBackground是否应该完成排序并发布我希望由paintComponent绘制的每个不同数组,然后调用repaint来绘制我们发布的每个数组?我不知道如何使用SwingWorker来实现这一点。是的,doInBackground将发布数组的每个迭代,因此您需要在发布时制作一个副本。process方法将接收数组并使用数组的新状态更新组件,然后重新绘制自身。您不需要实现done方法,因为组件会在结果发布时不断地重新绘制自身。