java - java.awt 矩形的动画未按预期运行

标签 java swing user-interface graphics

我正在尝试使用按高度显示排序值的矩形来动画选择和插入排序算法的过程。

当我的选择/插入排序算法发生单个更改时,我调用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 方法。而是重写 JPanelpaintComponent() 来自定义绘图。您可以使用 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/

相关文章:

java - 如何使用Java Scanner读取非英文字符?

java - WebSphere Liberty——从 Java 连接到安全网关

可滚动表的 Java Swing 布局?

java - Vaadin - 动态生成表

c# - 在 C# 中手动复制文件时显示复制文件对话框/表单?

Java AES 解密带有错误 header 的 zip 文件

java - 在 Linux 中不使用 sudo 查找进程名称

java - JComboBox getSelectedIndex 不工作两次?

java - 触发 Java GUI 更新

JavaFX:如何为组合框设置操作?