ProcessingでTwitterを表示&投稿のやり方

##前書き
Processingを学んでいた途中で、Twitterの情報の表示ができるサイトをある方から
教えてもらいました。Twitterは日ごろから使っているため身近なもので
ProcessingとTwitterAPIの勉強ができるのであれば
一石二鳥じゃんと思って始めました。

次からSTEP事に手順を踏んでプログラムを完成させていきましょう。
またProcessingのダウンロードなどは他の記事を参考にしてください

今回の開発環境はProcessing3.0で言語はJava
OSはWindows10となっています

今回の記事は(http://www2.kobe-u.ac.jp/~tnishida/misc/processing-web-api.html)
この記事の内容を元に改良したものとなっています。
この記事を書いた人には頭が上がりません

完成品は自分のタイムラインの確認とツイートができるものになっています。
正直実用性は微妙ですがtwitterAPIの勉強の第一歩としていいと思います。
今回の完成品はいたってシンプルな構造にしていますので
完成後は背景の色を変えたりTimeLineなどの表示位置をいじるなど
自分で改造にチャレンジしてみてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/a5db1871-337d-9811-9ed4-a62d70af6e50.png)


それではLet’s Processing


##STEP0　必要なライブラリの取得
#twiter4j
この章は(http://www2.kobe-u.ac.jp/~tnishida/misc/processing-web-api.html)
を参考(てかほぼパクリ)にして作られています

・twitter4j
まずはここに(http://twitter4j.org/ja/)
飛んでもらってそのサイトの中にある最新安定verをダウンロードしてください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/7ff393b9-d5a5-3cd2-0f4d-5618dd72f481.png)
展開は一旦Processingのファイルとは違うところで行ってください。

Processingのファイルの中にlibrariesがあるので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/6c53e810-cc08-8f48-5647-eb34a307ec8c.png)

その中にTwitter4Jというファイルを作成します。
(minimは違うProcessingのライブラリですお気になさらず)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/1da0255a-7435-1175-56b5-1a06c683b982.png)

その中に先ほど展開したTwitter4jの中にあるlibというフォルダを持ってきます。
でもこれだとダメでlibというフォルダ名をlibraryに変えなければいけません。
※これ忘れるとProcessing内でライブラリが出てこないので要注意！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/b4059f60-22c3-4af9-7a25-8be4a5109ca3.png)

そして中を確認してtwitter4j-core-4.0.7.jarの名前をtwitter4j.jarに変更
※これ忘れるとProcessing内でライブラリが出てこないので要注意！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/f9f0a066-b010-55c7-a003-e24e94e5344f.png)

Processingを開いてあることを確認しましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/16a2799f-4367-fe16-e164-8a454c8c7dc3.png)

これでtwitter4jを使う準備が出来ました

#Twitter Developers

(https://apps.twitter.com/)
にアクセスしてCreateNewAppを押すとたぶんこの登録画面に飛ばされます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/c1623190-bd5d-7b61-8099-506fdda3d509.png)
なんかそれっぽいHobbyistを選択して
一応tweetするのでその中の今回はMaking a botを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/03091039-b5c7-33ab-b9b1-0c2d232a4045.png)

ここから先は個人情報と使用目的を英語で書く必要があります
筆者は日本語の文章を英語の文章に翻訳して貼りました。
ここの写真は貼ることが出来ないのでご了承ください

文章などを書き終えいろいろOKして進んでいくと
このような画面に飛ぶと思います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/ad18e37b-98ce-4f34-3335-cb0254ad6195.png)

下の方にある+Create App をクリック
そうすると名前の入力を求められるので好きな名前を入力
使われている名前だとエラーが発生するので注意すること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/e1cfd577-eb34-96a7-09f1-5ca81f51d043.png)
そうするとキーとトークンが出てくるので全部コピーしておきましょう


一旦この画面がこのappでできる権限を表します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/05756516-8fea-4f89-7750-1f71d668b485.png)
このままだとReadOnlyで読み取ることしかできなくなるので
EditでRead and writeにしておきましょう
（将来的にDirectMessageも読み取りたい人は+DirectMessageにしよう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/04a7094a-d6a8-45a3-f523-740eaf627d69.png)
こんな感じでwriteが出てくれば成功です（DirectMessageがあっても大丈夫）

補足　キーとトークンを忘れた人は
このkeys and tokens を選んで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/faad22e5-df10-ed19-ea48-2f535cf11cff.png)
Regenerateしましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/6b3406eb-e75d-7184-1b2b-35e089414544.png)

これでkeyとTokenを手に入れることができたので
ついに次からプログラムを書いていきましょう

#STEP1 サンプルプログラムを打ち込む

(http://www2.kobe-u.ac.jp/~tnishida/misc/processing-web-api.html)
このページにあるプログラムを下にも貼りますので実行してみましょう
keyとTokenを書き換えるのを忘れないようにしてください

```java:sample.pde
import twitter4j.*;
import twitter4j.api.*;
import twitter4j.auth.*;
import twitter4j.conf.*;
import twitter4j.json.*;
import twitter4j.management.*;
import twitter4j.util.*;
import twitter4j.util.function.*;

String consumerKey = "該当する文字列をコピペ";
String consumerSecret = "該当する文字列をコピペ";
String accessToken = "該当する文字列をコピペ";
String accessTokenSecret = "該当する文字列をコピペ";

class Tweet {
  long id;
  String text;
  String name;
  String screenName;
  PImage profileImage;
  public Tweet(Status s) {
    id = s.getId();
    text = s.getText();    
    User u = s.getUser();
    name = u.getName();
    screenName = u.getScreenName();
    profileImage = loadImage(u.getProfileImageURL());
  }
}

Twitter twitter;
ArrayList<Tweet> tweets;

void setup() {
  size(400, 400);
  tweets = new ArrayList();
  ConfigurationBuilder builder = new ConfigurationBuilder();
  builder.setOAuthConsumerKey(consumerKey);
  builder.setOAuthConsumerSecret(consumerSecret);
  builder.setOAuthAccessToken(accessToken);
  builder.setOAuthAccessTokenSecret(accessTokenSecret);
  TwitterFactory factory = new TwitterFactory(builder.build());
  twitter = factory.getInstance();
}

void draw() {
  background(255);
  fill(0);
  String pointed = null;
  for (int i = 0; i < tweets.size(); i++) {
    Tweet t = tweets.get(i);
    int n = height / t.profileImage.height;
    float x = i / n * t.profileImage.width;
    float y = i % n * t.profileImage.height;
    image(t.profileImage, x, y);
    if (x < mouseX && mouseX < x + t.profileImage.width && y < mouseY && mouseY < y + t.profileImage.height) {
      pointed = t.name + " @" + t.screenName + "\n" + t.text;
    }
  }
  if (pointed != null) {
    text(pointed, mouseX, mouseY, 200, 200);
  }
}

void mouseClicked() {
  updateTimeLine();
}

void keyPressed() {
  tweet("Tweeting from my program in Processing!");
}

void updateTimeLine() {
  try {
    ResponseList<Status> result;
    if (tweets.size() > 0) {
      Paging p = new Paging(tweets.get(0).id);
      result = twitter.getHomeTimeline(p);
    } else {
      result = twitter.getHomeTimeline();
    }
    ArrayList<Tweet> temp = new ArrayList();
    for (int i = 0; i < result.size(); i++) {
      temp.add(new Tweet(result.get(i)));
    }
    tweets.addAll(0, temp);
  }
  catch(TwitterException e) {
    println("Error occured while trying to get the timeline.");
  }
}

void tweet(String text) {
  try {
    twitter.updateStatus(text);
  }
  catch(TwitterException e) {
    println("Error occured while trying to tweet.");
  }
}
```

このプログラムを実行すると
マウスをクリックするとこのようにタイムラインが流れ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1207695/4b4e0852-95e3-6b4d-28fb-5f7445582e41.png)

またどこかのキーボードのkeyを触るとTweeting from my program in Processing!
というツイートが自分のアカウントから一度のみ行われるというものだ
(ツイートは同文だとスパム扱いでTwitter側からはじかれてしまうが故)

サクッとプログラムの解説をしよう
setupでtwitterに接続する準備を行っています
getHomeTimeline毎回最新ツイート20個を獲得する
updateStatusをつかってツイートしています
それだけ覚えておけば基本は大丈夫


さてこのままだと
一応見る事もできるが見づらいしツイート一回の実行で定型文を一度しか
自動ツイートできないしエラー通知が黒画面にでるのはあまりに不便である
そこで次のステップからこのプログラムを改良していこう

#STEP2 ツイートを見やすくしよう

まずはボックスの大きさをsize(800,1600)にします
そうすると縦長になって見やすくなります

またdraw関数の中の```text(pointed,mouseX,mouseY,500,500)```だと
ずっとマウスのを中心にツイートが吸い付くので
```text(pointed,200,300,500,500)```に変えてあげましょう
そうするとマウスの呪縛から逃れて横に出て綺麗なタイムラインになるはずです
後FontをゴシックにしたいのでFontを作成します
それを下のtextFont命令で適用しています
```PFont myFont1 = createFont("ＭＳ ゴシック", 40);  
  textFont(myFont1);
  text("TimeLine",200,100,500,500);```
これを```String pointed = null;```の後に書いてあげましょう
そうするとtext命令での表示Fontが変わって上にTimeLineの文字が表示されるはずです

ツイート内容の文字の大きさが大きすぎるので
draw関数内のif文をこうします
Fontを指定して大きさも指定しています

```java:sample1.pde
  if (pointed != null) {
    PFont myFont2 = createFont("ＭＳ ゴシック", 24);  
    textFont(myFont2);  
    text(pointed, 200, 300, 500, 500);
  }
```

これで表示はマウスをクリックする事にタイムラインが更新されるものになりました

#STEP3 好きな文のツイート
いままでは定型文しか打てずつらい思いをしてきました
それを解消しよう
まずjavaのライブラリをインポートする
```import javax.swing.*;```
```import java.awt.*;```
この二つだ
このライブラリを使うとtextboxを生成できる
このテキストボックス内の文章を読み取り送信するように
プログラムを書き換えてみる

まずdraw関数の一番下に
```text("ツイートしよう",100,700,500,100);```を差し込む

次に```String detail;```をグローバル変数として用意します
また
``JLayeredPane pane;``
```JTextField field;```
これらの追加もこの下に行います

setup関数の一番下にこの四行を追加します
このテキストボックスの初期情報をここで書いています
今回であればフォントはMSゴシック　大きさは25
場所は```setBounds(左上からのx座標,左上からのy座標(↓が正),横幅,縦幅)```
のように指定ができます。
paneはテキストボックス召喚の儀式に必要なものです

  ```field = new JTextField();
  field.setFont(new Font("MS ゴシック",Font.BOLD,25));
  field.setBounds(100, 800, 500, 50);//場所いじる
  pane.add(field);```


次にkeyPressed関数を毎回何でもかんでも
key押す事に送信されちゃたまらないので
下記のように書き換えます

今回であればテキストボックスにツイート書き終えた後
テキストボックスからカーソルをはなした状態で
セミコロンのkeyを半角で入力するとツイートされます
テキストボックスにカーソルを合わせていると普通に；が入力されるので注意
何もないところで打ちましょう

```java:sample2.pde
void keyPressed() {
  if(key == ';'){
    detail = field.getText();
    tweet(detail);
  }
}
```

追記2021/4/2
最後にテキストボックスの中身がツイートするたびに消えるように改良しましょう
```field.setText("");```
これはテキストボックスを作成した後に中身（初期値）を指定できるものです
今回であれば何もなしを指定しているので
中身がすべて消えて綺麗になるという事です
いかにもTwitterらしい機能がつきました。やったね！


さて今回はkeyPressed関数でごり押しましたが改良するならば
ボタンオブジェクトを作成してそのボタンが押されたときにツイートにすると
より使いやすいＵＩになると思います

これで実行すると完成になります！
お疲れさまでした

#今回のコード
解説にミスがあるかもしれないので確実なソースコードを貼っておきます

```java:TwitterLite
import twitter4j.*;
import twitter4j.api.*;
import twitter4j.auth.*;
import twitter4j.conf.*;
import twitter4j.json.*;
import twitter4j.management.*;
import twitter4j.util.*;
import twitter4j.util.function.*;
import javax.swing.*;
import java.awt.*;




String consumerKey = "自分のものを";
String consumerSecret = "自分のものを";
String accessToken = "自分のものを";
String accessTokenSecret = "自分のものを";
String detail;

JLayeredPane pane;
JTextField field;

class Tweet {
  long id;
  String text;
  String name;
  String screenName;
  PImage profileImage;
  public Tweet(Status s) {
    id = s.getId();
    text = s.getText();    
    User u = s.getUser();
    name = u.getName();
    screenName = u.getScreenName();
    profileImage = loadImage(u.getProfileImageURL());
  }
}

Twitter twitter;
ArrayList<Tweet> tweets;

void setup() {
  size(800, 1600);
  Canvas canvas = (Canvas) surface.getNative();//
  pane = (JLayeredPane) canvas.getParent().getParent();//

  tweets = new ArrayList();
  ConfigurationBuilder builder = new ConfigurationBuilder();
  builder.setOAuthConsumerKey(consumerKey);
  builder.setOAuthConsumerSecret(consumerSecret);
  builder.setOAuthAccessToken(accessToken);
  builder.setOAuthAccessTokenSecret(accessTokenSecret);
  TwitterFactory factory = new TwitterFactory(builder.build());
  twitter = factory.getInstance();
  field = new JTextField();
  field.setFont(new Font("MS ゴシック",Font.BOLD,25));
  field.setBounds(100, 800, 500, 50);//場所いじる
  pane.add(field);
}

void draw() {
  background(255);
  fill(0);
  String pointed = null;
  PFont myFont1 = createFont("ＭＳ ゴシック", 40);  
  textFont(myFont1);
  text("TimeLine",200,100,500,500);
  for (int i = 0; i < tweets.size(); i++) {
    Tweet t = tweets.get(i);
    int n = height / t.profileImage.height;
    float x = i / n * t.profileImage.width;
    float y = i % n * t.profileImage.height;
    image(t.profileImage, x, y);
    if (x < mouseX && mouseX < x + t.profileImage.width && y < mouseY && mouseY < y + t.profileImage.height) {
      pointed = t.name + " @" + t.screenName + "\n" + t.text;
    }
  }
  if (pointed != null) {
    PFont myFont2 = createFont("ＭＳ ゴシック", 24);  
    textFont(myFont2);  
    text(pointed, 200, 300, 500, 500);
    
  }
  text("ツイートしよう",100,700,500,100);
}

void mouseClicked() {
  updateTimeLine();
}

void keyPressed() {
  if(key == ';'){
    detail = field.getText();
    tweet(detail);
    field.setText("");
  }
}

void updateTimeLine() {
  try {
    ResponseList<Status> result;
    if (tweets.size() > 0) {
      Paging p = new Paging(tweets.get(0).id);
      result = twitter.getHomeTimeline(p);
    } else {
      result = twitter.getHomeTimeline();
    }
    ArrayList<Tweet> temp = new ArrayList();
    for (int i = 0; i < result.size(); i++) {
      temp.add(new Tweet(result.get(i)));
    }
    tweets.addAll(0, temp);
  }
  catch(TwitterException e) {
    println("Error occured while trying to get the timeline.");
  }
}

void tweet(String text) {
  try {
    twitter.updateStatus(text);
  }
  catch(TwitterException e) {
    println("Error occured while trying to tweet.");
  }
}
```

#後書き
今回初めて記事を書いたのでうまく書けないところもありましたが
いかがだったでしょうか。
まだこのtwitter4jのライブラリを完全には理解していないので
理解できるように頑張ります。
またTwitterAPIやProcessingの勉強のひとつの教材と
なっていただければ幸いです。
個人的にはツイートボタンの追加とツイート後のテキストボックス内の文章を削除する機能を追加しておけばよかったと思っています。
ですのでもしできるようになったら追記する可能性もあります。
2021/4/2
テキストボックスの中身を削除する機能を搭載しました
ちょこっと加筆修正しました

最後にこの記事を書く上で参考にした
(http://www2.kobe-u.ac.jp/~tnishida/misc/processing-web-api.html)
このサイトを書いていただいた人に再度感謝申し上げます

#メモ書き
これからできそうなことをまとめていきます
書き連ねるだけなのでアイデアみたいなもんです
思いついたときに更新します

センサの値を自動投稿+processingの画面で表示
→これによりtwitterによる遠隔監視と実際現場で確認するときの作業が
一つのコードの中にまとめる事ができるのですごく便利かなーと思う