1
5

More than 3 years have passed since last update.

Pythonのみを使って、今TODOアプリケーション(分散型)を作るとしたら - 拡張その1

Posted at

本記事の概要

本記事はQiita夏祭り2020の 「 〇〇(言語)のみを使って、今△△(アプリ)を作るとしたら」 を
テーマにして作成したTODOアプリケーション(分散型)機能拡張について説明を行うものです。

Pythonのみを使って、今TODOアプリケーション(分散型)を作るとしたらで執筆したTODOアプリケーションを
機能拡張してみました。
Qiita夏祭りのためだけに作ったつもりが楽しくなってきたので、これからゆっくりと拡張していこうと思います。

使用しているのはPython3(ver 3.7)であり、Windows10上で動作確認をしております。

コードは以下のGitHubに配置しております。ご自由にお使いください。

コード

拡張後のTODOアプリケーション(分散型)とは

見た目

以下のようなアプリケーションになりました。

todo_ver2.jpg

拡張された機能

拡張した機能は以下の4つになります。

  • TODOファイルに記載されたメタデータの表示
  • 期限日重要度を基にしたTODOファイルソート
  • TODOファイルの名前につけた重要度による色分け
  • TODO詳細画面からパスをクリックすることでテキストエディタを開く

TODOファイルに記載されたメタデータの表示

メタデータはTODO名の後に期限カテゴリとして追加されています。

todo_ver2_metadata.png

メタデータを表示したい場合はTODOファイルの先頭行に#メタデータ1 メタデータ2と記載していきます。

todo.txt
#2020/7/12 修正

todoの詳細

メタデータ自体はconfig.iniによって管理しています。
[Meta_data]部分です。数字(連番)の後にメタデータとして表示したいキー名を入力します。

この設定ファイルだと#2020/07/29TODOファイルの先頭行に記載すれば、TODO一覧の該当TODOへ
期限:2020/07/29という文字列が追記されます。

1番のメタデータは要らないけど、2番のメタデータは欲しい、つまりカテゴリだけ表示したい場合は、
#[半角スペース1文字]カテゴリ名とします。半角スペース文字を区切り文字としているので、
不要なメタデータは半角スペース1文字を入れましょう。

config.ini
[Dir_names]
django=F:\Document\800_IT自己学習\09_python\10_Django
kivy=F:\Document\800_IT自己学習\09_python\14_Kivy
qiita=F:\Document\800_IT自己学習\09_python\51_Qiita

[File_names]
todo=*todo*.txt

[Meta_data]
1=期限
2=カテゴリ

期限日、重要度を基にしたTODOファイルのソート

左側のプルダウンからソート方法を選択し、更新ボタンを押すことでソートできます。

importanceは重要度、limitは期限です。

todo_ver2_sort.png

importanceは設定ファイルのImportance_colorで使用されている重要度を使用します。
重要度は基本的にはA、B、Cのようなローマ字数字にすると分かりやすいかと思います。
ここは設定ファイルを変更することで好きなように出来ます。

config.ini
[Dir_names]
django=F:\Document\800_IT自己学習\09_python\10_Django
kivy=F:\Document\800_IT自己学習\09_python\14_Kivy
qiita=F:\Document\800_IT自己学習\09_python\51_Qiita

[File_names]
todo=*todo*.txt

[Importance_color]
default=white
A=red
B=yellow
C=green

[Meta_data]
1=期限
2=カテゴリ

TODOファイルの名前につけた重要度による色分け

これは設定ファイルに記載した重要度の対応をもとに、TODOリストの色を変える機能です。

上記で説明しているようにconfig.ini[Importance_color]を設定し、好きな色にすることが出来ます。

TODO詳細画面からパスをクリックすることでテキストエディタを開く

TODO詳細画面にファイルパスを記載しており、そこをダブルクリックすることでOS既定のプログラムを使用してTODOファイルを開くことが出来ます。

私の環境では.txtはサクラエディタで開くことになっているため、TODO詳細画面からファイルパスをクリックするとサクラエディタが開きます。

todo_ver2_open_texteditor.png

使い方

詳しくは前回の投稿ページに記載しております。

今回更新した設定ファイルはImportance_colorMeta_dataです。

config.ini
[Dir_names]
#プルダウンに表示される名前=TODOファイルを格納しているフォルダの絶対パス
#例
qiita=F:\Document\800_IT自己学習\09_python\51_Qiita

[File_names]
#TODOリスト一覧に表示したいファイル名。ワイルドカード(*)を使用できます。
#例

#先頭にtodoという文字列があるファイル
todo=todo*

#拡張子がpyのファイル
python=*.py

[Importance_color]
#重要度を表すためにファイル名で使用する文字列と対応する色
#defaultは重要度の文字列が入っていないファイルに対して使用される色です。
#色はredやblueなどの文字列で指定します。
default=white
A=red
B=yellow
C=green

[Meta_data]
#メタデータとして使用するファイル内の文字列の位置とメタデータのキー名
#TODOファイルの先頭行のうち#から始まるものをメタデータとして認識します。
# example: #2020/09/01 機能追加 とすれば期限:2020/09/01 カテゴリ:機能追加となります。
#          # 機能追加 とすればカテゴリ:機能追加となります(半角スペース1文字があるため期限は無視される)。
1=期限
2=カテゴリ

実装

TODOファイルに記載されたメタデータの表示

これは単純にTodoクラスにsearch_mata_dataメソッドを実装し、メタデータのリストを返してもらうようにしました。
メタデータのリストをlistbox.insertで表示しています。

display.py
...
class TodoDisplay:
    def display_todo(self):
        ...
        for path in paths:
            metadata_list = self.todo.search_meta_data(path)
            insert_statement_list = [path.split("\\")[-1].split(".")[0]]
            insert_statement_list.extend(metadata_list)
            insert_statement = " ".join(insert_statement_list)
            self.listbox.insert(todo_list_box_id, insert_statement)
        ...
...
todo.py
class Todo:
    ...

    def search_meta_data(self, path):
        linecache.clearcache()
        first_line = linecache.getline(path, 1)
        if "#" == first_line[0]:
            metadata_list = first_line[1:].split(" ")[:len(self.rule_file["Meta_data"].keys())]
            display_metadata_list = []
            for i, metadata in enumerate(metadata_list):
                if metadata != "":
                    display_metadata_list.append(":".join([self.rule_file["Meta_data"][str(i+1)], metadata]))
            return display_metadata_list
        else:
            return [""]
    ...

期限日、重要度を基にしたTODOファイルのソート

TodoDisplayクラスからTodoクラスにあるsort_todoメソッドを呼び出します。

引数としてcombbox(プルダウン)で選択されている文字列を渡し、sort_todoで渡された文字列に応じて呼び出す関数を変えています。

display.py
class TodoDisplay:
    ...
    def display_todo(self):
        ...
        if self.sort_combbox.get() == "":
            pass
        else:
            paths = self.todo.sort_todo(paths, method=self.sort_combbox.get())
        ...
    ...
todo.py
class Todo:
    ...
    def sort_todo(self, paths, method):
        if method == "importance":
            return self.sort_importance(paths)
        elif method == "limit":
            return self.sort_todo_limit(paths)

    def sort_importance(self, paths):
        path_dicts = []
        for path in paths:
            path_dict = {}
            file_name = path.split("\\")[-1].split(".")[0]
            result = self.judge_importance(file_name)
            if result is None:
                path_dict["importance"] = "z"
            else:
                path_dict["importance"] = result.group()[1]
            path_dict["path"] = path
            path_dicts.append(path_dict)

        sorted_path_dicts = sorted(path_dicts, key=lambda x: x["importance"])
        sorted_paths = [sorted_path_dict["path"] for sorted_path_dict in sorted_path_dicts]
        return sorted_paths

    def sort_todo_limit(self, paths):
        path_dicts = []
        for path in paths:
            path_dict = {}
            first_metadata = self.search_meta_data(path)[0]
            if self.rule_file["Meta_data"]["1"] in first_metadata:
                path_dict["metadata_todo_limit"] = first_metadata.split(":")[-1]
            else:
                path_dict["metadata_todo_limit"] = "9999/12/31"
            path_dict["path"] = path
            path_dicts.append(path_dict)

        sorted_path_dicts = sorted(path_dicts, key=lambda x: x["metadata_todo_limit"])
        sorted_paths = [sorted_path_dict["path"] for sorted_path_dict in sorted_path_dicts]
        return sorted_paths
    ...

TODOファイルの名前につけた重要度による色分け

Todoクラスのsearch_importanceメソッドへファイルパスを渡し、対応する色を返してもらいます。
その後、listbox.itemconfigを使用して色付けを行います。

リストボックスの個々の行へ色付けする方法は以下のリンクを参考にしました。

Is it possible to colour a specific item in a Listbox widget?

display.py
class TodoDisplay:
    ...
    def display_todo(self):
        ...
        for path in paths:
            ...
            importance_color = self.todo.search_importance(path.split("\\")[-1].split(".")[0])
            self.listbox.itemconfig(todo_list_box_id, {'bg': importance_color})
            ...
        ...
    ...

TODO詳細画面からパスをクリックすることでテキストエディタを開く

text.tag_bindを使用することで、イベントをテキストの文字列に紐づけることができます。
またos.system("start " + path)とすることで、OSに設定されている既定のプログラムでpathのファイルを開けます。

gui_object.py
class Listbox(tk.Listbox):
    ...
    def show_detail(self, event=None):
        ...
        self.text = Text(self.master_of_detail_text)
        self.text.tag_config('system_message', background="white", foreground="blue", underline=1)
        self.text.tag_bind("system_message", "<Double-Button-1>", self.open_with_another_app)
        self.text.insert(END, self.get_todo_list()[self.index(ACTIVE)], "system_message")
        ...
    ...

    def open_with_another_app(self, event=None):
        path = self.get_todo_list()[self.index(ACTIVE)]
        os.system("start " + path)

終わりに

なんだか、アプリケーションを成長させるのが楽しくなってきました。
RPGでキャラクターを育てている感覚と同じかもしれません。

これから使っていって、もっと拡張していけたらと思います。そろそろUIもしっかりさせようと。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5