しがないPGの自衛記録

基本ずっと寝てる

Electron+Vue.jsで日報ファイル作成アプリを作ってみた

f:id:ashitaka1963:20200428072704p:plain

はじめに

こちらの記事で毎日投稿している?日報記事のベースとなるファイルを自動で作成するスクリプトを作成しました。

しかし、スクリプトの仕様として実行した日付が設定されるので、前日のものを作成したい場合などにはわざわざ日付を変えたりと使いづらくなりました。

なので、最近勉強しはじめたVue.jsを使ってGUIアプリケーションを作成していきたいと思います。

本記事のゴール

pythonスクリプトと同等の機能を持つアプリケーションを作成する。 (同等機能なので今のところはpythonスクリプト実行したほうがはやいけど。。。)

環境

  • Windows 10 64bit
  • node v12.16.2
  • npm 6.14.4

利用ライブラリ

  • Element : 2.13.1
    • デスクトップUIライブラリ

事前準備

element-uiインストール

element-uiをローカルインストールするために以下のコマンドを実行する。

>npm install  element-ui

日報アプリの実装手順

これ以降は、前回作成した環境から変更した部分のみを書いています。

ソースコード全文を見たい方は、Githubをご確認ください。

github.com

ファイル構成

# 一部のみ記載
create_templete_file
├── resource
│   └── templete.md
└── src
    ├── assets
    │   └── logo.png
    ├── components
    │   └── WriteFile.vue
    ├── App.vue
    ├── background.js
    └── main.js

main.js

インストールしたelement-uiを使用できるようにするためにmain.jsに以下を追加します。

// element-ui のimport
import ElementUI from 'element-ui'

// element-ui の言語を日本語に設定(デフォルト:中国語)
import locale from 'element-ui/lib/locale/lang/ja'

// element-ui のCSSをimport
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI, {locale})

background.js

DevToolsは必要ないので、26行目の以下をコメントアウトします。

if (process.env.WEBPACK_DEV_SERVER_URL) {
  // Load the url of the dev server if in development mode
  win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
  // if (!process.env.IS_TEST) win.webContents.openDevTools() ←ここをコメントアウト
} else {
  createProtocol('app')
  // Load the index.html when not in development
  win.loadURL('app://./index.html')
}

App.vue

前回はHelloWorld.vueという単一コンポーネントを読み込んでいた箇所を専用のコンポーネントに変更しています。

<template>
  <div id="app">
    <WriteFile/>
  </div>
</template>

<script>
import WriteFile from './components/WriteFile.vue'

export default {
  name: 'App',
  components: {
    WriteFile
  }
}
</script>

components/WriteFile.vue

メインとなるコンポーネントファイルになります。

<template>
  <el-main>
    <!-- ファイル名入力欄 -->
    <el-input placeholder="ファイル名を入力してください。" v-model="input" class="input-with-select">
      <el-select v-model="select" slot="append" placeholder="Select">
        <el-option label=".md" value=".md"></el-option>
        <el-option label=".txt" value=".txt"></el-option>
      </el-select>
    </el-input>

    <!-- 本文入力欄 -->
    <el-input
      type="textarea"
      :rows="2"
      :autosize="{ minRows: 10, maxRows: 50}"
      placeholder="Please input"
      v-model="textarea">
    </el-input>

    <!-- ファイル読み込みボタン -->
    <el-button type="primary" @click="readTempleteFile()">ファイル読み込み</el-button>
    <!-- ファイル書き出しボタン -->
    <el-button type="success" @click="writeFile()">ファイル書き出し</el-button>
  </el-main>
</template>

<script>
  export default {
    data () {
      return {
        taskList: [],
        input: '',
        select: '.md',
        textarea: ''
      }
    },
    methods: {
      // テンプレートファイル読み込み
      readTempleteFile(){

        // 初期化
        this.textarea=""

        // 現在日付取得
        var dt = new Date();
        var yyyy = dt.getFullYear();
        var mm= ("00" + (dt.getMonth()+1)).slice(-2);
        var dd = ("00" + dt.getDate()).slice(-2);
        var dayOfWeek = dt.getDay() ; // 曜日(数値)
        var dayOfWeekStr = [ "日", "月", "火", "水", "木", "金", "土" ][dayOfWeek]; // 曜日(日本語表記)

        // パス設定
        const path = require('path');
        const basePath = process.cwd();
        const templeteFilePath = path.resolve(basePath, './resource/templete.md');

        // テンプレートファイル読み込み
        const fs = require('fs');
        var readline = require("readline");
        var stream = fs.createReadStream(templeteFilePath, "utf8");
        var reader = readline.createInterface({ input: stream });

        let isFileNameFlg =true;
        reader.on("line", (line) => {

          // ======= 変換仕様 =======
          // 日付変換(yyyymmdd)
          if ( line.match(/yyyymmdd/)) {
            var replaceStr =  yyyy + mm + dd;
            line = line.replace( "yyyymmdd", replaceStr );
          }

          // 日付変換(yyyy年mm月dd日(Day))
          if ( line.match(/yyyy年mm月dd日(Day)/)) {
            replaceStr =  yyyy + "年"+ mm + "月" + dd + "日" + "(" + dayOfWeekStr + ")";
            line = line.replace( "yyyy年mm月dd日(Day)", replaceStr );
          }

          // 1行目の判定
          if (isFileNameFlg) {
            this.input = line;
            isFileNameFlg =false;
          }else{
            this.textarea += line
            this.textarea += '\n'
          }
        });
      },
      // ファイル書き出し
      writeFile () {
        const fs = require('fs');
        fs.writeFileSync(this.input +this.select, this.textarea);

        this.$message({
          message: 'ファイルが正常に出力されました。',
          type: 'success'
        });
      },
    }
  }
</script>

<style scoped>
  main.el-main {
    width: 600px;
    margin: 0px auto;
  }
</style>

<style>
  .el-select .el-input {
    width: 70px;
  }
  .input-with-select .el-input-group__prepend {
    background-color: #fff;
  }
</style>

完成品

こちらが完成品になります。

機能

今回作った日報作成アプリの機能は以下になります。

現時点では、2つの変換仕様にそってテンプレートファイルの内容が変換されます。

  • ファイル読み込みボタンをクリックすることで、resource配下のtemplete.mdファイルを読み込み画面に表示する。
  • テンプレートファイルの仕様
    • 1行目:ファイル名
    • 2行目以降:本文
  • 変換仕様
    • yyyymmdd ⇒ ex) 20200426
    • yyyy年mm月dd日(Day) ⇒ ex) 2020年04月26日(日)
  • ファイル書き出しボタンをクリックすることで、create_templete_file配下にファイルを出力する。

デモ

f:id:ashitaka1963:20200428073533g:plain

まとめ

とりあえず、pythonスクリプトと同じことができるGUIアプリケーションは作成できました。

まだまだ以下のような課題はあるので、少しずつ改修していきたいと思います。

ビミョーなところ

  • UIがいまいち。
  • 実行ファイル形式exeにすると、上手く動作しない。(テンプレートファイルの読み込み先が固定なため)
  • ソースコードがぐちゃぐちゃ。
  • 変換仕様の文字列は全て変換されてしまう。
  • ファイル出力場所がプロジェクトフォルダの直下に固定なところ。

改善したいこと

  • テンプレートファイルの読み込み場所を動的に変更できるようにする。
  • 出力ファイルの出力先を動的に変更できるようにする。
  • 関数化する。(変換部分など)
  • 文字列の置き換え対象のルールを作成する。
続きを読む

Electron+Vue.jsでTodoアプリを作ってみた

f:id:ashitaka1963:20200422065206p:plain

はじめに

前回、Electron+Vue.jsの環境構築は完成したので、手始めにTodoアプリを作ってみました。

本記事のゴール

必要最低限の機能を備えたTodoアプリを開発するまでがゴールになります。

なお、本記事はこの記事を参考にさせていただきました。

環境

  • Windows 10 64bit
  • node v12.16.2
  • npm 6.14.4

利用ライブラリ

  • Element : 2.13.1
    • デスクトップUIライブラリ

事前準備

element-uiインストール

element-uiをローカルインストールするために以下のコマンドを実行する。

>npm install  element-ui

Todoアプリの実装手順

これ以降は、前回作成した環境から変更した部分のみを書いています。

ソースコード全文を見たい方は、Githubをご確認ください。

github.com

ファイル構成

# src以下のみ記載
./src
├── assets
│   └── logo.png
├── components
│   └── TodoList.vue
├── App.vue
├── background.js
└── main.js

main.js

インストールしたelement-uiを使用できるようにするためにmain.jsに以下を追加します。

// element-ui のimport
import ElementUI from 'element-ui'

// element-ui の言語を日本語に設定(デフォルト:中国語)
import locale from 'element-ui/lib/locale/lang/ja'

// element-ui のCSSをimport
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI, {locale})

background.js

TodoアプリにDevToolsは必要ないので、26行目の以下をコメントアウトします。

if (process.env.WEBPACK_DEV_SERVER_URL) {
  // Load the url of the dev server if in development mode
  win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
  // if (!process.env.IS_TEST) win.webContents.openDevTools() ←ここをコメントアウト
} else {
  createProtocol('app')
  // Load the index.html when not in development
  win.loadURL('app://./index.html')
}

App.vue

前回はHelloWorld.vueという単一コンポーネントを読み込んでいた箇所をTodoアプリ用のTodoListコンポーネントに変更しています。

<template>
  <div id="app">
    <!-- logo画像は不要のため、コメントアウト -->
    <!-- <img alt="Vue logo" src="./assets/logo.png"> -->

    <!-- 単一ファイルコンポーネントの読み込み先の変更 -->
    <!-- <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <TodoList/>
  </div>
</template>

<script>
<!-- import HelloWorld from './components/HelloWorld.vue' -->
import TodoList from './components/TodoList.vue'

export default {
  name: 'App',
  components: {
    <!-- HelloWorld -->
    TodoList
  }
}
</script>

components/TodoList.vue

メインとなるコンポーネントファイルになります。

<template>
  <el-main>
    <!-- ===== タスク入力 ===== -->
    <!-- 入力欄 -->
    <el-input v-model="input" placeholder="タスク名を入力" clearable>
      <!-- 追加ボタン -->
      <el-button slot="append" size="mini"  icon="el-icon-plus" @click="insertTask">追加</el-button>
    </el-input>

    <!-- ===== Todoタスク一覧 ===== -->
    <p>Todo</p>
    <el-table :data="taskList" :show-header="false" stripe>
      <!-- 完了ボタン -->
      <el-table-column align="center" width="100px">
        <template slot-scope="record">
          <el-button size="mini" type="primary" @click="moveDoneTask(record.$index)" circle plain></el-button>
        </template>
      </el-table-column>
      <!-- タスク名 -->
      <el-table-column prop="task" width="auto"></el-table-column>
      <!-- 削除ボタン -->
      <el-table-column align="center" width="100px">
        <template slot-scope="record">
          <el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteTask(record.$index)">削除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- ===== Doneタスク一覧 ===== -->
    <p>Done</p>
    <el-table :data="doneList" :show-header="false" stripe>
      <!-- 戻すボタン -->
      <el-table-column align="center" width="100px">
        <template slot-scope="record">
          <el-button size="mini" type="primary" icon="el-icon-check" @click="moveTodoTask(record.$index)" circle></el-button>
        </template>
      </el-table-column>
      <!-- タスク名 -->
      <el-table-column prop="done" width="auto"></el-table-column>
    </el-table>
  </el-main>
</template>

<script>
  export default {
    data () {
      return {
        taskList: [],
        doneList: [],
        input: ''
      }
    },
    methods: {
      // タスク追加
      insertTask () {
        // タスクが未入力の場合、エラーメッセージを表示
        if(this.input == ''){
          this.$message({
            message: 'タスク名が入力されていません。',
            type: 'error',
            duration: 1000
          });
          return false;
        }

        this.taskList.push({task: this.input})
        this.input = ''
      },
      // タスク移動(Todo⇒Done)
      moveDoneTask (index) {
        this.doneList.push({done: this.taskList[index].task})
        this.taskList.splice(index, 1)
      },
      // タスク移動(Done⇒Todo)
      moveTodoTask (index) {
        this.taskList.push({task: this.doneList[index].done})
        this.doneList.splice(index, 1)
      },
      // Todo削除
      deleteTask (index) {
        this.taskList.splice(index, 1)
      }
    }
  }
</script>

<style scoped>
  main.el-main {
    width: 600px;
    margin: 0px auto;
  }
</style>

完成品

機能

今回作ったTodoアプリの機能は以下になります。

  • タスクを入力して、追加ボタンを押すとTodo一覧に追加される。
    • 未入力の状態で、追加ボタンを押すと、エラーメッセージが表示される。
  • Todo一覧の左側の完了ボタンをクリックすると、Done一覧に移動する。
  • Todo一覧の右側の削除ボタンをクリックすると、選択行した行が削除される。
  • Done一覧の左側のチェックボタンをクリックすると、Todo一覧に戻す。

デモ

こちらが完成品になります。

f:id:ashitaka1963:20200422065247g:plain

まとめ

デスクトップUIライブラリのElementを使うだけで、簡単に見栄えの良いアプリを作成することができました。

デザインセンスがない私にとっては、これからUIライブラリはかかせないものになりそうです。

vueについてはまだまだわからないことだらけなので、機能拡充しながら引き続き勉強していきたいと思います。

参考にさせて頂いたサイト

続きを読む

テーマ「ZENO-TEAL」のリンクをカスタマイズしてみた

f:id:ashitaka1963:20200423223238p:plain

はじめに

私のブログでは、ZENO-TEAL - テーマ ストアを利用しているのですが、 箇条書きリンク(liタグ内にaタグを設置)の見え方がいまいちだったので、cssをカスタマイズしました。

いまいちだった点

見た目がただの文字列になってしまっており、リンクとして飛べるような見た目になっていない。

f:id:ashitaka1963:20200423222640p:plain

こちらが記事のマークダウン(.md)になります。

## 参考にさせて頂いたサイト

* [サンプルアプリをいじりながらVue.js+Electronを学ぼう! 環境構築編 - Qiita](https://qiita.com/suzuq/items/026c43ad6f2d9f8697f7)
* [[Vue.js] Vue CLI 3 で electron-vue の環境を構築する方法](https://mseeeen.msen.jp/electron-for-vue-cli-3/)
* [Electron+Vue.jsを使ったデスクトップアプリ開発を始める手順](https://www.virment.com/vue-electron/)

変更した点

  1. 自身のブログのトップ画面にログインした状態でアクセスする。
  2. 画面右上の[自身のID▼(ashitaka1963)] > [デザイン]をクリックする。
  3. サイドバーの[レンチアイコン] > [デザインCSS]をクリックする。
  4. テキストボックスに以下を追記する。
/* liタグ配下のaタグのアンダーライン */
li >a {
  text-decoration: underline;
}
/* マウスホバー時に背景色を変更 */
li > a:hover {
  background: #cce7ff;
}

完成品

文字列にアンダーバーを付けています。 また、マウスオーバーした際には背景色を変更するようにしています。

f:id:ashitaka1963:20200423222900p:plain

続きを読む

2020年04月21日(火) 日報

f:id:ashitaka1963:20200421223156p:plain

AtCoder Beginner Contest全問解いてみたチャレンジ

今日は下の2問を解いた。

  1. ABC154 B
  2. ABC155 B

累計として、135問

今日の学び

Python】連続した数値を出力する

print('x' * 5)
# xxxxx

# 数字の場合は、掛け算
print(1 * 5)
# 5
続きを読む

Electron+Vue.jsの環境構築

f:id:ashitaka1963:20200420194011j:plain

はじめに

デスクトップアプリケーションを作りたいと思い、色々物色しているとWeb技術(HTML,CSS,JavaScript)で作成できるElectronなるものがあることを知りました。

そしてElectronでは、最近の流行りのJavaScriptフレームワークであるVue.jsも使えるとのこと。

これは、色々と勉強にもなるなと思ったので、これからElectron+Vue.jsを使って色んなアプリを作っていきたいと思います。

本記事のゴール

「よし、サンプルコードを修正してアプリケーションを開発していくぞ。」の前のあまり楽しくないけどめっちゃ重要で、つまると中々抜け出せない環境構築を行い、サンプルアプリケーションを実行するまでがゴールになります。

なお、本記事は10割近くをこの記事を参考にさせていただきました。

環境

  • Windows 10 64bit
  • node v12.16.2
  • npm 6.14.4

利用ツールなど

事前準備

Node.jsインストール

Node.jsにアクセスして、自身の環境にあったLTS(推奨版)をダウンロードし、インストールする。

  1. 初期画面で[Next]をクリックする。
  2. End-User License Agreementで同意して[Next]をクリックする。
  3. Destination Folderでデフォルトで[Next]をクリックする。
  4. Custom Setupはデフォルトで[Next]をクリックする。
  5. Toold for Native Modulesはデフォルト(チェックなし)で[Next]をクリックする。
  6. [Install] > [Finish]で完了

参考: Node.js - Windows10へのインストール方法 (Version 12)

Node.jsインストール確認

コマンドラインからnode -vnpm -vを入力してバージョンが表示されれば、nodeのインストールは完了になります。

>node -v
v12.16.3

>npm -v
6.14.4

環境構築手順

Vue CLI インストール

コマンドプロンプトで下のコマンドを実行する

# グローバルインストール
>npm install -g @vue/cli

Vue CLI インストール確認

コマンドプロンプトで下のコマンドを実行してバージョンが表示されればOKです。

>vue --version
@vue/cli 4.3.1

この後、使用するVue CLI Plugin Electron BuilderがVue cliのバージョンに対応しているかどうかは気をつけること。

現在、v4は対応しているため、次に進む。

プロジェクト作成

プロジェクト名は初めてなので「hello_vue_electron」という名前で作成する。

下のコマンドを叩くと、デフォルトかマニュアルのどっちで作成するか聞かれたけど、今回は特にこだわりがないのでデフォルトを選択した。

# グローバルインストール
>vue create hello_vue_electron

実行したパスに「hello_vue_electron」フォルダが作成されていればプロジェクトの作成は完了です。

electron-builderのインストール

Vue CLI Plugin Electron Builderを利用してvueアプリケーションが、Electronのデスクトップアプリとして動作するようにします。

Electronのバージョンは、6系を選択した。

>cd hello_vue_electron
>vue add electron-builder

# Choose Electron Version ^6.0.0

サンプルアプリの起動

ここまでの手順でサンプルアプリのひな型がインストールされ、デスクトップアプリケーションとして動作する状態になっている。

下のコマンドで起動すると、アプリケーションが立ち上がり画面が表示される。

>npm run electron:serve

なお、一度この手順でアプリケーションを作成した場合、これ以降は環境構築手順のプロジェクト作成から開始でOKです。 (Vue CLIはグローバルでインストールしているため。)

まとめ

環境構築というとつまりながらやるイメージがあったけど、cliとそのプラグインのおかげで特に詰まるところなく、一気に環境構築までできました。

あくまでここはスタートラインなのでこれから独自のアプリケーションを作成していきたいと思います。

github.com

参考にさせて頂いたサイト

続きを読む

2020年04月19日(日) 日報

f:id:ashitaka1963:20200421082535p:plain

AtCoder Beginner Contest全問解いてみたチャレンジ

今日はさぼり。

今日の学び

Electronとは

GitHubが開発したオープンソースのソフトウェアフレームワークである。

ChromiumとNode.jsを使っており、HTML、CSSJavaScriptのようなWeb技術で、macOSWindowsLinuxに対応したデスクトップアプリケーションをつくることができる。

wikipediaより

Node.jsとは

サーバサイドのJavaScript実行環境

ノンブロッキングI/Oを用いてC10K問題 (クライアント1万台接続問題)を解決する

npmとは

Node Package Managerの略。

Node.jsのライブラリや、パッケージを管理するためのもの。

node.jsインストールしたらこれもインストールされる。

続きを読む