Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在乐谱软件中向JPanel添加图形的正确方法_Java_Swing_Repaint - Fatal编程技术网

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

Java 在乐谱软件中向JPanel添加图形的正确方法,java,swing,repaint,Java,Swing,Repaint,我一直在开发一个记谱软件,我想用它来训练我的音乐学生的视觉阅读能力 我想知道我是否采取了正确的方法,或者是否有更好的方法 我已经使用Unicode和支持音乐符号的字体制作了谱号、音符和staff对象,代码如下: public static void spaceStaff(Graphics g){ Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, Renderin

我一直在开发一个记谱软件,我想用它来训练我的音乐学生的视觉阅读能力

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

我已经使用Unicode和支持音乐符号的字体制作了谱号、音符和staff对象,代码如下:

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;
}
然后我有一个名为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
   }
}
我正在使用此代码启动应用程序并显示音符:

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

}
该按钮应该在现有注释的末尾添加注释,但它没有

我是否使用正确的程序来做我想做的事情?非常感谢你的帮助。
我看到了这个问题,但它对我没有帮助:

一般来说,您的方法可能有效,但如果您倾向于将其应用到应用程序中,这是一种简单结构化的方法来正确工作。这里缺少数据模型。软件直接绘制注释,而不使用表示内部状态的模型

您应该看看抽象模式。首先开发一个数据模型,它与呈现注释无关

然后,开始为单个元素(例如注释)进行可视化。您将根据数据模型告诉您的内容在面板中组合组件并进行渲染。这就是在doPaintComponent方法中应该执行的操作

单击“添加注释”按钮时,应执行以下步骤:

  • 在模型中添加注释

  • 您的模型创建了一个ui事件,该事件导致调用重新绘制方法,甚至可能调用布局方法重新绘制ui,理想情况下只重新绘制需要重新绘制的部分

  • 如果在渲染过程中没有看到某些内容,请确保首先检查以下内容:

  • 您的渲染代码是否由awt线程调用
  • 您的组件是否可见
  • 你想画的位置正确吗
  • 您也许应该阅读一个或多个关于开发自定义swing组件的教程,如


    我知道答案在短期内可能对您没有帮助,但我相信在试图让代码以某种方式运行之前,最好先了解UI开发的概念

    可视化乐谱的类,它应该嵌入到应用程序中,而不是在其上启动帧。这只是为了演示MVC编码模式。 可视化严格地描述了模型(NoteSequence)所说的内容

    package com.musicsheet;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    public class MusicSheetComponent extends JPanel implements PropertyChangeListener {
      private NoteSequence noteSequence;
      public MusicSheetComponent(NoteSequence noteSequence) {
        this.noteSequence = noteSequence;
        this.noteSequence.addNoteSequenceChangedListener(this);
      }
      public static void main(String[] args) {
    
        SwingUtilities.invokeLater(() -> {
          JFrame f = new JFrame();
          NoteSequence noteSequence = new NoteSequence(); // the model
          f.setLayout(new BorderLayout()); // how should the screen be layouted
          f.add(new MusicSheetComponent(noteSequence), BorderLayout.CENTER); // the sheet component is the view, it renders whatever the model
                                                        // tells
          f.add(new JButton(new AbstractAction("Add note") {
            @Override
            public void actionPerformed(ActionEvent e) {
              noteSequence.addNote(new NoteSequence.Note((int)(Math.random()*5)));   // add a note on a random line
            }
          }), BorderLayout.SOUTH);
          f.setSize(320, 240);
          f.setVisible(true);
        });
      }
    
      @Override
      protected void paintComponent(Graphics g2d) {
        super.paintComponent(g2d);
        Graphics2D g = (Graphics2D) g2d; // graphics2d has more functions
        int w = getWidth();
        int h = getHeight();
        int lines = 5;
        int spacing = h / lines;
        paintSheetBackground(g, w, h, spacing);
        drawNotes(g, spacing);
      }
    
      private void paintSheetBackground(Graphics2D g, int w, int h, int spacing) {
        g.setColor(Color.white);
        g.fillRect(0, 0, w, h);
    
        g.setColor(Color.black);
        for (int i = 0; i < 5; i++) {
          final int y2 = i * spacing;
          g.drawLine(0, y2, w, y2);
        }
      }
    
      private void drawNotes(Graphics2D g, int heigtSpacing) {
        int xSpacing = 30;
        int x = 0;
        for (NoteSequence.Note note : noteSequence.getNotes()) {
          int y = (int) (note.getLine()*heigtSpacing);
          g.fillOval(x, y-3, 7, 6); // -3 because note should sit on line
          x+= xSpacing;
        }
      }
    
      @Override
      public void propertyChange(PropertyChangeEvent evt) {
        if (NoteSequence.PROP_NOTE_ADDED.equals(evt.getPropertyName()) || NoteSequence.PROP_NOTE_REMOVED.equals(evt.getPropertyName())) {
          repaint();
        }
      }
    }
    
    package com.musicsheet;
    导入javax.swing.*;
    导入java.awt.*;
    导入java.awt.event.ActionEvent;
    导入java.beans.PropertyChangeEvent;
    导入java.beans.PropertyChangeListener;
    公共类MusicSheetComponent扩展JPanel实现PropertyChangeListener{
    私有记事本顺序记事本顺序;
    公共音乐表组件(NoteSequence NoteSequence){
    this.noteSequence=noteSequence;
    this.noteSequence.addNoteSequenceChangedListener(this);
    }
    公共静态void main(字符串[]args){
    SwingUtilities.invokeLater(()->{
    JFrame f=新的JFrame();
    NoteSequence NoteSequence=新的NoteSequence();//模型
    f、 setLayout(newborderlayout());//屏幕应该如何布局
    f、 添加(新的MusicSheetComponent(noteSequence),BorderLayout.CENTER);//图纸组件是视图,它呈现模型中的任何内容
    //告诉
    f、 添加(新JButton)(新抽象操作(“添加注释”){
    @凌驾
    已执行的公共无效操作(操作事件e){
    noteSequence.addNote(新的noteSequence.Note((int)(Math.random()*5));//在随机行上添加注释
    }
    }),边界布局(南部);
    f、 设置大小(320240);
    f、 setVisible(真);
    });
    }
    @凌驾
    受保护的组件(图形g2d){
    超级油漆组件(g2d);
    Graphics2D g=(Graphics2D)g2d;//Graphics2D具有更多功能
    int w=getWidth();
    inth=getHeight();
    整数行=5;
    int间距=h/行;
    油漆板背景(g、w、h、间距);
    纸币(g,间距);
    }
    私有void paintSheetBackground(图形2D g、int w、int h、int间距){
    g、 setColor(Color.white);
    g、 fillRect(0,0,w,h);
    g、 设置颜色(颜色为黑色);
    对于(int i=0;i<5;i++){
    最终int y2=i*间距;
    g、 抽绳(0,y2,w,y2);
    }
    }
    专用空心图纸(图形2D g,内部高度间距){
    int xSpacing=30;
    int x=0;
    for(NoteSequence.Note:NoteSequence.getNotes()){
    int y=(int)(注意.getLine()*高度间隔);
    g、 填充椭圆(x,y-3,7,6);//-3,因为音符应该在直线上
    x+=xSpacing;
    }
    }
    @凌驾
    公共作废属性更改(属性更改事件evt){
    if(NoteSequence.PROP_NOTE_ADDED.equals(evt.getPropertyName())| | NoteSequence.PROP_NOTE_REMOVED.equals(evt.getPropertyName()){
    重新油漆();
    }
    }
    }
    
    下一步,为乐谱或音符序列建模的类

    package com.musicsheet;
    
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * The model class, that holds all notes.
     */
    public class NoteSequence {
      public static final String PROP_NOTE_ADDED = "noteAdded";
      public static final String PROP_NOTE_REMOVED = "noteRemoved";
    
      private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
      private final List<Note> notes = new ArrayList<>();
    
      public List<Note> getNotes() {
        return Collections.unmodifiableList(notes);
      }
    
      /**
       * is called by the UI or a button listener when a note should be added to this music sheet / notesequence
       * @param note
       */
      public void addNote(Note note) {
        this.notes.add(note);
        propertyChangeSupport.firePropertyChange(new PropertyChangeEvent(this, PROP_NOTE_ADDED, null, note));
      }
    
      public void removeNote(Note note) {
        this.notes.remove(note);
        propertyChangeSupport.firePropertyChange(new PropertyChangeEvent(this, PROP_NOTE_REMOVED, note, null));
      }
    
      void addNoteSequenceChangedListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
      }
    
      // not really needed atm
      void removeNoteSequenceChangedListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
      }
    
      /**
       * a single note.
       */
      public static class Note {
        private float line; // where does the note sit
        private float timestampSinceBeginning; // not used, but you have to know WHEN a note is played
        // ... more properties, e.g. name, or modifiers or whatever
    
        public Note(float line) { // this is certainly to easy, since notes can sit in between lines,
          // i did not try to think deeply into it, to define a better model
          this.line = line;
        }
    
        public float getLine() {
          return line;
        }
    
        public float getTimestampSinceBeginning() {
          return timestampSinceBeginning;
        }
      }
    }
    
    package com.musicsheet;
    导入java.beans.PropertyChangeEvent;
    导入java.beans.PropertyChangeListener;
    导入java.beans.PropertyChangeSupport;
    导入java.util.ArrayList;
    导入java.util.Collections;
    导入java.util.List;
    /**
    *模型类,它保存所有注释。
    */
    公共类注释序列{
    public static final String PROP_NOTE_ADDED=“notepadded”;
    公共静态最终字符串属性\u NOTE\u REMOVED=“noteRemoved”;
    私有属性更改支持属性更改支持=新属性更改支持(此);
    私有最终列表注释=新建ArrayList();
    公共列表getNotes(){
    返回集合。不可修改列表(备注);
    }
    /**
    *当应将音符添加到此乐谱/音符序列时,由UI或按钮侦听器调用
    *@param注释
    */
    公共无效添加注释(注释){
    本.注释.添加(注释);
    firePropertyChange(新的PropertyChangeEvent(此