【问题标题】:painting on JPanel line is not connectedJPanel线上的绘画未连接
【发布时间】:2017-04-12 17:09:54
【问题描述】:

我试图使用带有 Graphics2D 绘制形状的 JPanel 绘制方法制作图表。但是,我的线没有连接,它们的斜率为 0。我的期望是像信号波一样绘制线。这是我的代码:

package action;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.geom.Line2D;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Starter extends JFrame {
double Xoffset = 30, Yoffset = 20, Xold = 40, Ycurr = 40, Xcurr = Xold, 
Ytarget = Ycurr, Xgap = 10, Ygap = 60;
double sh = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
double sw = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
int panelOffSet = 20;

double[] value_old = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
double[] value_curr = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 
};// new

// double[17];
    int counter = 0;

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Starter mainThread = new Starter();
}

public Starter() {
    super("EEG Recorder");
    // //set the frame to center of screen
    setLayout(null);
    this.getContentPane().setBackground(new Color(32, 32, 32));
    setSize((int) sw, (int) sh);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // add the painting panel
    EEGRecorder plotter = new EEGRecorder();
    add(plotter);
    this.setVisible(true);
    while (true) {
        plotter.run();
    }
}

class EEGRecorder extends JPanel implements Runnable {

    public EEGRecorder() {
        setLayout(null);
        setBackground(new Color(32, 32, 32));
        setBounds(0, panelOffSet, (int) sw, (int) (sh - panelOffSet));
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            this.updateUI();
            repaint();
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // System.out.println("hello");
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D gg = (Graphics2D) g;
        for (int i = 1; i < 17; i++) {

            Random rn = new Random();
            Ytarget = rn.nextDouble() * 30;
            value_curr[i] = Ytarget;
            // System.out.println(value_curr[i]);

            if (Xcurr + Xgap - 1 > sw) {
                gg.clearRect((int) Xoffset, (int) Yoffset, (int) (sw - Xoffset - 20), (int) (sh - panelOffSet));
                gg.setColor(new Color(32, 32, 32));
                gg.fillRect(0, 0, (int) (sw), (int) (sh - panelOffSet));
                Xold = Xoffset;
                Xcurr = Xold + Xgap;
            } else {
                gg.setColor(Color.yellow);
                gg.drawString("ch" + i, 4, (int) (Yoffset + (i - 1) * Ygap));
                if (counter == 0) {
                    value_old[i] = 0;// value_curr[i];
                    Xcurr = Xold + Xgap;

                }
                gg.setColor(Color.BLUE);
                gg.draw(new Line2D.Double(Xold, (i - 1) * Ygap - value_old[i], Xcurr,
                        (i - 1) * Ygap - value_curr[i]));
                double Yold=(i - 1) * Ygap - value_old[i];
                double Ynew=(i - 1) * Ygap - value_curr[i];
                System.out.println(Xold+","+Yold+","+ Xcurr+","+Ynew);
            }
        }

        value_old = value_curr;

        // Ycurr = Ytarget;

        Xold = Xcurr;
        Xcurr += Xgap;
        counter++;
    }
}

}

【问题讨论】:

  • 我仍在尝试找出这段代码中的问题,有人知道吗?
  • while (true) { 在这种情况下非常危险; this.updateUI(); 与您尝试做的事情无关,看起来您只是随机调用“听起来”不错的方法 - 我建议阅读 updateUI 上的文档,基本上,永远不要再调用它
  • 您还破坏了记录在案的油漆链,这将产生无穷无尽的问题 - 我强烈建议您阅读 Painting in AWT and SwingPerforming Custom Painting
  • 另外,绘制方法不应该更新状态,它们应该只绘制当前状态。您应该尽可能减少逻辑,以便在其他地方做出许多决定 - 为什么?可以出于多种原因随时调用 Paint,其中许多原因是您无法控制的
  • 绘画也是破坏性的。预计每次调用paint时,您将重新绘制整个状态,而不仅仅是更新它。这让您有两个选择。您要么设计一个模型来维护组件完全绘制自身所需的信息,要么绘制到后备缓冲区。

标签: jpanel double line draw


【解决方案1】:

我可能会花很多时间向您解释为什么您的代码无法正常工作以及如何修复它,不用说,您需要退后一步并进行大量更改。

我强烈建议您花时间通读一遍:

现在,由于 Swing 中绘画的工作方式,您有两种选择。

您可以使用某种模型来维护您想要绘制的信息,并且当绘制周期发生时,您使用此信息更新组件,或者您绘制到后备缓冲区并在绘制周期发生时将其绘制到组件

我选择使用数据模型,它更简单,因为我不需要监视组件的状态并更新缓冲区,但我就是这样。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Starter {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Starter mainThread = new Starter();
            }
        });
    }

    public Starter() {
        JFrame frame = new JFrame("EEG Recorder");
        EEGRecorder plotter = new EEGRecorder();
        frame.add(plotter);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setVisible(true);
    }

    class EEGRecorder extends JPanel {

        double Xoffset = 30, Yoffset = 20, Xold = 40, Ycurr = 40, Xcurr = Xold,
                Ytarget = Ycurr, Xgap = 10, Ygap = 60;

        private List<List<Point2D>> series;

        public EEGRecorder() {
            series = new ArrayList<>(16);
            for (int line = 0; line < 16; line++) {
                series.add(new ArrayList<>(100));
            }
            setBackground(new Color(32, 32, 32));
            Timer timer = new Timer(50, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    update();
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void update() {
            int count = 1;
            for (List<Point2D> line : series) {
                Point2D last = new Point2D.Double(0, 0);
                if (line.size() > 0) {
                    last = line.get(line.size() - 1);
                }

                Random rn = new Random();
                double y = (rn.nextDouble() * 30) + (Yoffset + (count - 1) * Ygap);
                double x = Xoffset;

                int sw = getWidth();
                if (last.getX() + Xgap - 1 > sw) {
                    line.clear();
                } else {
                    x = last.getX() + Xgap;
                }

                line.add(new Point2D.Double(x, y));
                count++;
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.

            Graphics2D gg = (Graphics2D) g.create();
            int count = 1;
            for (List<Point2D> line : series) {
                gg.setColor(Color.yellow);
                gg.drawString("ch" + count, 4, (int) (Yoffset + (count - 1) * Ygap));
                gg.setColor(Color.BLUE);
                Point2D fromPoint = null;
                for (Point2D toPoint : line) {
                    if (fromPoint != null) {
                        gg.draw(new Line2D.Double(fromPoint, toPoint));
                    }
                    fromPoint = toPoint;
                }
                count++;
            }
            gg.dispose();
        }
    }
}

这不是从头开始系列,而是在到达组件末尾时保留一些旧信息,我只是清除系列并重新开始。

要让它“重叠”需要一个更复杂的模型,我很懒

【讨论】:

  • 感谢您的启发。您的代码正在运行,我试图弄清楚为什么我的代码不起作用。基本上我所做的至少对我来说似乎是合理的,但我花了大约 5 个小时试图找出问题。我的代码到底做错了什么?
  • 两个核心问题。你 run 循环,这可能会阻塞 EDT 或以其他方式从 EDT 外部更新 UI,这都是一个坏主意,而且你没有调用 super.paint 的事实,从而破坏了绘制链 - 虽然这并没有“看起来”很糟糕,Graphics 是 Swing 组件之间的共享资源,这意味着之前绘制到上下文中的任何内容在提供给您时仍然存在,绘制链的一部分责任是在组件被绘制
猜你喜欢
  • 2017-03-10
  • 2011-07-16
  • 2017-08-31
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
相关资源
最近更新 更多