repaint()方法不调用paintComponent [英] repaint() method not calling paintComponent

查看:276
本文介绍了repaint()方法不调用paintComponent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个使用Java Swing可视化简单排序算法的程序.

I'm trying to write a program that visualizes simple sorting algorithms using Java Swing.

我有一个带有按钮的菜单,可以让用户选择他们想要查看的排序算法. 我的问题是,每次索引交换后repaint()都没有调用paintComponent,因此我们看不到正在对数组进行排序.取而代之的是,程序在面板可见后才显示数组,显示已排序的数组.

I have a menu with buttons that let the user choose which sorting algorithm they would like to see. My problem is that repaint() is not calling paintComponent after every index swap, so we don't get to see the array being sorted. Instead, the program just displays the array once the panel is made visible, showing the already sorted array.

我尝试添加frame.revalidate(),但是它没有任何作用,因为我没有调整任何框架或面板,仅调整数组.

I've tried adding frame.revalidate() but it doesn't do anything since I'm not adjusting any frames or panels, just the array.

我想念什么?

谢谢!

这是我的主班和一个排序班(都差不多).

Here is my main class and a sorting class (they're all similar).

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;
    }
}

import java.awt.*;
import javax.swing.*;

public class Bubble extends JComponent {

    private static int checkedIndex1;
    private static int checkedIndex2;
    private static final long serialVersionUID = 1L;
    private Integer[] arr;

    public Bubble(Integer[] arr) {
        this.arr = arr;
    }

    public void sort() {

        for (int i = 0; i < AlgVisualiser.N - 1; i++) {
            for (int j = 0; j < AlgVisualiser.N - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    checkedIndex1 = i;
                    checkedIndex2 = j;
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    AlgVisualiser.frame.revalidate();
                    AlgVisualiser.frame.repaint();

                }
            }
        }
        checkedIndex1 = -1;
        checkedIndex2 = -1;
        AlgVisualiser.frame.revalidate();
        AlgVisualiser.frame.repaint();
    }

    @Override
    public void paintComponent(Graphics g) {

        Graphics2D graphics2d = (Graphics2D) g;
        graphics2d.setColor(Color.DARK_GRAY);
        graphics2d.fillRect(0, 0, AlgVisualiser.CONTENT_WIDTH, AlgVisualiser.CONTENT_HEIGHT);

        for (int i = 0; i < arr.length; i++) {

            int width = (int) (AlgVisualiser.CONTENT_WIDTH / (double) AlgVisualiser.N);
            int height = arr[i] * (AlgVisualiser.CONTENT_HEIGHT / AlgVisualiser.N);
            int x = i * width;
            int y = AlgVisualiser.CONTENT_HEIGHT - height;

            if (i == checkedIndex1 || i == checkedIndex2) {
                graphics2d.setColor(Color.RED);
            } else if (checkedIndex1 == -1) {
                graphics2d.setColor(Color.GREEN);

            } else {
                graphics2d.setColor(Color.WHITE);
            }

            graphics2d.fillRect(x, y, width, height);
        }
    }

}

推荐答案

发布的代码存在几个问题:

There are several problems with the posted code:

    frame.getContentPane().setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
    ...
    frame.add(buttonPanel);
    frame.add(arrPanel);

    bubbleSort.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
    ...
    arrPanel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
    arrPanel.add(bubbleSort);

您将3个不同的组件设置为相同的大小.它们的大小不能全部相同,因为框架的内容窗格包含多个组件.

You set 3 different components to the same size. They can't all be the same size, since the content pane of the frame contains multiple components.

不要一直设置组件的首选大小.每个组件都有责任确定自己的首选大小.

Don't keep setting the preferred size of components. It is the responsibility of each component to determine its own preferred size.

对于按钮等组件,如果希望按钮更大,可以使用setMargins(...)方法.

With components like buttons, if you want the button bigger, you can use the setMargins(...) method.

进行自定义绘制时,您将覆盖该类的getPreferredSize(),因为自定义绘制代码最清楚应该是什么大小.

When doing custom painting, you would override the getPreferredSize() of the class, since your custom painting code knows best what the size should be.

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;

不要在任何地方使用静态变量.这表明设计不当.

Don't use static variable everywhere. This indicates improper design.

public static void initializeVars() {

同样,不要使用静态方法.也是不正确的设计.

Again, don't use static methods. Also improper design.

您需要创建一个包含实例变量和可以访问这些实例变量的方法的类.

You need to create a class with instance variables and method that can access these instance variables.

graphics2d.fillRect(0, 0, AlgVisualiser.CONTENT_WIDTH, AlgVisualiser.CONTENT_HEIGHT);

在绘画时不要从另一个类访问变量.取而代之的是,您可以使用getWidth()getHeight()方法来确定组件的当前大小,以便可以在面板的背景中进行填充.

Don't access variable from another class when doing painting. Instead you would use the getWidth() and getHeight() methods to determine the current size of the component so you can fil in the background of the panel.

    AlgVisualiser.frame.revalidate();
    AlgVisualiser.frame.repaint();

不要重新绘制整个框架.您只需要更改自定义组件,只需要重新绘制组件即可,而无需重新绘制整个框架.也不需要reavalidate(). revalidate()方法用于调用布局管理器.您没有在面板中添加或删除组件.

Don't repaint the entire frame. You are only changing your custom component you you only need to repaint the component, not the entire frame. There is also no need for the reavalidate(). The revalidate() method is used to invoke the layout manager. Your are not adding or removing components from the panel.

一旦使面板可见,该程序就只显示数组,显示已排序的数组.

the program just displays the array once the panel is made visible, showing the already sorted array.

现在是最困难的部分.

repaint()方法仅将绘画请求添加到RepaintManager.然后,RepaintManager将合并请求,并将绘制请求添加到事件调度线程"(EDT),以重新绘制框架.

The repaint() method just adds a paint request to the RepaintManager. The RepaintManager will then consolidate requests and add a paint request to the Event Dispatch Thread (EDT) which will repaint the frame.

问题在于您的循环代码执行得如此之快,以至于您看不到各个步骤.因此,您需要使用Thread.sleep(...),以便减慢处理速度,以便GUI可以绘制每个步骤.

The problem is your looping code executes so fast that you don't see the individual steps. So you need to use a Thread.sleep(...) so slow down processing to give the GUI a chance to paint each step.

现在您还有另一个问题.如果在EDT上使用Thread.sleep(),则在循环执行完成之前,GUI仍无法重绘自身.

Now you have another problem. If you use Thread.sleep() on the EDT, the GUI still can't repaint() itself until the loop is finished executing.

因此,您需要在单独的线程上执行排序代码.然后,您可以告诉排序线程进入睡眠状态,并告诉GUI重新绘制自身.一种方法是使用SwingWorker.

So you need to execute the soring code on a separate Thread. Then you can tell the sorting Thread to sleep and tell the GUI to repaint itself. One way to do this is to use a SwingWorker.

并发上,从Swing教程中阅读本节.有关EDTSwingWorker的更多信息.

Read the section from the Swing tutorial on Concurrency for more information on the EDT and the SwingWorker.

这篇关于repaint()方法不调用paintComponent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆