このシリーズ記事では私の体験を記録として残すべくあれこれ書いていますが、読んでいても結局何をしたら真似できるのかわからんぞ、というご感想もあろうかと思いますので、私の環境を共有する記事もちょっと書いておこうと思います。
以前から「WebブラウザをGUIとしたアプリケーションを作った」という話をずっとしているわけですが、それってそもそもどうやるのと思われた方もいらっしゃるかもしれません。何をどう調べたら情報が出てくるかもあまりよくわからない感じがします。
挑戦しようとした時に一番困ることは、まさにこの「何を調べたらいいのかがわからない」ということだと思います。何を調べたらいいのかがわかるなら調べればいいのです。なので、私のスタンスとしては、知識そのものを提供するのではなく、何を調べたらいいのかの手掛かりになることを目指して書くことにします。知識の理解の手助けは私自身初学者ゆえ何も責任を持てませんので、学習そのものは書籍や学習サービス、インターネット検索などでどうにか頑張ってください。
なお親切な書籍やサービスはたくさんあるかと思いますが、私自身はインターネットの力で強引に進んできましたので、これがいいよというのを具体的に薦めることはできません。その上どういうワードで何を調べたのかも曖昧です。なので、全く良い導き手ではないことを先に侘びておきます。ですが「自分のペースでのんびりやりたい人」の良き友人でありたいと思っています。
本題に戻りましょう。WebブラウザをGUIとしたアプリケーションを自作するというのは、超簡単に言うと「自前のHTMLをブラウザで開く」ということです。GUIとは、コマンドプロンプト的ではない、マウスなどによって操作可能で人間にわかりやすいインターフェースのことです(「アプリケーション」と言って思い浮かぶものがつまりGUIです)。
その「自前のHTML」にてCSSやJavaScriptを呼び出して機能を使えるようにしているわけです。最もシンプルな方法は、拡張子htmlのファイルに然るべき書き方であれこれ書いて、ファイルをダブルクリックするなどして開くというものです。
htmlファイルの開き方はいくつかあります。列挙すると例えば以下のような選択肢です。言っている意味がわからないところもあるかもしれませんが、最初から全部理解する必要はありません。
- htmlファイルをそのままWebブラウザで開く
- ローカルサーバーを立て、htmlファイルを呼び出してWebブラウザで開く
- Electronのアプリケーションとしてhtmlファイルを開く(※Webブラウザではない)
どうしてこのような複雑な選択肢が生まれてしまうのかというと、Webブラウザにはローカルファイルの扱いに於いてセキュリティのための制約があるからです。1は制約がそのままで、2、3はその制約を回避しています。
ノートテイキングアプリケーションを作る場合、データというのはローカルファイルとして存在して、アプリケーション上で編集するためにそのファイルの中身を呼び出し、書き込んで保存する、という形になってほしいものと思います(私はそうです)。持って回った言い方になりましたが、ファイルを編集するタイプのデスクトップアプリケーションは普通そうなっています。
しかし、Webブラウザ上で実行するスクリプトによってローカルファイルを編集できるようになっていては危険極まりないので、Webブラウザでは通常そういうことができないようになっているわけです。ローカルファイルの内容を読み取るだけなら簡単な方法があるのですが、書き込むことはどう頑張ってもできません(ローカルサーバーを使わない限り)。
GUI自体を作ることができる言語を使えばこの問題は起こりませんが、GUIを作るというのはおそらくプログラミング初心者にはかなりハードルが高いので、セキュリティの問題の複雑さとの戦いがあってもなお「HTMLを書いてWebブラウザで開く」という方式を採用しています。
日頃、WebブラウザをGUIとして利用したアプリケーションについて語る中で、ローカルサーバーがどうこうとかElectronがどうこうとかいう話をしばしば登場させていますが、それはこういう事情によるものです。
最初の最初は普通にWebブラウザで開いて動かすものを作るのが簡単です。ローカルファイルへの保存は直にはできませんが、ブラウザ内には保存領域があるので(localStorage)、データが失われないように保存すること自体は可能です。なのでローカルサーバーだのElectronだのということがわからなくてもアプリケーションとして成り立つものは作ることができます。
やがて「ローカルファイルに保存できたらいいのに!」という気持ちが高まったらローカルサーバーやElectronの勉強をするということになるでしょう。ちなみに、Webサイトの運営をしたことがある人はサーバーというものに馴染みがあるかもしれませんが、私は全く無縁だったためサーバーという概念の理解が難しく、先にElectronを習得することになりました。今はElectronをやめてローカルサーバーでやっています。どちらが簡単ということはなく、それぞれ違う種類の難しさがあると思います。
ここまでの話と補足情報をまとめてざっくり整理しておきます。
- WebブラウザをGUIとした自作アプリケーションとは、ここではhtmlファイルを書いてWebブラウザで開いて動かすものを指している。
- Webブラウザは基本的にローカルファイルを編集できないようになっている。
- 代わりにWebブラウザにはlocalStorageという保存領域がある。
- Webブラウザからローカルファイルを編集するならローカルサーバーを立てる必要がある。
- WebブラウザではなくElectronというフレームワークを使えばローカルファイルを自由に編集できる。
- ElectronはWebブラウザではなくデスクトップアプリケーションだが、Chromium(Google ChromeやEdgeなどモダンなブラウザの核みたいもの)を使ってレンダリングしているので、感触としてはWebブラウザとほぼ同じ。
すぐ必要になるので検索すると良いかもしれないキーワードは以下の通り。
- HTML
- CSS
- JavaScript
- localStorage
- ブラウザのデベロッパーツール
いつかは調べることになるけど焦らなくていいキーワードが以下の通り。
- ローカルサーバー
- Electron
- Chromium
- Node.js
それでは最後に、htmlファイルを適当な名前で適当なフォルダに作ってみましょう(どこでもいいです)。
そのhtmlファイルを「メモ帳」か他のテキストエディタで開いて、以下をコピペしてください。簡単なスクリプトを書いてあります。
<html lang="ja"> | |
<head> | |
<meta charset="utf-8"> | |
<meta content='width=device-width,initial-scale=1.0,user-scalable=yes' name='viewport' /> | |
<title>Title</title> | |
<style> | |
body { | |
padding: 20px 50px; | |
} | |
#input { | |
width: 500px; | |
} | |
.item { | |
white-space: pre-wrap; | |
} | |
.item:hover { | |
background-color: #eee; | |
cursor: default; | |
} | |
#explain { | |
margin-top: 40px; | |
font-size: 90%; | |
} | |
</style> | |
</head> | |
<body spellcheck="false"> | |
<h2>簡易メモアプリ</h2> | |
<textarea id="input" rows="3" placeholder="好きな文字列を入力"></textarea> | |
<button id="add-item">追加</button> | |
<ul id="item-list"></ul> | |
<div id="explain"> | |
<p>説明書き</p> | |
<ul> | |
<li>テキストエリアに入力して「追加」をクリックでメモを記録します。</li> | |
<li>項目はダブルクリックで削除できます。</li> | |
<li>マウスオーバーで追加日時を確認できます。</li> | |
<li>保存機能は付けていないためリロードすると全て消去されます。</li> | |
</div> | |
</div> | |
<script> | |
const input = document.getElementById('input'); // 変数inputに入力欄のinput要素を代入する | |
const button = document.getElementById('add-item'); // 変数buttonに追加ボタンのbutton要素を代入する | |
button.addEventListener('click', addItem); // 追加ボタンをクリック時に関数addItemを実行させる | |
const list = document.getElementById('item-list'); // 変数listに項目を表示する欄のul要素を代入する | |
// 現在日時を取得して文字列にする関数 | |
function getDateAndTime() { | |
const now = new Date(); // 現在時刻のDateインスタンス(情報が詰まったオブジェクト) | |
// 数字を二桁に揃える(1→01にする)関数を作っておく | |
function formatNumber(number) { | |
return ('00' + number).slice(-2); | |
} | |
const year = now.getFullYear(); // 西暦4桁 | |
const month = formatNumber(now.getMonth() + 1); // 月(0始まりで取得するため1を加える) | |
const date = formatNumber(now.getDate()); // 日 | |
const hour = formatNumber(now.getHours()); // 時 | |
const minute = formatNumber(now.getMinutes()); // 分 | |
return `${year}/${month}/${date} ${hour}:${minute}`; // YYYY/MM/DD hh:mm | |
} | |
// 入力欄の値から項目を生成する関数 | |
function addItem() { | |
if (!input.value) return; // 入力欄が空ならreturn(処理の終了) | |
const item = document.createElement('li'); // li要素を作る | |
list.append(item); // 作ったli要素をul要素に追加する | |
item.textContent = input.value; // 内容に入力欄の文字列を入れる | |
item.classList.add('item'); // style適用のため「item」クラスをつける | |
item.addEventListener('dblclick', removeItem); // ダブルクリック時に関数removeItemを実行させる | |
item.title = getDateAndTime(); // 追加した日時をマウスオーバーで表示できるようにする | |
input.value = ''; // 入力欄の文字列をクリアする | |
} | |
// 項目を削除する関数 | |
function removeItem() { | |
const q = confirm('この項目を削除しますか?'); // ダイアログで確認する(回答がtrueまたはfalseで変数に代入される) | |
if (!q) return; // OKでないならreturn | |
this.remove(); // この関数が登録されている要素を削除する | |
} | |
</script> | |
</body> | |
</html> |
Webブラウザでこのhtmlファイルを開いてみましょう。こういう画面になると思います。(フォントは全然違ったものになると思います。)
テキストエリアに何かしら入力して追加ボタンをクリックすると、書いたものが下に表示されるはずです。入力と追加を繰り返すとどんどん下に追加されます。
追加されたものをダブルクリックしてみましょう。すると削除していいか聞かれます。OKで記述は削除されます。
これは簡単な例ですが、こういう処理の組み合わせによってアプリケーションを作っていくことになります。localStorageへの保存処理を作ってドラッグアンドドロップ処理や編集機能などを加えればToDoリストなどとして使えるものになるでしょう。
こんな感じでツールづくりのヒントを書いていこうかと思います。自分自身が初学者だから書けることというのも何かしらあるのではと思っています。先生ではなく隣の席の「ちょっと予習進んでるやつ」くらいの立ち位置のつもりです。一連のシリーズ記事の主目的は体験の文章化なのでこちらは余力があればになりますが、よろしければ参考になさってください。
なお、これは本シリーズに於いて「プログラミングの話が書いてあるのに参考にできない」という穴を埋めるためのものであり、正確な知識や網羅的な情報を提供することを目指したものではありません。独力で調べられる方は自力でお調べくださいますようお願い致します。
このシリーズ記事の概要はこちら→ノートテイキングアプリDIY体験記