If you were to create a TODO application (distributed) using only Python-extension 1

[3]: https://qiita.com/The-town/items/3bc23ea6eef140787ee2 # How to use [4]:https://stackoverflow.com/questions/5348454/is-it-possible-to-colour-a-specific-item-in-a-listbox-widget

Summary of this article

This article is about Qiita Summer Festival 2020 "If you want to make △△ (app) now using only 〇〇 (language)" This section describes the ** extension ** of the ** TODO application (distributed) ** created as a theme.

[If you want to make a TODO application (distributed) now using only Python] The TODO application I wrote in 2 I tried to expand the function. I've enjoyed making it just for the Qiita Summer Festival, so I'm going to slowly expand it.

I am using ** Python3 (ver 3.7) **, and I have confirmed the operation on Windows 10.

The code is located on the following GitHub. Feel free to use it.

[Code] 1

What is the expanded TODO application (distributed)?

Appearance

The application is as follows.

todo_ver2.jpg

Enhanced functionality

The expanded functions are the following four.

Display of metadata described in TODO file

Metadata is added after ** TODO name ** as ** deadline ** or ** category **.

todo_ver2_metadata.png

If you want to display ** metadata **, write ** # metadata 1 metadata 2 ** on the first line of the ** TODO ** file.

todo.txt


#2020/7/12 Fix

details of todo

** Metadata ** itself is managed by ** config.ini **. ** [Meta_data] ** part. After the number (serial number), enter the ** key name ** that you want to display as ** metadata **.

With this configuration file, if you write it in the first line of ** # 2020/07/29 ** and ** TODO file **, you can go to the corresponding TODO in the ** TODO list **. ** Deadline: 2020/07/29 ** will be added.

If you don't need the first metadata, but want the second metadata, that is, you want to display only ** categories ** ** # [1 character of half-width space] Category name **. Since the half-width space character is used as the delimiter, Enter ** one half-width space ** for unnecessary metadata.

config.ini


[Dir_names]
django=F:\Document\800_IT self-learning\09_python\10_Django
kivy=F:\Document\800_IT self-learning\09_python\14_Kivy
qiita=F:\Document\800_IT self-learning\09_python\51_Qiita

[File_names]
todo=*todo*.txt

[Meta_data]
1=Deadline
2=category

Sort TODO files based on due date and importance

You can sort by selecting the sorting method from the pull-down on the left and pressing the update button.

** importance ** is the importance and ** limit ** is the deadline.

todo_ver2_sort.png

** importance ** uses the ** importance ** used in ** Importance_color ** in the configuration file. I think that ** importance ** is basically easier to understand if it is ** romaji ** or ** number ** such as ** A, B, C **. You can do whatever you want here by changing the config file.

config.ini


[Dir_names]
django=F:\Document\800_IT self-learning\09_python\10_Django
kivy=F:\Document\800_IT self-learning\09_python\14_Kivy
qiita=F:\Document\800_IT self-learning\09_python\51_Qiita

[File_names]
todo=*todo*.txt

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

[Meta_data]
1=Deadline
2=category

Color-coded by importance given to the name of the TODO file

This is a function to change the color of the TODO list based on the correspondence between ** importance ** and ** color ** described in the configuration file.

As explained above, you can set ** [Importance_color] ** in ** config.ini ** to make it any color you like.

Open the text editor by clicking the path from the TODO details screen

The file path is described on the TODO details screen, and you can open the ** TODO file ** using the ** OS default program ** by double-clicking on it.

In my environment, **. Txt ** is supposed to be opened in Sakura Editor, so clicking the file path from the TODO details screen will open Sakura Editor.

todo_ver2_open_texteditor.png

How to use

Details are described in [Last Post Page] [3].

The updated configuration files are ** Importance_color ** and ** Meta_data **.

config.ini


[Dir_names]
#The name displayed in the pull-down=Absolute path of the folder containing the TODO file
#Example
qiita=F:\Document\800_IT self-learning\09_python\51_Qiita

[File_names]
#The file name you want to display in the TODO list. Wildcard(*)You can use.
#Example

#Files with the string todo at the beginning
todo=todo*

#Files with the extension py
python=*.py

[Importance_color]
#The color that corresponds to the string used in the file name to indicate importance
#default is the color used for files that do not contain a severity string.
#The color is specified by a character string such as red or blue.
default=white
A=red
B=yellow
C=green

[Meta_data]
#The position of the string in the file to be used as the metadata and the key name of the metadata
#Of the first line of the TODO file#Recognize anything that starts with as metadata.
# example: #2020/09/01 Deadline for adding functions:2020/09/01 Category:Functions will be added.
#          #Category if function is added:A function will be added (the deadline is ignored because there is one single-byte space).
1=Deadline
2=category

Implementation

Display of metadata described in TODO file

This simply implemented the ** search_mata_data ** method in the ** Todo ** class to get a list of metadata returned. The list of metadata is displayed by ** 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 [""]
    ...

Sort TODO files based on due date and importance

Call the ** sort_todo ** method in the ** Todo ** class from the ** TodoDisplay ** class.

The character string selected by ** combbox (pull-down) ** is passed as an argument, and the function to be called is changed according to the character string passed by ** 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
    ...

Color-coded by importance given to the name of the TODO file

Pass the file path to the ** search_importance ** method of the ** Todo ** class and have it return the corresponding color. Then use ** listbox.itemconfig ** for coloring.

I referred to the link below for how to color each line of the list box.

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

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})
            ...
        ...
    ...

Open the text editor by clicking the path from the TODO details screen

By using ** text.tag_bind **, you can associate ** event ** with a text string. You can also open the ** path ** file with the default program set in ** OS ** by setting ** os.system ("start" + 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)

At the end

Somehow, it's become fun to grow the application. It may be the same as raising a character in an RPG.

I hope to use it from now on and expand it further. It's time to make the UI solid.

Recommended Posts

If you were to create a TODO application (distributed) using only Python-extension 1
If you want to create a Word Cloud.
If you want to make a Windows application (exe) that can be actually used now using only Python
I tried to make a todo application using bottle with python
Go beginner tried to create a cloud native web application using Datastore / GAE
If you want to display values using choices in a template in a Django model
Try to create a Todo management site using WebSocket with Django (Swamp Dragon)
Create a shogi game record management application using Django 5 ~ Pass DB data to Template ~
I tried to create a table only with Django
(Python) Try to develop a web application using Django
What to do if you can't create a virtual environment using venv even though you're following the Django official website
How to get only the data you need from a structured data set using a versatile method
Create a game to control puzzle & dragons drops using pygame
[Django] What to do if the model you want to create has a large number of fields
If you want to become a data scientist, start with Kaggle
If you know Python, you can make a web application with Django
What to do if you get a minus zero in Python
What to do if you get a UnicodeDecodeError with pip install
If you want to assign csv export to a variable in python
How to save only a part of a long video using OpenCV
How to create a CSV dummy file containing Japanese using Faker
Check if you can connect to a TCP port in Python
Create a command line tool to convert dollars to yen using Python
What to do if you get a "Wrong Python Platform" warning when using Python with the NetBeans IDE
[Python] What to do if you get a ModuleNotFoundError when importing pandas using Jupyter Notebook in Anaconda