简体   繁体   English

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

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

I wrote a GUI in Java for a guitar chord finder application using 2D graphics. 我用Java编写了一个GUI,用于使用2D图形的吉他和弦查找器应用程序。 The program opens an .jpg image on the canvas. 该程序在画布上打开.jpg图像。 It then draws each individual note (space between the frets) as an ellipse with the name of the note. 然后它将每个单独的音符(音柱之间的空格)绘制为带有音符名称的椭圆。 The program allows the user to select chords from a toolbar where they are displayed on the the fretboard by changing the color of the chord's individual notes. 该程序允许用户通过改变和弦的各个音符的颜色,从工具栏中选择和弦显示在指板上的和弦。 However, whenever the user selects a new chord, the previous chord is not deleted. 但是,每当用户选择新的和弦时,不会删除前一个和弦。 How can I fix this? 我怎样才能解决这个问题? Here is some of my code (The program is over 1000 lines of code). 这是我的一些代码(该程序超过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);
}

This is the gist of the program. 这是该计划的要点。 Everything else is basically the placement of each individual notes or similar methods to display the chords. 其他所有内容基本上都是每个音符或类似方法的位置以显示和弦。 I am stuck and have no idea how to fix this program. 我被困住了,不知道如何修复这个程序。 This is the first GUI I have ever programmed as well. 这是我编程的第一个GUI。 Please help. 请帮忙。 Thanks! 谢谢!

The first thing that jumps out at me is the use getGraphics() . 跳出来的第一件事就是使用getGraphics() You should avoid using this method. 您应该避免使用此方法。

Graphics in Java are stateless. Java中的图形是无状态的。 That is, the Graphics context used to render your component is not guaranteed to be the same between cycles. 也就是说,用于渲染组件的Graphics上下文在循环之间不保证是相同的。 You shouldn't keep a reference to the Graphics context. 您不应该保持对Graphics上下文的引用。

All painting should be done from within the context of the components paint methods, preferably, JComponent#paintComponent , as the paint method is acomplex method, doing a lot of important work you really don't want to have to duplicate. 所有绘画都应该在组件paint方法的上下文中完成,最好是JComponent#paintComponent ,因为paint方法是acomplex方法,做了很多重要的工作,你真的不想复制。

I would create a chord "model" of some kind, where each instance was capable of painting it self. 我会创建一种和弦的“模型”,每个实例都能够自己绘制它。 I would then create a view that was capable of painting the fret and the chords. 然后我会创建一个能够画出音品和和弦的视图。

Update with example 以示例更新

This is a proof of concept example. 这是一个概念证明的例子。 It is assumed that guitar strings start at 5 (thickets) to 0 (smallest). 假设吉他弦从5(丛林)开始到0(最小)。

I'm not a musician, I have no beat or rhythm, so I may have made some fundamental mistakes. 我不是音乐家,我没有节拍或节奏,所以我可能犯了一些根本性的错误。

在此输入图像描述

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

    }
}

A lot of work goes into mapping between the image and UI, this you're going to have figure out yourself, I cracked open PhotoShop and measured out all the points manually. 图像和用户界面之间的映射有很多工作,你可以自己搞清楚,我打开了PhotoShop并手动测出了所有的点数。 If you draw the fret board your self, it becomes easier. 如果你自己画出音板,它会变得更容易。

The basic concept revolves around "Chords". 基本概念围绕“和弦”。 A chord has a name and can paint itself. 和弦有一个名字,可以画自己。 I've create a simple abstract implementation of my Chord interface that takes up much of the leg work and makes it easier creating new chords (as you simply only need to provide it with the frets and strings for each fret that makes up that chord) 我创建了一个简单的Chord接口抽象实现,它占用了大部分腿部工作,并且更容易创建新的和弦(因为你只需要为构成该和弦的每个音品提供音品和弦乐)

I'd also suggest you have a read through 我也建议你仔细阅读

One way to do this is to draw everything from beginning each time paintComponent is called. 一种方法是在每次调用paintComponent时从头开始绘制所有内容。 Draw fretboard image unconditionally, move code for drawing selected cord in paintComponent, and make it draw cord according to some variable, and make actionListner set that variable to selected cord. 无条件地绘制指板图像,移动代码在paintComponent中绘制选定的线,并根据某个变量绘制线,并使actionListner将该变量设置为选定的线。

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

相关问题 如何在Fragment中恢复AdapterViewFlipper的状态? - How can I restore the state of an AdapterViewFlipper in a Fragment? 如何在Mac上还原Java - How can I restore Java on my mac JavaFX动画恢复到原始状态 - JavaFX animation restore to original state 如果它在每次迭代后返回到其原始状态,我可以安全地改变我正在迭代的数组吗? - Can I safely mutate an array I am iterating over, if it returns to its original state after each iteration? 尽管使用了共享首选项,但如何保存我的 cardView 单击事件状态以保存其颜色 - How can I save my cardView click event state to save its colour in spite of using shared preferences 我们如何保存活动状态并恢复它 - How can we Save an Activity state and restore it 如何安排GUI和GUI组件状态读取的线程同步? - how can i arrange gui and thread synchronization of gui component's state reading? 如何在方法调用之前将PriorityQueue恢复为其初始状态? - How to restore the PriorityQueue to its initial state before the method call? 重启手机时如何将小部件数据恢复到以前的状态? - How to restore widget data to its previous state when reboot the phone? 如何还原我的Android Studio项目? - How can I restore my Android Studio project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM