我正在尝试动画选择和放大的过程。插入排序算法,矩形按高度显示排序值。
当我的选择/插入排序算法发生单个更改时,我调用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;
}
}
答案 0 :(得分:1)
首先,您不应该覆盖JFrame
的绘制方法。而是覆盖paintComponent()
的{{1}}以进行自定义绘图。您可以将JPanel
用于此目的:
MyPanel
其次,避免使用null布局。在您的案例中,最好使用public class MyPanel extends JPanel{
public MyPanel(){
setBackground(Color.WHITE);
}
public synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
// your paint code
}
}
之类的JFrame
。
此外,您必须了解BorderLayout。 GUI元素的操作必须在这个线程上进行。
您应该在EDT上设置GUI。您可以使用main-method中的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
块,以便与paintComponent()
方法同步。这是必要的,因为绘画发生在EDT上,而排序发生在不同于EDT的线程上。在示例中,我使用MyPanel
对象作为监视器。