SQLite:上から何番目の行を削除したい
はじめに
最近、大学でSQLiteを習ったのですが、データベースを作成中「上から〇番目のものを消したいな」と思ったのですが、それが上手くいかなかったのでいろいろと調べてみました。
使うテーブル
テーブル名:user
id | name |
---|---|
2 | tanaka |
5 | kato |
7 | maeda |
LIMITとOFFSET
SELECT文ではLIMITとOFFSETという変数を指定するだけで、上から何番目の行を指定することができます。
LIMIT
limit
というのは抜き出した行(またはパラメータ)の数を制限する命令です。
たとえば
SELECT * FROM user LIMIT 2;
としたときの結果は以下の表になります。
id | name |
---|---|
2 | tanaka |
5 | kato |
OFFSET
OFFSET
というのは行を取得するときの開始位置を決める命令です。
LIMIT
を使用しているときのみ使用可能です。
たとえば
SELECT * FROM user OFFSET 1;
と書くとエラーを吐きます。
実際に使用するときは
SELECT * FROM user LIMIT 2 OFFSET 1;
と書きます。その結果は以下の表になります。
id | name |
---|---|
5 | kato |
7 | maeda |
上からk番目を取得したいとき
以上のことを踏まえると上からk番目を取得する書き方は以下のようになります。
SELECT * FROM user LIMIT 1 OFFSET k-1;
上からk番目を削除したい
これをDELETE文でもできないかと思い以下のようなコマンドを書きました。
DELETE FROM user LIMIT 1 OFFSET k-1;
しかし、このコードはエラーを吐いてしまいました……。 どうしてかと思い調べてみるとこんな図がありました。
SQLite Syntax: delete-stmt-limitedより引用
つまりはDELETE文ではLIMIT
もOFFSET
も使えないらしいです。
SELECT文と組み合わせる
じゃあ、上からk番目を消すことができないのかというと別にそういうわけではなく、SELECT文と組み合わせると可能になるようです。
delete from user where id = (select id from user limit 1 offset k-1);
(select id from user limit 1 offset k-1)
は上からk番目の行のidを取得しています。そのidと同じ行を削除すれば結果的に上からk番目の行を削除できるというわけです。
おわりに
今回はDELETE文でスマートに上からk番目を削除したかったのですが、どうやら仕組み的に間接的な方法しかないことが分かりました。 ただ正直、遠回りな分コマンドが長くなってしまうのはあまり好きではないですね……。
参考資料
標高からきんモザのアリスちゃんを探してみた
はじめに
今回は大学のプログラミング授業で「APIを使ってWebサービスを作ろう」という課題で自分が提出した作品について語ろります。
Webサービスの説明
左にある地図をタップするとそこの標高が取得され、その標高に合わせてアニメ「きんいろモザイク」のアリスちゃんのgif画像を表示します。
完成図
試したブラウザ
使用したAPI
プログラムの仕組み
1.緯度・経度を取得
Yahoo!JavascriptマップAPIを使い地図の表示と、そこをタップした座標(緯度・経度)の取得に使いました。
html
<script type="text/javascript" charset="utf-8" src="https://map.yahooapis.jp/js/V1/jsapi?appid=[ここにapikeyを入れる]"></script> <div id="map"></div>
Javascript
var ymap = new Y.Map("map"); //地図の表示 ymap.drawMap(new Y.LatLng(35.36055, 138.72777), 15, Y.LayerSetId.NORMAL);//緯度・経度は富士山を基準の座標に指定 //緯度・経度を取得するメゾット ymap.bind('click', function (latlng) { console.log("緯度:" + latlng.lat() + ",経度:" + latlng.lng()); });
2,標高の取得
国土地理院が提供している標高APIは緯度・経度を入力すればそこの標高を返してくれます。
var URL = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=" +[経度]+ "&lat=" + [緯度] + "&outtype=JSON" $.getJSON(URL, function (response) { console.log(response.elevation.);//標高を表示 })
3.きんモザAPIを叩く
きんモザAPIはきんいろモザイクのアリスちゃんのgif画像を返してくれるAPIです。一話から十二話までの話数を指定する「ep」とその中で何番目のgif画像を指定するかという「no」を指定するとgif画像を返してくれます。
<iframe id="gif"></iframe>
var gif_url = 'http://mogashi.com/alice/?ep=' + ep + '&no=' + no; document.getElementById('gif').src = gif_url;
4.APIを組み合わせる
大雑把な流れは緯度・経度の取得
->標高の取得
->標高から「ep」、「no」を指定してgif画像を呼び出す
です。
「ep」は標高を300で割った値にして、「no」は十の位と一の位を4で割った値にしている。
最終的なコード
index.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> </head> <body> <div style="width:1020px; display:table;"> <div id="map" style="width:600px; height:300px;display: table-cell;"></div> <div style="width:600px; display:table-cell;"> gif画像 <br><br> <iframe id="gif" src="http://mogashi.com/alice/?ep=2&no=50" name="gif" width="500" height="300"></iframe> </div> </div> 好きなところにクリックしてね <script type="text/javascript" charset="utf-8" src="https://map.yahooapis.jp/js/V1/jsapi?appid=[ここにapikeyを入れる]"></script> <script type="text/javascript" src="./main.js"></script> </body> </html>
main.js
window.onload = function () { var ymap = new Y.Map("map"); ymap.drawMap(new Y.LatLng(35.36055, 138.72777), 15, Y.LayerSetId.NORMAL); ymap.bind('click', function (latlng) { var URL = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=" + latlng.lng() + "&lat=" + latlng.lat() + "&outtype=JSON" $.getJSON(URL, function (response) { console.log(response.elevation); var ep = Math.floor(response.elevation / 300); var no = Math.floor((response.elevation - Math.floor(response.elevation / 100) * 100) / 4); AliceGif(ep, no); }) }); //アリスちゃんのgif画像を返してくれる関数 function AliceGif(ep, no) { if (ep < 1) ep = 1; if (ep > 12) ep = 12; var gif_url = 'http://mogashi.com/alice/?ep=' + ep + '&no=' + no; document.getElementById('gif').src = gif_url; } }
おわりに
我ながら意味不明なWebサービスを作ってしまったと思っています……。ただこれによりどんなgif画像が見つかるか予測することが難しいため、未知との遭遇を演出できるのではないでしょうか?今回紹介したAPIやそのソースコードが何かの役に立てたなら光栄です。
アニヲタが作ったおもしろAPI集
はじめに
今回は(たぶん)アニメが好きな人たちが作ったであろうAPIを紹介します。
目次
API一覧
ShangriLa API
qiita.com 指定した年や春夏秋冬を指定するとそのときにやっていたアニメが何だったのか返してくれます。
きんモザAPI
idや何話目かを指定すると「きんいろモザイク」のアリスちゃんのgif画像が帰ってきます。
自分もこのAPIを使ったサービスを作ってみました!
シャロシコAPI
syaroshico.hinaloe.net 「シャロシコ」が含まれたツイート数をカウントしてくれます。
おわりに
後半二つはアニメキャラへの愛情が伝わってくるAPIでした(適当)。 こんなアニメキャラを元にしたWebAPIが増えてくると面白いWebサービスが作れそうですね。 皆さんもアニメに関連したAPIを作ってみてはどうでしょうか?
GIFMAGAZINE APIをJavaScript/Node.jsで叩いてみた
はじめに
プログラミングの授業で「Web APIを使ってWebサービスを作ろう」という課題が出たためいろいろとWeb APIを探していたときにこの「Gifmagazine-API」見つけました。ただリファレンスを読むとサンプルコードが書いていなかったためこの記事でJavaScriptとNode.jsでのサンプルコードを書きます。(JavaScriptにはjQueryライブラリを使いました)
GIFMAGAZINE APIとは?
サンプルコードの前に「GIFMAGAZINE API」とは何なのか説明します。 「GIFMAGAZINE」とはgif画像を投稿したり登校されたgif画像をダウンロードすることができるgif画像の投稿・共有サービスです。このAPIでは「GIFMAGAZINE」内のgif画像を検索することができます。 このAPIのおもしろいところは感情別でgif画像を検索できるところです。感情は標準化されたユニコード絵文字を元に対応しています。 また特徴として、id検索以外はAPIキーなしで利用できるところが挙げられます。ただしこの「GIFMAGAZINE」から提供されたデータを使用する際は以下のような決まりがあるの注意してください。(詳しくは http://api.gifmagazine.net/ )
URL:http://gifmagazine.net/ クレジット:http://sinkr.main.jp/api/brand_logo_kit.zip
サンプルコード
ここからはGifmagazine-API-Documentationに書かれているAPIの説明を引用しながら、それを参考に書いたサンプルコードを書いていきます。
JavaScriptの場合はjQueryを使用するのでhtmlの<head>
タグの中に次のタグを入れてください。
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
文字検索
名前の通り文字で検索します。
パラメータ
- q(必須) : 検索したい単語
- limit : 返ってくる検索結果の件数。デフォルトは2件。最大2件。0~2以外の数値を指定した場合はデフォルト値が利用されます。
- offset : オフセット。デフォルトは0。最大0。
- safe : 0を指定するとR-18のgifを検索結果から除く。1を指定するとR-18のgifも含んだ検索結果を返す。デフォルトは0。
Request
var query = '猫'; var limit = 1; var offset = 0; var safe = 0; var URL = 'http://api.gifmagazine.net/v1/gifs/search?q=' + query + '&limit=' + limit + '&offset' + offset + '&safe=' + safe; $.getJSON(URL, function (response) { console.log(response); })
Node.js
const request = require('request'); var URL = 'http://api.gifmagazine.net/v1/gifs/search'; request.get({ url: URL, headers: {'Content-type': 'application/json'}, qs: { q:"猫", limit:2, offset:0, safe:0 }, json: true }, function(err, req, json){ console.log(json); });
Response
{ "data": [ { "id": 4003, "url": "http://gifmagazine.net/post_images/4003", "title": "いけー!", "description": "#cat #猫 cat 猫", "user_name": "berururunnnnnnn", "file_size": 2525252, "rate": "g", "image": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.gif", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.gif", "width": 300, "height": 240 }, "small": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/small.gif", "width": 140, "height": 112 } }, "video": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.mp4", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.mp4", "width": 300, "height": 240 } }, "tags": [ "猫" ] }, ], "pagination": { "total_count": 1, "count": 1, "offset": 0 } }
感情検索
感情を表した絵文字に対応する名前で検索します。
パラメータ
- q(必須) : 各種絵文字に対応するName(詳細は現在対応済みの絵文字を参照)
- limit : 返ってくる検索結果の件数。デフォルトは2件。最大2件。0~2以外の数値を指定した場合はデフォルト値が利用されます。
- offset : オフセット。デフォルトは0。最大0。
- safe : 0を指定するとR-18のgifを検索結果から除く。1を指定するとR-18のgifも含んだ検索結果を返す。デフォルトは0。
現在対応済みの絵文字(2017/12/03現在)
Emoji | Name |
---|---|
😁 | grin |
😂 | joy |
😃 | smiley |
😄 | smile |
😅 | sweat_smile |
😆 | satisfied |
😉 | wink |
😊 | blush |
😋 | yum |
😌 | relieved |
😍 | heart_eyes |
😏 | smirk |
😒 | unamused |
😓 | sweat |
😔 | pensive |
😖 | confounded |
😘 | kissing_heart |
😚 | kissing_closed_eyes |
😜 | stuck_out_tongue_winking_eye |
😝 | stuck_out_tongue_closed_eyes |
😞 | disappointed |
😠 | angry |
😡 | rage |
😢 | cry |
😣 | persevere |
😤 | triumph |
😥 | disappointed_relieved |
😨 | fearful |
😩 | weary |
😪 | sleepy |
😫 | tired_face |
😭 | sob |
😰 | cold_sweat |
😱 | scream |
😲 | astonished |
😳 | flushed |
😵 | dizzy_face |
😷 | mask |
Request
var query = 'yum'; var limit = 1; var offset = 0; var safe = 0; var URL = 'http://api.gifmagazine.net/v1/gifs/emotion?q=' + query + '&limit=' + limit + '&offset' + offset + '&safe=' + safe; $.getJSON(URL, function (response) { console.log(response); })
Node.js
const request = require('request'); var URL = 'http://api.gifmagazine.net/v1/gifs/emotion'; request.get({ url: URL, headers: {'Content-type': 'application/json'}, qs: { q:"yum", limit:1, offset:0, safe:0 }, json: true }, function(err, req, json){ console.log(json);//返ってきたjson });
Response
{ "data": [ { "id": 727127, "url": "http://gifmagazine.net/post_images/727127", "title": "face savouring delicious food[9-6]", "description": "face savouring delicious food[9-6]", "user_name": "Mr.emotion", "file_size": 1191679, "rate": "g", "image": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/727127/original.gif", "width": 393, "height": 200 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/727127/medium.gif", "width": 300, "height": 153 }, "small": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/small.gif", "width": 140, "height": 112 } }, "video": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.mp4", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.mp4", "width": 300, "height": 240 } }, "tags": [ "猫" ] }, ], "pagination": { "total_count": 10, "count": 2, "offset": 0 } }
pickup , topic , jumble
pickup : Pickup Gifに選ばれた投稿の新着フィードを返す topic : 今web上で話題のGIFの新着フィードを返す jumble : pickupとtopicを混ぜたgifのフィードを返す
パラメータ
- limit : 返ってくる検索結果の件数。デフォルトは2件。最大2件。0~2以外の数値を指定した場合はデフォルト値が利用されます。
- offset : オフセット。デフォルトは0。最大0。
Request
var feed = 'pickup';//topic , jumble var limit = 1; var offset = 0; var safe = 0; var URL = 'http://api.gifmagazine.net/v1/feeds/' + feed + '?limit=' + limit + '&offset' + offset + '&safe=' + safe; $.getJSON(URL, function (response) { console.log(response); })
Node.js
const request = require('request'); var URL = 'http://api.gifmagazine.net/v1/feeds/'; var feed = 'pickup';//topic , jumble request.get({ url: URL + feed, headers: {'Content-type': 'application/json'}, qs: { limit:1, offset:0, safe:0 }, json: true }, function(err, req, json){ console.log(json); });
Response
pickup
{ "data": [ { "id": 4003, "url": "http://gifmagazine.net/post_images/4003", "title": "いけー!", "description": "#cat #猫 cat 猫", "user_name": "berururunnnnnnn", "file_size": 2525252, "rate": "g", "image": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.gif", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.gif", "width": 300, "height": 240 }, "small": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/small.gif", "width": 140, "height": 112 } }, "video": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.mp4", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.mp4", "width": 300, "height": 240 } }, "tags": [ "猫" ] } ], "pagination": { "total_count": 1, "count": 1, "offset": 0 } }
topic
{ "data": [ { "id": 4003, "url": "http://gifmagazine.net/post_images/4003", "title": "いけー!", "description": "#cat #猫 cat 猫", "user_name": "berururunnnnnnn", "file_size": 2525252, "rate": "g", "image": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.gif", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.gif", "width": 300, "height": 240 }, "small": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/small.gif", "width": 140, "height": 112 } }, "video": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.mp4", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.mp4", "width": 300, "height": 240 } }, "tags": [ "猫" ] }, ], "pagination": { "total_count": 1, "count": 1, "offset": 0 } }
jumble
{ "data": [ { "id": 4003, "url": "http://gifmagazine.net/post_images/4003", "title": "いけー!", "description": "#cat #猫 cat 猫", "user_name": "berururunnnnnnn", "file_size": 2525252, "rate": "g", "image": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.gif", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.gif", "width": 300, "height": 240 }, "small": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/small.gif", "width": 140, "height": 112 } }, "video": { "default": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/original.mp4", "width": 500, "height": 400 }, "medium": { "url": "http://img.gifmagazine.net/gifmagazine/images/4003/medium.mp4", "width": 300, "height": 240 } }, "tags": [ "猫" ] }, ], "pagination": { "total_count": 1, "count": 1, "offset": 0 } }
id検索
idで指定されたgifの詳細情報を返す。
パラメータ
- [必須]token : 専用トークンを指定する
Request
const YOUR_TOKEN = 'ここに専用トークンを書く'; var GIF_ID = 1;//gif画像のID var URL = 'http://api.gifmagazine.net/v1/detail_gifs/' + GIF_ID + '?token=' + YOUR_TOKEN ; $.getJSON(URL, function (response) { console.log(response); })
Node.js
const request = require('request'); const YOUR_TOKEN = 'ここに専用トークンを書く'; var URL = 'http://api.gifmagazine.net/v1/detail_gifs/'; var GIF_ID = 1;//gif画像のID request.get({ url: URL + GIF_ID , headers: {'Content-type': 'application/json'}, qs: { token:YOUR_TOKEN }, json: true }, function(err, req, json){ console.log(json); });
Response
{ "data": { "gif": { "id": 100000, "url": "https://gifmagazine.net/post_images/100000", "title": "かっこいいアウディが華麗に存在感を放っているGIF画像", "description": "[元動画] https://www.youtube.com/watch?v=_kPFr8H-o5g", "user_name": "gif_research61", "file_size": 2751967, "rate": "g", "image": { "default": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/original.gif", "width": 420, "height": 236 }, "medium": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/medium.gif", "width": 300, "height": 169 }, "small": { "url": "https://media.gifmagazine.net/rszgif/wiI-PfLjd7ltYD4Ric90Lj-EmMQ=/420/236/140/140/100000/", "width": 140, "height": 79 }, "medium_thumb": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/medium_thumb.png", "width": 300, "height": 169 }, "thumb": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/thumb.png", "width": 100, "height": 100 } }, "video": { "default": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/original.mp4", "width": 420, "height": 236 }, "medium": { "url": "https://img.gifmagazine.net/gifmagazine/images/100000/medium.mp4", "width": 300, "height": 169 } }, "tags": [ "from youtube", "車", "かっこいい", "普通車", "高級車", "アウディ" ] }, "related_gifs": [ { "id": 100023, "url": "https://gifmagazine.net/post_images/100023", "title": "かっこいいアウディが華麗に存在感を放っているGIF画像", "description": "[元動画] https://www.youtube.com/watch?v=qZVtnv3DeBI", "user_name": "gif_research61", "file_size": 3076909, "rate": "g", "image": { "default": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/original.gif", "width": 420, "height": 236 }, "medium": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/medium.gif", "width": 300, "height": 169 }, "small": { "url": "https://media.gifmagazine.net/rszgif/9XAWF4YNw99aR1XS_BffXhYDrzQ=/420/236/140/140/100023/", "width": 140, "height": 79 }, "medium_thumb": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/medium_thumb.png", "width": 300, "height": 169 }, "thumb": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/thumb.png", "width": 100, "height": 100 } }, "video": { "default": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/original.mp4", "width": 420, "height": 236 }, "medium": { "url": "https://img.gifmagazine.net/gifmagazine/images/100023/medium.mp4", "width": 300, "height": 169 } }, "tags": [ "from youtube", "車", "かっこいい", "普通車", "高級車", "アウディ" ] }, ] }, "pagination": { "total_count": 1, "count": 1, "offset": 0 } }
参考資料
Android×Processing:adb input touchscreen編
はじめに
この記事ではProcessingを使ってAndroid端末を操作しようと思います。
環境設定
'input touchscreen'
タッチや直線のスワイプといった単純な操作にはinput touchscreen
を使います
タッチの場合
adb shell input touchscreen tap x y
- 画面上の座標の(x,y)にタップする命令
- xとyは10進数
スワイプの場合
adb shell input touchscreen swipe x1 y1 x2 y2 t
- (x1,y1)から(x2,y2)までをスワイプする命令
t
はミリ秒
Processingとの連帯
今回使う命令
launch()
- コマンドを打つ命令(Macでも使用可能)
- 詳しくはProcessing:コマンドプロンプトを開いてみた - ZawaWorks’s diaryをご覧ください
例:adb shell input touchscreen tap x y
String [] AdbTap = {"adb","shell","input","touchscreen","tap",str(x),str(y)};//xとyはString型に変換 launch(AdbTap);
input tap
の場合
コード
String [] AdbTap = {"adb", "shell", "input", "touchscreen", "tap", "", ""}; void setup() { size(360, 640);//Xperoa XZの解像度は 1080 x 1920 background(0, 0, 255); } void draw() { if (!mousePressed) return; fill(-1); ellipse(mouseX, mouseY, 15, 15); AdbTap[5] = str(mouseX*3); AdbTap[6] = str(mouseY*3); launch(AdbTap); }
デモ
input Swipe
の場合
コード
ArrayList<PVector>vector = new ArrayList(); Boolean launch_able = true; int time = 100; void setup() { size(360, 640); background(0, 0, 255); } void draw() { background(0, 0, 255); for (int i=0; i<vector.size(); i++) { PVector v = vector.get(i); fill(-1); ellipse(v.x, v.y, 20, 20); } if (vector.size() != 2) return; PVector v1 = vector.get(0); PVector v2 = vector.get(1); stroke(-1); line(v1.x, v1.y, v2.x, v2.y); if (!launch_able)return; launch("adb shell input touchscreen swipe"+" "+ v1.x+" "+ v1.y+" "+v2.x+" "+v2.y+" "+time); launch_able = false; } void mousePressed() { if (vector.size()%2 == 0) { vector = new ArrayList(); launch_able = true; } vector.add(new PVector(mouseX, mouseY)); }
デモ
youtu.be
- t = 100
のときとt = 50
のときを比較
GitHub
参考資料
Android×Processing:adb getevent編
はじめに
前に紹介したadbコマンドをProcessingと組み合わせてみました。この記事ではAndroid端末のタッチイベントをProcessingを使ってリアルタイムでアニメーションします。
環境設定
- Processing3.3.6
- Xperia XZ
- Windows10
おさらい
adbのgeteventコマンドが分からない方は前の記事を読んでから次へ進んでください。
実装方法
今回使うコマンドはadb shell getevent -lt
です。これで得たログデータをテキストファイルに書き込み、それをProcessingで読み込みます。
用意するディレクトリ
AdbGetevent
フォルダーAdbGetevent.pde
data
フォルダーpos.txt
AdbGetevent.pde
void setup() { size(360, 640); //テキストファイルを空に PrintWriter output; output = createWriter("data/pos.txt"); output.close(); } void draw() { background(0, 0, 255); //テキストファイルを読み込む String []lines = loadStrings("data/pos.txt"); float posX = 0; float posY = 0; for (int i=0; i<lines.length; i++) { int getx_point = lines[i].indexOf("ABS_MT_POSITION_X "); int gety_point = lines[i].indexOf("ABS_MT_POSITION_Y "); if (getx_point != -1) { String result = lines[i].substring(getx_point+21, getx_point+29); posX = unhex(result) / 3.0;//Processingの画面に合わせる continue; } if (gety_point != -1) { String result=lines[i].substring(gety_point+21, gety_point+29); posY = unhex(result)/3.0;//Processingの画面に合わせる noStroke(); fill(-1); ellipse(posX, posY, 10, 10); } } }
使い方
デモ
- 使用したアプリ
GitHub
Processing:コマンドプロンプトを開いてみた
はじめに
今回はProcessingでコマンドプロンプトを開くことを試みました。今回見つけた方法をそれまでの失敗を含めて紹介していきたいと思います。
環境設定
- Windows10
- Processing 3.2.1
launch()を使ってみる
launch()
はProcessingからファイルを実行できる命令です。
たとえば
void setup(){ launch("notepad.exe"); }
というコードを実行すればメモ帳が開かれます。これの応用でlaunch("cmd.exe")
と書き直して実行しました。
しかし動かない!
ここで躓いた僕はいろいろと原因を探してみました。
絶対パスが原因?
このサイトを見ると、絶対パスにしたことで解決した例がありました。それを参考にlaunch("C:\\Windows\\System32\\cmd.exe")
と入力してみました。
しかし動かない!
リファレンスを読んでみた
ここで諦めそうになった僕ですが、リファレンスを読み返してみました。するとこんな一文が……。
This function behaves differently on each platform. On Windows, the parameters are sent to the Windows shell via "cmd /c".
どうやらlaunch()
に書いた文字列をコマンドプロンプトに送って実行してるようです。コマンドプロンプトでcmd.exe
を開くときstart cmd.exe
と打つので試しに以下のようなコードを書きました。
void setup(){ launch("start cmd.exe"); }
これを実行すると……。
動いた!!!
当初の目的通り、Processingでコマンドプロンプトを開くことに成功しました!
ついでに
これで目的は達成しましたが、ついでに開いたコマンドプロンプトが実行したpdeファイルの入ったディレクトリに行くようにする方法も見つけました。これはバッチファイルというものを使います。バッチファイルはコマンドプロンプトで実行する命令をまとめたテキストファイルです。これに指定したディレクトリをたどり着き、かつ、コマンドプロンプトを実行するという命令を書き込みます。それをlaunch()
で実行します。
コード
void setup() { PrintWriter output = createWriter("data/test.bat");//test.batを空にして書き込みを開始! output.println("cd"+" "+sketchPath()); output.println("start cmd.exe"); output.flush(); output.close();//書き込み終了! launch(dataPath("test.bat")); }
実行の様子
(sketchPath()
やdataPath()
が分からない人はこちらを参考にしてください)
最後に
ただ開くだけだとlaunch("start cmd.exe")
でいいですがバッチファイルを使った方が汎用性があるように感じました。Windowsユーザの皆さんは試してみると良いかもしれません。