前提
Javaでドローエディタを作成し,コンパイルしてファイルを作成し,ドローエディタをクリックするとエラーメッセージが表示されて描画できない.
実現したいこと
ドローエディタを作成したい.
該当のソースコード
java
1import javax.swing.*; 2import java.awt.*; 3import java.awt.event.*; 4import java.util.*; 5// 描画した図形を記録する Figure クラス (継承して利用する) 6class Figure { 7 protected int x, y, width, height; 8 protected Color color; 9 public Figure(int x, int y, int w, int h, Color c) { 10 this.x = x; 11 this.y = y; // this.x, this.y はインスタンス変数. 12 width = w; 13 height = h; // ローカル変数で同名の変数がある場合は,this 14 color = c; // を付けると,インスタンス変数を指す. 15 } 16 public void setSize(int w, int h) { 17 width = w; 18 height = h; 19 } 20 public void setLocation(int x, int y) { 21 this.x = x; 22 this.y = y; 23 } 24 public void reshape(int x1, int y1, int x2, int y2) { 25 } 26 public void draw(Graphics g) { 27 } 28} 29class CircleFigure extends Figure { 30 public CircleFigure(int x, int y, int w, int h, Color c) { 31 super(x, y, w, h, c); 32 } 33 public void reshape(int x1, int y1, int x2, int y2) { 34 int newx = Math.min(x1, x2); 35 int newy = Math.min(y1, y2); 36 int neww = Math.abs(x1 - x2); 37 int newh = Math.abs(y1 - y2); 38 setLocation(newx, newy); 39 setSize(neww, newh); 40 } 41 public void draw(Graphics g) { 42 g.setColor(color); 43 g.drawOval(x, y, width, height); 44 } 45} 46class LineFigure extends Figure { 47 public LineFigure(int x, int y, int w, int h, Color c) { 48 super(x, y, w, h, c); 49 } 50 public void reshape(int x1, int y1, int x2, int y2) { 51 setLocation(x1, y1); 52 setSize(x2, y2); 53 } 54 public void draw(Graphics g) { 55 g.setColor(color); 56 g.drawLine(x, y, width, height); 57 } 58} 59class RectangleFigure extends Figure { 60 public RectangleFigure(int x, int y, int w, int h, Color c) { 61 super(x, y, w, h, c); 62 // 引数付きのコンストラクタは継承されないので,コンストラクタを定義. 63 // superで親のコンストラクタを呼び出すだけ. 64 } 65 public void reshape(int x1, int y1, int x2, int y2) { 66 int newx = Math.min(x1, x2); 67 int newy = Math.min(y1, y2); 68 int neww = Math.abs(x1 - x2); 69 int newh = Math.abs(y1 - y2); 70 setLocation(newx, newy); 71 setSize(neww, newh); 72 } 73 public void draw(Graphics g) { 74 g.setColor(color); 75 g.drawRect(x, y, width, height); 76 } 77} 78//////////////////////////////////////////////// 79// Model (M) 80// modelは java.util.Observableを継承する.Viewに監視される. 81class DrawModel extends Observable { 82 protected ArrayList<Figure> fig; 83 protected String figurelabel; 84 protected Figure drawingFigure; 85 protected Color currentColor; 86 protected ViewPanel viewPanel; 87 public DrawModel() { 88 fig = new ArrayList<Figure>(); 89 drawingFigure = null; 90 currentColor = Color.red; 91 } 92 public void setViewPanel(ViewPanel c) { 93 viewPanel = c; 94 } 95 public ArrayList<Figure> getFigures() { 96 return fig; 97 } 98 public Figure getFigure(int idx) { 99 return fig.get(idx); 100 } 101 public void createFigure(int x, int y) { 102 Figure f = null; 103 ; 104 if (figurelabel == "rect") 105 f = new RectangleFigure(x, y, 0, 0, currentColor); 106 else if (figurelabel == "circ") 107 f = new CircleFigure(x, y, 0, 0, currentColor); 108 else if (figurelabel == "line") 109 f = new LineFigure(x, y, x, y, currentColor); 110 fig.add(f); 111 drawingFigure = f; 112 viewPanel.repaint(); 113 setChanged(); 114 notifyObservers(); 115 } 116 public void reshapeFigure(int x1, int y1, int x2, int y2) { 117 if (drawingFigure != null) { 118 drawingFigure.reshape(x1, y1, x2, y2); 119 viewPanel.repaint(); 120 setChanged(); 121 notifyObservers(); 122 } 123 } 124 public void changecolor(Color col) { 125 currentColor = col; 126 } 127 public void changefigure(String fi) { 128 figurelabel = fi; 129 } 130} 131//////////////////////////////////////////////// 132// View (V) 133// Viewは,Observerをimplementsする.Modelを監視して, 134// モデルが更新されたupdateする.実際には,Modelから 135// update が呼び出される. 136class ViewPanel extends JPanel implements Observer { 137 protected DrawModel model; 138 public ViewPanel(DrawModel m) { 139 this.setBackground(Color.white); 140 model = m; 141 model.addObserver(this); 142 } 143 public void paintComponent(Graphics g) { 144 super.paintComponent(g); 145 ArrayList<Figure> fig = model.getFigures(); 146 for (int i = 0; i < fig.size(); i++) { 147 Figure f = fig.get(i); 148 f.draw(g); 149 } 150 } 151 public void update(Observable o, Object arg) { 152 repaint(); 153 } 154} 155class Select implements ActionListener { 156 DrawModel a; 157 Select(DrawModel ap) { 158 a = ap; 159 } 160 public void actionPerformed(ActionEvent e) { // 設定の変更 161 String es = e.getActionCommand(); 162 if (es.equals("red")) 163 a.changecolor(Color.red); 164 if (es.equals("green")) 165 a.changecolor(Color.green); 166 if (es.equals("blue")) 167 a.changecolor(Color.blue); 168 if (es.equals("rect")) 169 a.changefigure("rect"); 170 if (es.equals("circ")) 171 a.changefigure("circ"); 172 if (es.equals("line")) 173 a.changefigure("line"); 174 } 175} 176////////////////////////////////////////////////// 177// Main class 178// (GUIを組み立てているので,view の一部と考えてもよい) 179class DrawFrame extends JFrame { 180 DrawModel model; 181 ViewPanel view; 182 DrawController cont; 183 public static void main(String[] args) { 184 JFrame f = new JFrame("Draw"); 185 JPanel pc = new JPanel(); 186 JPanel pf = new JPanel(); 187 pc.setLayout(new GridLayout(1, 3)); 188 pf.setLayout(new GridLayout(1, 3)); 189 JButton r = new JButton("red"); 190 JButton g = new JButton("green"); 191 JButton b = new JButton("blue"); 192 JButton rect = new JButton("rect"); 193 JButton circ = new JButton("circ"); 194 JButton line = new JButton("line"); 195 r.setActionCommand("red"); 196 g.setActionCommand("green"); 197 b.setActionCommand("blue"); 198 rect.setActionCommand("rect"); 199 circ.setActionCommand("circ"); 200 line.setActionCommand("line"); 201 DrawModel a = new DrawModel(); 202 ViewPanel dp = new ViewPanel(a); 203 a.setViewPanel(dp); 204 DrawController ml = new DrawController(a); 205 dp.addMouseListener(ml); 206 dp.addMouseMotionListener(ml); 207 pc.add(r); 208 pc.add(g); 209 pc.add(b); 210 pf.add(rect); 211 pf.add(circ); 212 pf.add(line); 213 b.addActionListener(new Select(a)); 214 g.addActionListener(new Select(a)); 215 r.addActionListener(new Select(a)); 216 circ.addActionListener(new Select(a)); 217 rect.addActionListener(new Select(a)); 218 line.addActionListener(new Select(a)); 219 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 220 f.getContentPane().add(dp, BorderLayout.CENTER); 221 f.getContentPane().add(pc, BorderLayout.SOUTH); 222 f.getContentPane().add(pf, BorderLayout.NORTH); 223 f.setSize(400, 300); 224 f.setVisible(true); 225 } 226} 227//////////////////////////////////////////////// 228// Controller (C) 229class DrawController implements MouseListener, MouseMotionListener { 230 protected DrawModel model; 231 protected int dragStartX, dragStartY; 232 public DrawController(DrawModel a) { 233 model = a; 234 } 235 public void mouseClicked(MouseEvent e) { 236 } 237 public void mousePressed(MouseEvent e) { 238 dragStartX = e.getX(); 239 dragStartY = e.getY(); 240 model.createFigure(dragStartX, dragStartY); 241 } 242 public void mouseDragged(MouseEvent e) { 243 model.reshapeFigure(dragStartX, dragStartY, e.getX(), e.getY()); 244 } 245 public void mouseReleased(MouseEvent e) { 246 model.reshapeFigure(dragStartX, dragStartY, e.getX(), e.getY()); 247 } 248 public void mouseEntered(MouseEvent e) { 249 } 250 public void mouseExited(MouseEvent e) { 251 } 252 public void mouseMoved(MouseEvent e) { 253 } 254}
### 該当のソースコード
```java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
// 描画した図形を記録する Figure クラス (継承して利用する)
class Figure {
protected int x, y, width, height;
protected Color color;
public Figure(int x, int y, int w, int h, Color c) {
this.x = x;
this.y = y; // this.x, this.y はインスタンス変数.
width = w;
height = h; // ローカル変数で同名の変数がある場合は,this
color = c; // を付けると,インスタンス変数を指す.
}
public void setSize(int w, int h) {
width = w;
height = h;
}
public void setLocation(int x, int y) {
this.x = x;
this.y = y;
}
public void reshape(int x1, int y1, int x2, int y2) {
}
public void draw(Graphics g) {
}
}
class CircleFigure extends Figure {
public CircleFigure(int x, int y, int w, int h, Color c) {
super(x, y, w, h, c);
}
public void reshape(int x1, int y1, int x2, int y2) {
int newx = Math.min(x1, x2);
int newy = Math.min(y1, y2);
int neww = Math.abs(x1 - x2);
int newh = Math.abs(y1 - y2);
setLocation(newx, newy);
setSize(neww, newh);
}
public void draw(Graphics g) {
g.setColor(color);
g.drawOval(x, y, width, height);
}
}
class LineFigure extends Figure {
public LineFigure(int x, int y, int w, int h, Color c) {
super(x, y, w, h, c);
}
public void reshape(int x1, int y1, int x2, int y2) {
setLocation(x1, y1);
setSize(x2, y2);
}
public void draw(Graphics g) {
g.setColor(color);
g.drawLine(x, y, width, height);
}
}
class RectangleFigure extends Figure {
public RectangleFigure(int x, int y, int w, int h, Color c) {
super(x, y, w, h, c);
// 引数付きのコンストラクタは継承されないので,コンストラクタを定義.
// superで親のコンストラクタを呼び出すだけ.
}
public void reshape(int x1, int y1, int x2, int y2) {
int newx = Math.min(x1, x2);
int newy = Math.min(y1, y2);
int neww = Math.abs(x1 - x2);
int newh = Math.abs(y1 - y2);
setLocation(newx, newy);
setSize(neww, newh);
}
public void draw(Graphics g) {
g.setColor(color);
g.drawRect(x, y, width, height);
}
}
////////////////////////////////////////////////
// Model (M)
// modelは java.util.Observableを継承する.Viewに監視される.
class DrawModel extends Observable {
protected ArrayList<Figure> fig;
protected String figurelabel;
protected Figure drawingFigure;
protected Color currentColor;
protected ViewPanel viewPanel;
public DrawModel() {
fig = new ArrayList<Figure>();
drawingFigure = null;
currentColor = Color.red;
}
public void setViewPanel(ViewPanel c) {
viewPanel = c;
}
public ArrayList<Figure> getFigures() {
return fig;
}
public Figure getFigure(int idx) {
return fig.get(idx);
}
public void createFigure(int x, int y) {
Figure f = null;
;
if (figurelabel == "rect")
f = new RectangleFigure(x, y, 0, 0, currentColor);
else if (figurelabel == "circ")
f = new CircleFigure(x, y, 0, 0, currentColor);
else if (figurelabel == "line")
f = new LineFigure(x, y, x, y, currentColor);
fig.add(f);
drawingFigure = f;
viewPanel.repaint();
setChanged();
notifyObservers();
}
public void reshapeFigure(int x1, int y1, int x2, int y2) {
if (drawingFigure != null) {
drawingFigure.reshape(x1, y1, x2, y2);
viewPanel.repaint();
setChanged();
notifyObservers();
}
}
public void changecolor(Color col) {
currentColor = col;
}
public void changefigure(String fi) {
figurelabel = fi;
}
}
////////////////////////////////////////////////
// View (V)
// Viewは,Observerをimplementsする.Modelを監視して,
// モデルが更新されたupdateする.実際には,Modelから
// update が呼び出される.
class ViewPanel extends JPanel implements Observer {
protected DrawModel model;
public ViewPanel(DrawModel m) {
this.setBackground(Color.white);
model = m;
model.addObserver(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
ArrayList<Figure> fig = model.getFigures();
for (int i = 0; i < fig.size(); i++) {
Figure f = fig.get(i);
f.draw(g);
}
}
public void update(Observable o, Object arg) {
repaint();
}
}
class Select implements ActionListener {
DrawModel a;
Select(DrawModel ap) {
a = ap;
}
public void actionPerformed(ActionEvent e) { // 設定の変更
String es = e.getActionCommand();
if (es.equals("red"))
a.changecolor(Color.red);
if (es.equals("green"))
a.changecolor(Color.green);
if (es.equals("blue"))
a.changecolor(Color.blue);
if (es.equals("rect"))
a.changefigure("rect");
if (es.equals("circ"))
a.changefigure("circ");
if (es.equals("line"))
a.changefigure("line");
}
}
//////////////////////////////////////////////////
// Main class
// (GUIを組み立てているので,view の一部と考えてもよい)
class DrawFrame extends JFrame {
DrawModel model;
ViewPanel view;
DrawController cont;
public static void main(String[] args) {
JFrame f = new JFrame("Draw");
JPanel pc = new JPanel();
JPanel pf = new JPanel();
pc.setLayout(new GridLayout(1, 3));
pf.setLayout(new GridLayout(1, 3));
JButton r = new JButton("red");
JButton g = new JButton("green");
JButton b = new JButton("blue");
JButton rect = new JButton("rect");
JButton circ = new JButton("circ");
JButton line = new JButton("line");
r.setActionCommand("red");
g.setActionCommand("green");
b.setActionCommand("blue");
rect.setActionCommand("rect");
circ.setActionCommand("circ");
line.setActionCommand("line");
DrawModel a = new DrawModel();
ViewPanel dp = new ViewPanel(a);
a.setViewPanel(dp);
DrawController ml = new DrawController(a);
dp.addMouseListener(ml);
dp.addMouseMotionListener(ml);
pc.add(r);
pc.add(g);
pc.add(b);
pf.add(rect);
pf.add(circ);
pf.add(line);
b.addActionListener(new Select(a));
g.addActionListener(new Select(a));
r.addActionListener(new Select(a));
circ.addActionListener(new Select(a));
rect.addActionListener(new Select(a));
line.addActionListener(new Select(a));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(dp, BorderLayout.CENTER);
f.getContentPane().add(pc, BorderLayout.SOUTH);
f.getContentPane().add(pf, BorderLayout.NORTH);
f.setSize(400, 300);
f.setVisible(true);
}
}
////////////////////////////////////////////////
// Controller (C)
class DrawController implements MouseListener, MouseMotionListener {
protected DrawModel model;
protected int dragStartX, dragStartY;
public DrawController(DrawModel a) {
model = a;
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
dragStartX = e.getX();
dragStartY = e.getY();
model.createFigure(dragStartX, dragStartY);
}
public void mouseDragged(MouseEvent e) {
model.reshapeFigure(dragStartX, dragStartY, e.getX(), e.getY());
}
public void mouseReleased(MouseEvent e) {
model.reshapeFigure(dragStartX, dragStartY, e.getX(), e.getY());
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
}
```
### 試したこと
コンパイルを行った.
```
「DrawFrame.java:98: 警告:[deprecation] java.utilのObservableは推奨されません
class DrawModel extends Observable {
^
DrawFrame.java:163: 警告:[deprecation] java.utilのObserverは推奨されません
class ViewPanel extends JPanel implements Observer {
^
DrawFrame.java:181: 警告:[deprecation] java.utilのObservableは推奨されません
public void update(Observable o, Object arg) {
^
警告3個」
```
といった警告を確認した.
ソースコードは質問本文に記載して下さい。
字数制限のためここに記載いたしました.
### 発生している問題・エラーメッセージ
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "Figure.draw(java.awt.Graphics)" because "<local4>" is null
at ViewPanel.paintComponent(DrawFrame.java:177)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5318)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1656)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1631)
at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1569)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1336)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5266)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5076)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:878)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:861)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:861)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:834)
at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:784)
at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1897)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
エラーメッセージを記載いたします.
コメントにマークダウンは適用されません。
NullPointerException ですので、該当箇所での変数の値を確認の上、原因を探ってください。
修正いたしました.
>Observableは推奨されません
>Observerは推奨されません
両者は java9 から非推奨となりました。
「ObserverとObservableでサポートされているイベント・モデルは非常に限定されており、Observableによって配信される通知の順序は不定であり、状態の変更は通知と1対1で対応していません。 豊富なイベント・モデルの場合は、java.beansパッケージの使用を検討してください。 スレッド間の信頼性の高い順序付きメッセージングのために、java.util.concurrentパッケージ内の同時データ構造の1つを使用することを検討してください。 リアクティブ・ストリーム・スタイルのプログラミングについては、Flow APIを参照してください。」
https://docs.oracle.com/javase/jp/9/docs/api/java/util/Observable.html
NullPointerExceptionの味方が今一つわかっていないのですけれど,この場合はFigure.draw部分にエラーが発生しているという認識でよろしいでしょうか.
NullPointerException に限らず、例外発生時のスタックトレースにはどこで何が起きたのかが書かれていますので、見方が分かっていないとデバッグの手がかりが無くなります。
> at ViewPanel.paintComponent(DrawFrame.java:177)
とありますので、 ViewPanel クラスの paintComponent メソッド内 (DrawFrame.java ファイルの 177 行目 ) で NullPointerException が発生しています。
> Cannot invoke "Figure.draw(java.awt.Graphics)" because "<local4>" is null"
は、 draw メソッドが ( ローカル変数が )null で呼べないということなので、 f.draw(g); の f が null になっていたのでしょう。
この f は model.getFigures() でモデルから得た list 中の一つとなりますが、その list への格納は DrawModel.createFigure メソッド内 fig.add(f); で行っています。こちらの f は初期値 null で一連の if 文で設定されることになっていますが、 if 文に引っかからなければ null が入ってしまうので原因の可能性があります。ここで思い込み無く if 文を見れば、 java でよくある「文字列を == で比較しようとしてしまう」バグが見つかるはずです。

回答4件
あなたの回答
tips
プレビュー