繁体   English   中英

如何将GUI的状态恢复为原始外观?

[英]How can I restore the state of my GUI to its original appearance?

我用Java编写了一个GUI,用于使用2D图形的吉他和弦查找器应用程序。 该程序在画布上打开.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。 请帮忙。 谢谢!

跳出来的第一件事就是使用getGraphics() 您应该避免使用此方法。

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

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

我会创建一种和弦的“模型”,每个实例都能够自己绘制它。 然后我会创建一个能够画出音品和和弦的视图。

以示例更新

这是一个概念证明的例子。 假设吉他弦从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;
        }

    }
}

图像和用户界面之间的映射有很多工作,你可以自己搞清楚,我打开了PhotoShop并手动测出了所有的点数。 如果你自己画出音板,它会变得更容易。

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

我也建议你仔细阅读

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM