Java - 在 Windows 10 上调用 Paint(),但在 OSX 10.10.5 上不调用

标签 java swing

因此,我编写了一个程序来在我的 Windows 计算机上显示 Julia 集,但是当我将完全相同的代码传输到我的 MacBook 时,paint() 方法没有被调用。

全类:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class JuliaSet extends JPanel implements MouseWheelListener {

    public double width;
    public double height;
    public double pixToCoord;
    public Complex c;
    public double iterations = 100;
    double xMin = -2;
    double xMax = 2;
    double centerY = 0;

    public JuliaSet(double width, double height) {
        this.width = width;
        this.height = height + 31;
        pixToCoord = (xMax - xMin) / width;
        c = new Complex(0.285, 0.01);
    }

    public void setC(double x, double y) {
        c.x = x;
        c.y = y;
    }

    public void paint(Graphics g) {

        pixToCoord = (xMax - xMin) / width;
        double yMin = centerY - (height * pixToCoord / 2.0);
        Graphics2D g2 = (Graphics2D) g;
        for (double y = 0; y <= height - 31; y++) {
            for (double x = 1; x <= width; x++) {
                Complex z = new Complex(x * pixToCoord + xMin, (-y + height) * pixToCoord + yMin);
                double count = 0;
                for (count = 0; count < iterations && z.magnitude() < 2; count++) {
                    z = z.multiply(z).add(c);
                }
                g2.setColor(Color.getHSBColor((float) (count / iterations), (float) 1.0, (float) (1.0 - (count / iterations))));
                g2.drawLine((int) x, (int) y - 31, (int) x, (int) y - 31);
            }
        }
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {

        double x = (double) e.getX();
        double y = (double) e.getY() - 31;
        x = x * pixToCoord + xMin;
        double yMin = centerY - (height * pixToCoord / 2.0);
        double yMax = centerY + (height * pixToCoord / 2.0);
        y = (-y + height) * pixToCoord + yMin;
        if (e.getWheelRotation() < 0) {
            xMin += 0.25 * (x - xMin);
            xMax -= 0.25 * (xMax - x);
            yMin += 0.25 * (y - yMin);
            yMax -= 0.25 * (yMax - y);
        } else {
            xMin -= (x - xMin) / 3.0;
            xMax += (xMax - x) / 3.0;
            yMin -= (y - yMin) / 3.0;
            yMax += (yMax - y) / 3.0;
        }
        centerY = (yMax + yMin) / 2.0;
        this.repaint();
    }

    public static void main(String[] args) throws InterruptedException {

        JFrame frame = new JFrame();
        frame.setTitle("Julia Set");
        frame.setBounds(0, 0, 600, 631);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JuliaSet p = new JuliaSet((double) frame.getWidth(), (double) frame.getHeight());
        frame.add(p);
        //frame.addMouseWheelListener(p);
        double angle = 0;
        long time = System.currentTimeMillis();
        while (true) {
            {Thread.sleep(16);}
            angle += Math.PI / 960.0;
            if (angle >= Math.PI * 2.0) angle = 0;
            p.setC(0.775 * Math.cos(angle), 0.775 * Math.sin(angle));
            p.repaint();
            System.out.println((int) (1000.0 / (double) (System.currentTimeMillis() - time)));
            time = System.currentTimeMillis();
        }
    }
}

有什么理由让这段代码在 Windows 上运行而不是在 OSX 上运行吗?

最佳答案

您的代码使用 while (true)Thread.sleep 以及可能的后台线程中的 Swing 组件突变更改忽略了 Swing 线程规则,因此您的问题应该问的是为什么它在任何系统上都有效。

建议:

  • 使用 SwingWorker 创建后台线程,并允许您对事件线程上的 Swing 组件进行突变更改。
  • 在paintComponent中绘制,而不是绘制,并在您的重写中调用super的绘制方法,如果您正确地重写了此方法,则在此处调用super.paintComponent(g)
  • 在后台线程中进行复杂的数学计算或任何 CPU 或时间密集型处理,并避免在绘画方法中进行。这些方法应该只用于绘画和绘画。

例如,下面是一个示例程序,它使用 SwingWorker 和图形来计算和绘制 Mandelbrot 集的各个部分(抱歉,还没有 Julia Set 实现):

enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.Window;
    import java.awt.Dialog.ModalityType;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.image.BufferedImage;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.concurrent.ExecutionException;

    import javax.swing.*;

    @SuppressWarnings("serial")
    public class Mandel2 extends JPanel {
        private static final int GUI_HEIGHT = 600;
        private static final int GUI_WIDTH = 600;
        private static final int MAX_ITERS = 50000;
        private BufferedImage image = new BufferedImage(GUI_WIDTH, GUI_HEIGHT,
                BufferedImage.TYPE_INT_ARGB);
        private Rectangle zoomRect;
        private double myX0 = -2.5;
        private double myY0 = -2.0;
        private double myX1 = 1.5;
        private double myY1 = 2.0;
        private JDialog waitDialog;

        public Mandel2() {
            final MyMouse myMouse = new MyMouse();

            int delayStartingCalc = 2 * 1000; // 2 second delay
            Timer timer = new Timer(delayStartingCalc, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    addMouseListener(myMouse);
                    addMouseMotionListener(myMouse);

                    Rectangle myRect = new Rectangle(0, 0, GUI_WIDTH, GUI_HEIGHT);
                    createMandel(myRect);
                }
            });
            timer.setRepeats(false);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet()) {
                return super.getPreferredSize();
            }
            return new Dimension(GUI_WIDTH, GUI_HEIGHT);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (image != null) {
                g.drawImage(image, 0, 0, this);
            }
            Graphics2D g2 = (Graphics2D) g;
            if (zoomRect == null) {
                return;
            }
            g2.setXORMode(Color.gray);
            g2.draw(zoomRect);
        }

        private double screenToLogicalX(double screenX) {
            return myX0 + (screenX * (myX1 - myX0)) / GUI_WIDTH;
        }

        private double screenToLogicalY(double screenY) {
            return myY0 + ((GUI_HEIGHT - screenY) * (myY1 - myY0)) / GUI_HEIGHT;
        }

        private void createMandel(Rectangle myRect) {
            double x0 = screenToLogicalX(myRect.x);
            double y0 = screenToLogicalY(myRect.y + myRect.height);
            double x1 = screenToLogicalX(myRect.x + myRect.width);
            double y1 = screenToLogicalY(myRect.y);

            myX0 = x0;
            myY0 = y0;
            myX1 = x1;
            myY1 = y1;

            MandelWorker mandelWorker = new MandelWorker(MAX_ITERS, x0, y0, x1, y1);
            mandelWorker.addPropertyChangeListener(new MandelWorkerListener());
            mandelWorker.execute();
            if (waitDialog == null) {
                Window win = SwingUtilities.getWindowAncestor(Mandel2.this);
                JProgressBar jProgressBar = new JProgressBar();
                jProgressBar.setIndeterminate(true);
                waitDialog = new JDialog(win, "Please Wait", ModalityType.APPLICATION_MODAL);
                waitDialog.add(jProgressBar);
                waitDialog.pack();
                waitDialog.setLocationRelativeTo(win);
            }
            waitDialog.setVisible(true);
        }

        private class MyMouse extends MouseAdapter {
            private Point p;

            @Override
            public void mousePressed(MouseEvent e) {
                p = e.getPoint();
            }

            public void mouseDragged(MouseEvent e) {
                zoomRect = createRect(e);
                repaint();
            };

            @Override
            public void mouseReleased(MouseEvent e) {
                zoomRect = createRect(e);
                repaint();
                createMandel(zoomRect);
            }

            private Rectangle createRect(MouseEvent e) {
                int x = Math.min(p.x, e.getX());
                int y = Math.min(p.y, e.getY());
                int width = Math.abs(p.x - e.getX());
                int height = Math.abs(p.y - e.getY());
                return new Rectangle(x, y, width, height);
            }
        }

        private class MandelWorkerListener implements PropertyChangeListener {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
                    waitDialog.setVisible(false);
                    waitDialog.dispose();
                    MandelWorker worker = (MandelWorker) evt.getSource();
                    try {
                        image = worker.get();
                        zoomRect = null;
                        repaint();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        private class MandelWorker extends SwingWorker<BufferedImage, Void> {
            private int maxIters;
            private double x1;
            private double y1;
            private double x2;
            private double y2;

            public MandelWorker(int maxIters, double x1, double y1, double x2, double y2) {
                this.maxIters = maxIters;
                this.x1 = x1;
                this.y1 = y1;
                this.x2 = x2;
                this.y2 = y2;
            }

            @Override
            protected BufferedImage doInBackground() throws Exception {
                int[][] iterGrid = new int[GUI_HEIGHT][GUI_WIDTH];
                for (int i = 0; i < GUI_HEIGHT; i++) {
                    double y = y1 + i * (y2 - y1) / GUI_HEIGHT;
                    for (int j = 0; j < GUI_WIDTH; j++) {
                        double x = x1 + j * (x2 - x1) / GUI_WIDTH;
                        int iIndex = GUI_HEIGHT - i - 1;
                        iterGrid[iIndex][j] = calcMandel(x, y);
                    }
                }

                return render(iterGrid);
            }

            private BufferedImage render(int[][] iterGrid) {
                int w = GUI_WIDTH;
                int h = GUI_HEIGHT;
                BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                Graphics2D g2 = img.createGraphics();
                for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        if (iterGrid[i][j] < maxIters) {
                            String hexCode = String.format("#%06x", (0xFFFFFF & (32 * iterGrid[i][j])));
                            g2.setColor(Color.decode(hexCode));
                        } else {
                            g2.setColor(Color.CYAN);
                        }
                        g2.drawLine(j, i, j, i);
                    }
                }
                g2.dispose();
                return img;
            }

            private int calcMandel(double x, double y) {
                Complex c = new Complex(x, y);
                Complex z = new Complex();
                int iters = 0;

                while (z.getMagnitude() < 2 && iters <= maxIters) {
                    z = z.multiply(z).add(c);
                    iters++;
                }
                return iters;
            }
        }

        private class Complex {
            private double real, imag;

            // Constructors
            public Complex() {
                real = 0.0;
                imag = 0.0;
            }

            public Complex(double real, double imag) {
                this.real = real;
                this.imag = imag;
            }

            // add given complex number to this one, returning the Complex result
            public Complex add(Complex other) {
                return new Complex(this.real + other.real, this.imag + other.imag);
            }

            // multiply given complex number by this one, returning the Complex
            // result
            public Complex multiply(Complex other) {
                return new Complex((this.real * other.real) - (this.imag * other.imag),
                        (this.imag * other.real) + (this.real * other.imag));
            }

            // get the magnitude of this complex number
            public double getMagnitude() {
                return Math.sqrt((real * real) + (imag * imag));
            }
        }

        private static void createAndShowGui() {
            Mandel2 mainPanel = new Mandel2();

            JFrame frame = new JFrame("Mandel2");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.setResizable(false);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }

        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGui();
                }
            });
        }
    }

关于Java - 在 Windows 10 上调用 Paint(),但在 OSX 10.10.5 上不调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41213121/

相关文章:

java - Jersey:让客户端抛出相同的服务器异常

java - 将 MVP 模式应用于 JDialogs

java - Spring Boot 2 中的映射资源

java - 在准备好的语句中获取列名而不是值

java - 你如何从一个按钮关闭的java swing窗口返回一个值?

java - JComboBox 的自定义字体

Java Swing 应用程序在高 DPI 屏幕上看起来很小,但它应该缩放到正常大小

java - 如何从同一应用程序服务器上运行的应用程序中查找 HornetQ 实例? (AS7)(无法实例化InitialContextFactory)

java - 如何使用带有 Gson 的 retrofit2 将空字符串视为 null

java - 如何将 MyClass 类型的实例添加到 MyClass 数组(在 MyClass 的构造函数内声明)?