我正在尝试使用按高度显示排序值的矩形来动画选择和插入排序算法的过程。
当我的选择/插入排序算法发生单个更改时,我调用repaint()
,但它似乎并没有完全重新绘制它们,只有一些矩形发生变化。在最终结果中,它实际上根本不显示完全排序的数组。
两种算法都经过测试并且可以工作,因此问题似乎在于动画处理过程。
有什么帮助吗?
MyPaint.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
public class MyPanel extends JPanel{
private static int[] mainArr;
private boolean reset = false;
private Timer t = new Timer();
private int[] tempArr;
public MyPanel(){
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(400, 400));
panel.setBackground(Color.WHITE);
panel.setLayout(new FlowLayout(FlowLayout.CENTER));
//JButton selButton = new JButton("Select Sort");
//panel.add(selButton);
add(panel);
}
public static void main(String[] args) {
SortDriver frame = new SortDriver();
mainArr = frame.getArr();
frame.setVisible(true);
}
}
SortDriver.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Graphics;
public class SortDriver extends JFrame implements ActionListener {
private int modeName;
private JButton startButton;
private JButton selButton;
private JButton insButton;
private JPanel mainPanel;
private MyPanel panel;
private int[] sortArr = new int[41];
public SortDriver() {
setLayout(null);
setPreferredSize(new Dimension(420, 420));
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
mainPanel.setBackground(Color.WHITE);
mainPanel.setBounds(0, 0, 420, 420);
mainPanel.setPreferredSize(new Dimension(400, 400));
//mainPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
add(mainPanel);
//Buttons
startButton = new JButton("Start");
startButton.addActionListener(this);
mainPanel.add(startButton);
selButton = new JButton("Select Sort");
selButton.addActionListener(this);
mainPanel.add(selButton);
insButton = new JButton("Insert Sort");
insButton.addActionListener(this);
mainPanel.add(insButton);
//Panel
panel = new MyPanel();
mainPanel.add(panel);
//Array
for(int i = 0; i <= 40; i++){
sortArr[i] = 0;
}
for(int i = 0; i <= 40; i++){
int random = (int)(Math.random() * 50 + 1);
sortArr[i] = random;
}
//Final
pack();
}
public void paint(Graphics g) {
for(int i = 0; i <= 40; i++){
g.fillRect(i * 10, 100, 5, sortArr[i]);
}
}
public void selectionSort (int[] list){
int min;
int temp;
for (int index = 0; index < list.length-1; index++){
min = index;
for (int scan = index+1; scan < list.length; scan++)
if (list[scan] - (list[min]) < 0) min = scan;
// Swap the values
temp = list[min];
list[min] = list[index];
list[index] = temp;
repaint();
}
//for(int i = 0; i <= list.length; i++){
// System.out.println(list[i]);
//}
}
public void insertionSort (int[] list){
for (int index = 1; index < list.length; index++){
int key = list[index];
int position = index;
// Shift larger values to the right
while (position > 0 && key - (list[position-1]) < 0){
list[position] = list[position-1];
position--;
repaint();
}
list[position] = key;
}
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == selButton) {
modeName = 1;
}
else if (event.getSource() == insButton) {
modeName = 2;
}
else if (event.getSource() == startButton) {
if(modeName == 1){
selectionSort(sortArr);
}
if(modeName == 2){
insertionSort(sortArr);
}
}
}
public int getMode(){
return modeName;
}
public int[] getArr(){
return sortArr;
}
}
最佳答案
首先,您不应该重写JFrame
的paint 方法。而是重写 JPanel
的 paintComponent()
来自定义绘图。您可以使用 MyPanel
来实现此目的:
public class MyPanel extends JPanel{
public MyPanel(){
setBackground(Color.WHITE);
}
public synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
// your paint code
}
}
其次,避免使用空布局。最好使用类似 BorderLayout 的东西在您的情况下为 JFrame
。
此外,您还必须注意 Event Dispatch Thread 。对 GUI 元素的操作必须在此线程上进行。
您应该在 EDT 上设置 GUI。您可以在主方法中使用 SwingUtilities.invokeLater()
来执行此操作:
SwingUtilities.invokeLater(() -> {
SortDriver frame = new SortDriver();
mainArr = frame.getArr();
frame.setVisible(true);
});
您应该考虑在单独的线程中处理动画,以便在 EDT 之外进行排序。这是一个小演示,介绍了它的原理如何工作,以您的选择排序为特色:
new Thread(() -> {
int min;
int temp;
final int delayMillis = 100;
long startTickTime = System.nanoTime();
for (int index = 0; index < list.length-1; index++){
synchronized(myPanel){
min = index;
for (int scan = index+1; scan < list.length; scan++)
if (list[scan] - (list[min]) < 0) min = scan;
// Swap the values
temp = list[min];
list[min] = list[index];
list[index] = temp;
}
myPanel.repaint();
try {
TimeUnit.NANOSECONDS.sleep(delayMillis*1000000-System.nanoTime()+startTickTime);
startTickTime = System.nanoTime();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
正如您所看到的,我将用于更新选择排序的代码放入 synchronized
block 中,以便它与 paintComponent()
方法同步。这是必要的,因为绘制发生在 EDT 上,而排序发生在与 EDT 不同的线程上。在示例中,我使用 MyPanel
对象作为监视器。
关于java - java.awt 矩形的动画未按预期运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41636669/