【问题标题】:How can I restore the state of my GUI to its original appearance?如何将我的 GUI 状态恢复到其原始外观?
【发布时间】:2012-11-30 20:22:08
【问题描述】:

我用 Java 为使用 2D 图形的吉他和弦查找器应用程序编写了一个 GUI。程序在画布上打开一个 .jpg 图像。然后它将每个单独的音符(音品之间的空间)绘制为带有音符名称的椭圆。该程序允许用户通过更改和弦各个音符的颜色从工具栏中选择和弦,这些和弦显示在指板上。然而,每当用户选择一个新的和弦时,之前的和弦都不会被删除。我怎样才能解决这个问题?这是我的一些代码(程序超过1000行代码)。

    public class Fretboard extends JFrame  implements ActionListener{
        public static void main(String[] args) {
            JFrame frame = new Fretboard();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setVisible(true);
        }
        // Variables to be used throughout the program
        ImagePanel imageSrc;                                    
        // Declare fonts to be used
        Font font1 = new Font("SansSerif", Font.BOLD, 18);          // Font to be used for notes with # or b
        Font chordFont = new Font("SansSerif", Font.BOLD, 50);      // Font for the name of the chord displayed
        Font font = new Font("SansSerif", Font.BOLD, 20);           // Font to be used for whole note

        int h = 40, w = 26, x = 695, y = 254;

        // Declare the note variables
        // First string
        Ellipse2D E1 = new Ellipse2D.Double(x, y-110, w, h);        // E note, open 1st string
        Ellipse2D F1 = new Ellipse2D.Double(x, y, w, h);            // F note, 1st string, 1st fret
        Ellipse2D fSharp1 = new Ellipse2D.Double(x, y+125, w, h);   // F#/Gb note, 1st string, 2nd fret
        Ellipse2D G1 = new Ellipse2D.Double(x+2, y+240, w, h);      // G note, 1st string, 3rd fret

        /**
         * Create the menu bar and set title
         */

        public Fretboard() {
            // Change the title of the window
            setTitle("Fretboard Chord Finder");
            // Create a menu bar where user will be given choice of chords
            JMenuBar mb = new JMenuBar();
            setJMenuBar(mb);

            JMenu menu = new JMenu("Chords");
            // Add names of chords to the menu
            JMenuItem mi = new JMenuItem("A Major");
            mi.addActionListener(this);
            menu.add(mi);
            mi = new JMenuItem("A Minor");
            mi.addActionListener(this);
            menu.add(mi);

            Container cp = this.getContentPane();
            cp.setLayout(new FlowLayout());
            imageSrc = new ImagePanel();
            cp.add(imageSrc);
        }


        /**
         * Obtain the user's chord selection from the chord menu
         */
        public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            if("A Major".equals(command))
                paintAMajor();
            if("A Minor".equals(command))
                paintAMinor();
            }

    /**
     * Displays the notes for the A Major chord when the user selects
     * "A Major" from the toolbar.
     */
    public void paintAMajor() {
        // Declare local variables
        Graphics g = getGraphics();
        Graphics2D g2 = (Graphics2D) g;

        // Display the name of the chord
        g2.drawString("A Major Chord", 40, 150);
        g2.drawString("Notes: A, C#, E", 40, 180);

        // Display notes for the A Major chord
        // Draw the E note on the open 1st string
        // Change color to blue
        g2.setColor(Color.red);
        g2.draw(E1);
        g2.fill(E1);
        g2.setColor(Color.white);
        g2.setFont(font);
        g2.drawString("E", x+7, y-82);
        // Change color back to red
        g2.setColor(Color.red);
    }

class ImagePanel extends JPanel {
    BufferedImage image = null; 

    public ImagePanel() {
        File fretBoardFile = new File("/Users/macbook/documents/workspace/Fretboard App/Gibson_Fretboard.jpg");     // The location of the fretboard image
        // Open the image
        try {
            image = ImageIO.read(fretBoardFile);
        } 
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        setPreferredSize(new Dimension(1280, 960));
    }

    /**
     * 
     * @param bi
     */
    public ImagePanel(BufferedImage bi) {
        image = bi; 
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        // Draw the image of the fretboard on the canvas.
        // Check to see if the image is available
        if(image != null) {
            g2.drawImage(image, 25, 0, null);
        }
        else
            g2.drawRect(0, 0, getWidth()-1, getHeight()-1);

        // Draw notes
        // Draw the E note on the open 1st string
        // Change color to blue
        g2.setColor(Color.blue);
        g2.draw(E1);
        g2.fill(E1);
        g2.setColor(Color.white);
        g2.setFont(font);
        g2.drawString("E", x+7, y-82);
        // Change color back to blue
        g2.setColor(Color.blue);
}

这是程序的要点。其他一切基本上是每个单独音符的位置或显示和弦的类似方法。我被卡住了,不知道如何修复这个程序。这也是我编写的第一个 GUI。请帮忙。谢谢!

【问题讨论】:

    标签: java user-interface graphics


    【解决方案1】:

    我首先想到的是使用getGraphics()。你应该避免使用这种方法。

    Java 中的图形是无状态的。也就是说,用于渲染组件的Graphics 上下文不能保证在循环之间是相同的。您不应保留对 Graphics 上下文的引用。

    所有的绘制都应该在组件paint方法的上下文中完成,最好是JComponent#paintComponent,因为paint方法是一个复杂的方法,做了很多你真的不想做的重要工作复制。

    我会创建某种和弦“模型”,其中每个实例都能够自行绘制。然后,我将创建一个能够绘制音品和和弦的视图。

    更新示例

    这是一个概念验证示例。假设吉他弦从 5(厚度)到 0(最小)开始。

    我不是音乐家,我没有节拍或节奏,所以我可能犯了一些根本性的错误。

    public class TestFretBoard {
    
        public static void main(String[] args) {
            new TestFretBoard();
        }
    
        public TestFretBoard() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new ChordsPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class ChordsPane extends JPanel {
    
            public ChordsPane() {
                setLayout(new BorderLayout());
                FretPane fretPane = new FretPane();
                fretPane.setChord(new AChord());
                add(fretPane);
            }
        }
    
        public static interface FretBoard {
    
            public Rectangle getFretBounds(int index);
    
            public GuitarString getGuitarString(int index);
    
            public GuitarString[] getGuitarStrings(int... index);
        }
    
        public static class FretPane extends JPanel implements FretBoard {
    
            private static final Point BOARD_OFFSET = new Point(9, 9);
            private static final int BOARD_WIDTH = 84;
            private static final Rectangle[] FRET_BOUNDS = {
                new Rectangle(BOARD_OFFSET.x, 20, BOARD_WIDTH, 68 - 20),
                new Rectangle(BOARD_OFFSET.x, 71, BOARD_WIDTH, 113 - 71),
                new Rectangle(BOARD_OFFSET.x, 116, BOARD_WIDTH, 153 - 116),
                new Rectangle(BOARD_OFFSET.x, 156, BOARD_WIDTH, 189 - 156),
                new Rectangle(BOARD_OFFSET.x, 192, BOARD_WIDTH, 222 - 192),
                new Rectangle(BOARD_OFFSET.x, 225, BOARD_WIDTH, 254 - 225),
                new Rectangle(BOARD_OFFSET.x, 257, BOARD_WIDTH, 289 - 257),
                new Rectangle(BOARD_OFFSET.x, 287, BOARD_WIDTH, 312 - 287),
                new Rectangle(BOARD_OFFSET.x, 315, BOARD_WIDTH, 338 - 315),
                new Rectangle(BOARD_OFFSET.x, 341, BOARD_WIDTH, 364 - 341),
                new Rectangle(BOARD_OFFSET.x, 367, BOARD_WIDTH, 389 - 367),
                new Rectangle(BOARD_OFFSET.x, 392, BOARD_WIDTH, 412 - 392),};
            private static final GuitarString[] GUITAR_STRINGS = {
                new GuitarString(85 - BOARD_OFFSET.x, 1),
                new GuitarString(72 - BOARD_OFFSET.x, 1),
                new GuitarString(58 - BOARD_OFFSET.x, 1),
                new GuitarString(43 - BOARD_OFFSET.x, 2),
                new GuitarString(29 - BOARD_OFFSET.x, 2),
                new GuitarString(15 - BOARD_OFFSET.x, 2),};
            private BufferedImage background;
            private Chord chord;
    
            public FretPane() {
                try {
                    background = ImageIO.read(new File("fretboard02.png"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
            }
    
            public Chord getChord() {
                return chord;
            }
    
            public void setChord(Chord chord) {
                this.chord = chord;
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                if (background != null) {
                    int x = (getWidth() - background.getWidth()) / 2;
                    int y = (getHeight() - background.getHeight()) / 2;
                    g2d.drawImage(background, x, y, this);
                    Chord chord = getChord();
                    if (chord != null) {
                        g2d.translate(x, y);
                        chord.paint(this, g2d);
                        g2d.translate(-x, -y);
                    }
                }
                g2d.dispose();
            }
    
            @Override
            public Rectangle getFretBounds(int index) {
                Rectangle bounds = null;
                if (index >= 0 && index < FRET_BOUNDS.length) {
                    bounds = FRET_BOUNDS[index];
                }
                return bounds;
            }
    
            @Override
            public GuitarString getGuitarString(int index) {
                GuitarString gs = null;
                if (index >= 0 && index < GUITAR_STRINGS.length) {
                    gs = GUITAR_STRINGS[index];
                }
                return gs;
            }
    
            @Override
            public GuitarString[] getGuitarStrings(int... indices) {
                List<GuitarString> strings = new ArrayList<GuitarString>(indices.length);
                for (int index : indices) {
                    strings.add(getGuitarString(index));
                }
                return strings.toArray(new GuitarString[strings.size()]);
            }
        }
    
        public static class GuitarString {
    
            private int x;
            private int width;
    
            public GuitarString(int x, int width) {
                this.x = x;
                this.width = width;
            }
    
            public int getX() {
                return x;
            }
    
            public int getWidth() {
                return width;
            }
        }
    
        public interface Chord {
    
            public String getName();
    
            public void paint(FretBoard board, Graphics2D g2d);
        }
    
        public abstract class AbstractChord implements Chord {
    
            public abstract int[] getFrets();
    
            public abstract GuitarString[] getGuitarStrings(FretBoard board, int fret);
    
            @Override
            public void paint(FretBoard board, Graphics2D g2d) {
                for (int fret : getFrets()) {
                    Rectangle fretBounds = board.getFretBounds(fret);
                    // Guitar Strings start at 5 (thickest) to 0 (smallest)
                    GuitarString[] guitarStrings = getGuitarStrings(board, fret);
    
                    int y = fretBounds.y + (fretBounds.height / 2);
    
                    g2d.setColor(Color.RED);
                    Ellipse2D dot = new Ellipse2D.Float(0, 0, 10, 10);
    
                    for (GuitarString gs : guitarStrings) {
                        int x = ((gs.x + fretBounds.x) + (gs.width / 2)) - 5;
                        g2d.fill(getDot(dot, x, y - 5));
                    }
                }
            }
    
            public Shape getDot(Ellipse2D dot, int x, int y) {
    
                PathIterator pathIterator = dot.getPathIterator(AffineTransform.getTranslateInstance(x, y));
                Path2D path = new Path2D.Float();
                path.append(pathIterator, true);
    
                return path;
    
            }
        }
    
        public class AChord extends AbstractChord {
    
            private int index;
    
            @Override
            public String getName() {
                return "A";
            }
    
            @Override
            public int[] getFrets() {
                return new int[]{1};
            }
    
            @Override
            public GuitarString[] getGuitarStrings(FretBoard board, int fret) {
                GuitarString[] strings = new GuitarString[0];
                switch (fret) {
                    case 1:
                        strings = board.getGuitarStrings(3, 2, 1);
                        break;
                }
                return strings;
            }
    
        }
    }
    

    很多工作都涉及到图像和 UI 之间的映射,这个你要自己弄清楚,我打开 PhotoShop 并手动测量所有点。如果你自己画指板,那就更容易了。

    基本概念围绕“和弦”展开。一个和弦有一个名字,可以自己画。我已经创建了我的Chord 接口的一个简单抽象实现,它占用了大量的腿部工作并且更容易创建新的和弦(因为你只需要为它提供组成它的每个音品的音品和弦乐)和弦)

    我也建议你通读一遍

    【讨论】:

    • 如果我把所有的东西都放在paintComponent方法中,当用户做出选择时,和弦怎么显示?这是我最困惑的地方。我也不明白你所说的“模型”是什么意思,每个实例都可以自己绘制。感谢您的帮助!
    • 很高兴你问到。我已经做了一个展示基本概念的例子。
    • 哇。与我的相比,这绝对是惊人的。很多这些东西都超出了我的想象。我将尝试破译它并希望将其应用到我的程序中。再次感谢!
    【解决方案2】:

    一种方法是在每次调用paintComponent 时从头开始绘制所有内容。无条件绘制指板图像,在paintComponent中移动绘制选中线的代码,使其根据某个变量绘制线,并让actionListner将该变量设置为选中线。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-04
      • 1970-01-01
      • 2022-12-17
      • 2021-09-09
      • 1970-01-01
      • 2021-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多