2

JPanelを拡張してActionListenerを実装するBarという名前のクラスを拡張するFooという名前のクラスがあります。円を選択して描画ボ​​タンをクリックすると円が描画され、長方形を押して描画をクリックすると、前の形状が消去されて長方形が描画されます。

ただし、消去ボタンをクリックするまで、JPanelのすべての形状を保持したいと思います。そこで、を削除するsuper.paintComponent(g)と機能しますが、クラスBarのボタンがグリッチで再表示されます。ボタンが再びペイントされないようにするにはどうすればよいですか?Barを拡張せず、FooにJPanelを拡張させることを考えていました。

  public class Bar extends JPanel implements ActionListener
    {
    public void actionPerformed(ActionEvent e)
    {

        if (e.getActionCommand() == "Draw")
        {
            this.requestDraw = true;
            repaint();
        }
            if (e.getActionCommand() == "Circle")
            {
                requestRectangle = false;
                requestTriangle = false;
                requestCircle = true;
            }
            if (e.getActionCommand() == "Rectangle")
            {
                requestCircle = false;
                requestTriangle = false;
                requestRectangle = true;
            }
            if (e.getActionCommand() == "Right Triangle")
            {
                requestCircle = false;
                requestRectangle = false;
                requestTriangle = true;
            }
    }


    public class Foo extends Bar
    {    
        @Override
        public void paintComponent(Graphics g)
        {
            //super.paintComponent(g);
            if(RequestDraw())
            {

                if(RequestCircle())
                    circle.draw(g);
                if(RequestRectangle())
                    rectangle.draw(g);
                if(RequestTriangle())
                    rightTriangle.draw(g);



            }

            if(!RequestDraw())
            {                    


                g.setColor(getBackground());
                g.fillRect(0,0,getWidth(), getHeight());
            }        
        }
    }
}

ここに画像の説明を入力してください

4

2 に答える 2

5

ホバークラフトのすべてのコメントとともに

Graphics コンテキストはコンポーネント間で共有されます。のタスクの 1 つはsuper.paintComponent、描画する前にグラフィックス コンテキストを「クリーン」にすることです。

これが、2 つのバージョンのボタンが表示される理由です...

また、さまざまなことを別の方法で行います。これにより、拡張性と長期的な再利用が促進され、ロジックが少し削減されます。

私は...するだろう...

  • シェイプを、塗りつぶしとストロークの色、位置、サイズ、ストロークなどの最小要件を持つ基本的な「シェイプ」クラスに抽象化し、それ自体をペイントする方法を理解します。
  • 責任の境界を分離して定義できるようなモデルを作成します。形状を「管理」するのはコンポーネントの責任ではなく、表面にペイントするだけです。同様に、コンポーネントは「形状」が何であるかを気にせず、それらがどのようにペイントされるかについて知りたいだけです...
  • s を使用Actionして、これらの形状を単純に作成し、モデルに追加します...

ここに画像の説明を入力

私は三角形の形を作成しただけです(場所とサイズ以外の属性はありません)が、一般的なアイデアは理解できると思います...(psアクションに独自の三角形アイコンを提供する必要があります;))

public class DrawMe {

    public static void main(String[] args) {
        new DrawMe();
    }

    public DrawMe() {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());

                DrawModel model = new DefaultDrawModel();
                model.addElement(new Triangle(new Rectangle(10, 10, 100, 100)));
                DrawPane drawPane = new DrawPane(model);

                JToolBar toolBar = new JToolBar();
                toolBar.add(new AddTriangleAction(model));
                frame.add(toolBar, BorderLayout.NORTH);

                frame.add(drawPane);
                frame.setSize(400, 400);
                frame.setVisible(true);
            }
        });

    }

    /**
     * Simple action used to add triangles to the model...the model acts
     * as a bridge between the action and the UI.
     */
    protected class AddTriangleAction extends AbstractAction {

        private DrawModel model;

        public AddTriangleAction(DrawModel model) {
            // Supply your own icon
            putValue(SMALL_ICON, new ImageIcon(getClass().getResource("/shape_triangle.png")));
            this.model = model;
        }

        public DrawModel getModel() {
            return model;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // Randomly add the triangles...
            int x = (int)(Math.random() * 400);
            int y = (int)(Math.random() * 400);
            model.addElement(new Triangle(new Rectangle(x, y, 100, 100)));
        }

    }

    /**
     * This is the background pane, from which the draw pane extends...
     */
    protected class BackgroundPane extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int x = getWidth() / 2;
            int y = getHeight() / 2;

            Graphics2D g2d = (Graphics2D) g.create();
            RadialGradientPaint rgp = new RadialGradientPaint(
                    new Point(x, y),
                    Math.max(getWidth(), getHeight()),
                    new float[]{0f, 1f},
                    new Color[]{Color.GRAY, Color.WHITE}
                    );

            g2d.setPaint(rgp);
            g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));

            g2d.setBackground(Color.BLACK);
            g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);

            g2d.dispose();
        }
    }

    /**
     * This is a simple model, I stole the list model because it was quicker
     * and easier to demonstrate (don't need to write all the listeners)
     */
    public interface DrawModel extends ListModel<DrawMeShape> {
        public void addElement(DrawMeShape shape);
        public void removeElement(DrawMeShape shape);
    }

    /**
     * A default implementation of the DrawModel...
     */
    public class DefaultDrawModel extends DefaultListModel<DrawMeShape> implements DrawModel {
        @Override
        public void removeElement(DrawMeShape shape) {
            removeElement((Object)shape);
        }
    }

    /**
     * The actually "canvas" that shapes are rendered to
     */
    protected class DrawPane extends BackgroundPane {

        // Should provide ability to setModel...
        private DrawModel model;

        public DrawPane(DrawModel model) {
            this.model = model;
            model.addListDataListener(new ListDataListener() {

                @Override
                public void intervalAdded(ListDataEvent e) {
                    repaint();
                }

                @Override
                public void intervalRemoved(ListDataEvent e) {
                    repaint();
                }

                @Override
                public void contentsChanged(ListDataEvent e) {
                    repaint();
                }
            });
        }

        public DrawModel getModel() {
            return model;
        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            // Draw the shapes from the model...
            Graphics2D g2d = (Graphics2D) g.create();
            DrawModel model = getModel();
            for (int index = 0; index < model.getSize(); index++) {
                DrawMeShape shape = model.getElementAt(index);
                shape.paint(g2d, this);
            }

            g2d.dispose();

        }

    }

    /**
     * A abstract concept of a shape.  Personally, if I was doing it, I would
     * generate an interface first, but this is just a proof of concept...
     */
    public abstract class DrawMeShape {

        private Rectangle bounds;

        public void setBounds(Rectangle bounds) {
            this.bounds = bounds;
        }

        public Rectangle getBounds() {
            return bounds;
        }

        protected abstract Shape getShape();

        /**
         * The shape knows how to paint, but it needs to know what to paint...
         * @param g2d
         * @param parent 
         */
        public void paint(Graphics2D g2d, JComponent parent) {
            g2d = (Graphics2D) g2d.create();
            Rectangle bounds = getBounds();
            Shape shape = getShape();
            g2d.translate(bounds.x, bounds.y);
            g2d.setColor(Color.DARK_GRAY);
            g2d.fill(shape);
            g2d.setColor(Color.BLACK);
            g2d.draw(shape);
            g2d.dispose();
        }

    }

    /**
     * An implementation of a Triangle shape...
     */
    public class Triangle extends DrawMeShape {

        public Triangle(Rectangle bounds) {
            setBounds(bounds);
        }

        @Override
        protected Shape getShape() {
            // This should be cached ;)
            Path2D path = new Path2D.Float();
            Rectangle bounds = getBounds();

            path.moveTo(bounds.width / 2, 0);
            path.lineTo(bounds.width, bounds.height);
            path.lineTo(0, bounds.height);
            path.lineTo(bounds.width / 2, 0);
            path.closePath();

            return path;
        }
    }
}

楽しいお絵描き…

于 2012-10-10T01:00:35.830 に答える
3

提案:

  • super.paintComponent(g)削除する必要がある重要な役割があるため、削除しないでください。
  • paintComponent(...)代わりに、BufferedImageに描画してから、メソッドオーバーライドでそのBufferedImageを描画してみませんか。
  • 次に、描画された画像を消去する場合は、新しいBufferedImageを作成するか、その上に描画します。

余談ですが、を使用して文字列を比較しないでください==。代わりにequals(...)またはメソッドを使用してください。equalsIgnoreCase(...)==は、2つのオブジェクトが同じであるかどうかをチェックしますが、これはあなたが興味を持っているものではないことを理解してください。一方、メソッドは、2つの文字列が同じ順序で同じ文字を持っているかどうかをチェックします。これが、ここで重要です。だから代わりに

if (fu == "bar") {
  // do something
}

行う、

if ("bar".equals(fu)) {
  // do something
}

また、

if ("bar".equalsIgnoreCase(fu)) {
  // do something
}
于 2012-10-10T00:12:18.537 に答える