プログラミング演習3 第3回 ミニプロジェクト
ミニプロジェクトについて 1週目では丸や三角形などの形状を用いて継承の復習、2週目ではボタンなどのレイアウトや図形の描画などGUIの復習をしました ミニプロジェクトでは、これら2つを組み合わせておえかきツールを作ってみましょう
完成図の例 図形選択パネル メニュー 描画パネル ボタンを選択 -> 選択された図形の描画準備 ボタンを選択 -> 選択された図形の描画準備 描画パネルをクリック -> 選択された図形をクリックされた 座標に描画
ミニプロジェクトの流れ Swingによる描画 描画クラスの定義 複合図形の描画 描画パネルと図形選択パネルの設計 ActionListenerの処理の記述 Graphicsクラスによる描画 描画クラスの定義 図形クラスの設計 描画用インターフェースの設計 複合図形の描画
描画パネルと図形選択パネルの設計 JPanelを継承したクラスを作り、実行クラス内で呼び出す class MainFrame extends JFrame{ ChoosePanel cp; DrawPanel dp; class ChoosePanel extends JPanel{ } class DrawPanel extends JPanel{
ActionListenerの処理の記述 イベントを発生させたいコンポーネントに リスナー(ボタンの場合はActionListener)を指定 イベントを発生した時に行う処理を書く ボタンによって処理を変えたい場合はgetSourceやgetActionCommandで場合分け
ボタンに貼る画像の作り方 まず図形クラスで、図形の大きさに合ったBufferedImageを作成しdrawメソッドで描いたものをImageとして返す サイズが(70,70)の空のイメージを作成し、そこにTreeを構成する要素を描く 作成する画像の横幅を返すメソッド 作成する画像の高さを返すメソッド ※Treeクラスについてはスライド23,24を参考にすること
ボタンに画像を貼る方法 getImageメソッドで生成した画像は図形によって大きさが異なるので、一定の大きさに縮小してからボタンに貼り付ける
パネルへの配置例 private Drawable drawable; private JLabel l; private JButton b; : setLayout(new GridLayout(1, 2)); drawable = new Tree(); l = new JLabel(drawable.toString(), SwingConstants.CENTER); add(l); img = drawable.getImage(); newimg = img.getScaledInstance(imagesize, imagesize, java.awt.Image.SCALE_SMOOTH); b = new JButton(new ImageIcon(newimg)); b.addActionListener(this); add(b); 縦1,横2で配置 レイアウトマネージャーを無効にして絶対座標で指定する方法もあります http://www.javadrive.jp/tutorial/nulllayout/index1.html
描画に必要なメソッド 塗りつぶさずに描画 -> draw(int x, int y, Graphics g) 塗りつぶして描画 -> drawfill(int x, int y, Graphics g) 色の設定と取得 -> setColor(Color c), getColor() 塗りつぶすか選択 -> setFilled(Boolean b), getFilled() ボタンに画像を貼る -> getImage() : draw(…), drawfill(…) を場合分け 画像サイズを決定する -> getWidth(), getHeight() ChoosePanel( ) { drawable[0] = new Tree(); drawable[1] = new Tree(); drawable[2] = new BigCircle(); drawable[3] = new BigCircle(); drawable[1].setColor(Color.PINK); drawable[1].setFilled(true); drawable[3].setColor(Color.BLUE); drawable[3].setFilled(true); ・・・
Graphicsクラスによる描画 描画はpaintComponentメソッドで行う 描画には以下のようなメソッドが用意されている 文字列の描画 :drawstring(表示する文字列,x座標,y座標) 線の描画 :drawLine(始点のx座標,y座標,終点のx座標,y座標) 四角形の描画 :drawRect(x座標,y座標,横幅,高さ) 丸の描画 :drawOval(x座標,y座標,横幅,高さ) 多角形の描画 :drawPolygon(x座標の配列,y座標の配列,頂点数) 塗りつぶす場合はdraw~をfill~に変える
クリックしたところに描画する mouseClickメソッド内でクリックした座標を取得し、描画を行う ←2回めのHomeworkの解答例
図形とクリックした場所の保持 private ArrayList<ShapeObject> shapes=new ArrayList<ShapeObject>(); @Override public void paintComponent(Graphics g) { super.paintComponent(g); for (int i = 0; i < shapes.size(); i++) shapes.get(i).pd.draw(shapes.get(i).p.x,shapes.get(i).p.y, g); } public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); shapes.add(new ShapeObject(currentDrawable, p)); repaint(); : private class ShapeObject { Drawable d; Point p; public ShapeObject(Drawable d, Point p){ this.pd = pd; this.p = p; repaintメソッドで再描画すると、これまでに描画していたものは消えてしまうので、LinkedHashMapやAllayListを使ってこれまでに描画した図形と描画した座標を保持する ←実装例 追加された形状を全て描画 クリックされたら形状と座標を追加 描画する形状と座標を保つクラス
継承を生かした描画 SmallCircleもBigCircleも大きさが異なるだけで描画する方法は同じなのでCircleクラスに処理をまとめることができる Circleクラス SmallCircleクラスとBigCircleクラスにはdrawメソッドが書かれていないので継承元のCircleクラスのdrawメソッドが呼ばれる SmallCircleクラス BigCircleクラス
メニューの作り方 メニューを作るにはJMenuBar,Jmenu,JMenuItemを用いる JMenuBar L JMenu L JMenuItem の構造になっていて、JMenuItemをクリックした時にイベントを発生させたい場合はJButtonと同様にActionListenerに登録し、actionPerformedメソッド内に処理を書く 表示する文字列やショートカットキーの設定 終了を押した時の処理
描画クラスの定義 基本的(primitive)な図形と複合的(compound)な図形を分けて考える 描画に必要なメソッドを考え、インターフェースにまとめる 基本的 複合的 必要なこと (メソッド) 実現したいこと (機能)
基本的な図形クラスの設計 Interface Drawable 全ての基本図形がDrawable のメソッドを使える BigSquare BigRectangle SmallRectangle BigIsoscelesTriangle SmallIsoscelesTriangle BigCircle SmallCircle ? IsoscelesTriangle Circle Rectangle Shape Polygon SmallSquare Square Interface Drawable void draw(int x, int y, Graphics g) void setColor(Color c) ・・・ 全ての基本図形がDrawable のメソッドを使える
複合的な図形クラスの設計 draw( int x, int y, Graphics g) の宣言はどこ? Tree の中で宣言? CompoundDrawable の中で宣言? Drawable から継承? getParts()の返り値は何? あらゆる図形を複数入れれる箱は..? Interface Drawable draw(int x, int y, Graphics g)? ・・・ Interface CompoundDrawable getParts() draw( int x, int y, Graphics g)? Tree draw( int x, int y, Graphics g)? SmallSquare BigIsoscelesTriangle SmallIsoscelesTriangle
描画に必要なメソッド 塗りつぶさずに描画 -> draw(int x, int y, Graphics g) 塗りつぶして描画 -> drawfill(int x, int y, Graphics g) 色の設定と取得 -> setColor(Color c), getColor() 塗りつぶすか選択 -> setFilled(Boolean b), getFilled() ボタンに画像を貼る -> getImage() : draw(…), drawfill(…) を場合分け 画像サイズを決定する -> getWidth(), getHeight() ChoosePanel( ) { drawable[0] = new Tree(); drawable[1] = new Tree(); drawable[2] = new BigCircle(); drawable[3] = new BigCircle(); drawable[1].setColor(Color.PINK); drawable[1].setFilled(true); drawable[3].setColor(Color.BLUE); drawable[3].setFilled(true); ・・・
BigCircle クラスの実装例 (Shape クラス) protected 修飾子はサブクラスのみがアクセス範囲
BigCircle クラスの実装例 (Circle クラス)
BigCircle クラスの実装例 (/3)
Tree クラスの実装例 (1/2)
Tree クラスの実装例 (2/2)
Treeクラスをもっと簡潔に 複合的な図形では、使用するパーツの定義と描画する座標の設定以外の処理はほとんど共通の処理を抽象クラスにまとめて書くと便利 継承 継承 他の複合的な形状のクラス
実装の過程 Circleクラスを参考にして四角形や三角形などの基本図形を作る Step1 Circleクラスを参考にして四角形や三角形などの基本図形を作る Step2 図形選択パネルにStep1で作成した図形の画像を貼り付けたボタンを表示する Step3 図形選択パネルのボタンを選んで、描画パネル上でクリックすると、クリックした場所に図形が描画される Step4 複合的な図形を実装する上で共通のメソッドをまとめたCompoundFigureクラスを定義し、Treeクラスなどの複合的な図形を表すクラスに継承させる Step5 おえかきツールでStep4で作成した図形を描画できるようにする Step6 TreeクラスのようなCompoundDrawbleを継承するクラスをメンバーに持つCompoundDrawbleを継承したクラスを5個以上作る Step7 メニューにヘルプの項目を作り、クリックすると作成者の名前が書かれたダイアログを表示させる Step8 おえかきツールにオリジナルの機能を追加する(Undoとかキャプチャとか)