在乐谱软件中将图形添加到 JPanel 的正确方法

Jos*_*iah 4 java swing repaint

我一直在开发一种乐谱软件,我想用它来训练我的音乐学生视奏。

我想知道我是否采取了正确的方法,或者是否有更好的方法。

我已经设法使用支持乐谱的 unicodes 和字体使用如下代码制作谱号、音符和谱表对象:

public static void spaceStaff(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Font font = new Font("Bravura", Font.PLAIN, 32);
    g2.setFont(font);
    g2.drawString("\uD834\uDD1A", note.spacing-2, staffDistance);
    note.spacing = note.spacing + 16;
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个名为 Surface 的类,它将笔记绘制到 JPanel 上:

public class Surface extends JPanel {
@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);
    staff.spaceStaff(g);
    clef.drawGclef(g);//not given in example code above
    note.drawCrotchet(g, note.B1);//not given in example code above
   }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用此代码启动应用程序并显示音乐笔记:

public class SightreadHelper extends JFrame {

public SightreadHelper(){
    initUI();
}

private void initUI() {

    JButton button = new JButton("add notes"); //explanation for this button below
    button.setSize(150, 75);
    button.setVisible(true);
    add( button );

    button.addActionListener( new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            repaint();//this doesn't work as I expect: explanation below
        }
    });

    Surface srf = new Surface();
    add(new Surface());
    setSize(700, 1000);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            SightreadHelper srh = new SightreadHelper();
            srh.setVisible(true);
        }
    });
  }

}
Run Code Online (Sandbox Code Playgroud)

该按钮应该在现有注释的末尾添加注释,但事实并非如此。 这张图片解释了我点击按钮后会发生什么。

我是否使用正确的程序来做我想做的事情?非常感谢你的帮助。我看到了这个问题,但它对我没有帮助:在 JAVA 中重新绘制小程序而不会丢失以前的内容

小智 5

一般来说,您的方法可能有效,但如果您倾向于将其推送到应用程序,则它是结构简单的方法,可以正常工作。您在这里缺少数据模型。您的软件直接绘制注释,而无需代表内部状态的模型。

您应该看看模型视图控制器抽象模式。并首先开发一个数据模型,这与渲染笔记无关。

然后您开始为单个元素(例如注释)开发可视化。您将根据数据模型告诉您的内容在面板中组合组件并呈现它们。这就是你应该在 doPaintComponent 方法中做的事情。

当您点击按钮添加注释时,应该会发生以下步骤:

  1. 为您的模型添加注释

  2. 您的模型会创建一个 ui 事件,该事件导致调用 repaint 方法,甚至可能调用 layout 方法重绘您的 ui,理想情况下仅重绘需要重绘的部分。

如果您在渲染过程中没有看到任何内容,请确保首先检查以下事项:

  1. 你的渲染代码是由 awt 线程调用的吗?
  2. 你的组件可见吗?
  3. 您尝试绘制的位置是否正确?

您或许应该阅读一或更多关于开发自定义 Swing 组件(Oracle Tutorial Custom Swing 组件)的教程

我知道答案在短期内可能不会真正帮助你,但我相信在尝试让你的代码以某种方式运行之前理解 UI 开发的概念会更好。