Akashic Records

Flet 메모장 본문

Python for Beginners

Flet 메모장

Andrew's Akashic Records 2024. 11. 14. 11:11
728x90

이 책에 포함된 예제 코드중 메모장 기능을 새로 만들어 보왔습니다.

 

이 코드에서는 Flet을 사용하여 사용자가 메모를 입력하고, 삭제하고, 선택할 수 있는 기능을 제공합니다. 데이터베이스와의 연동을 위해 memo_dbhandler.py 모듈을 별도로 작성하였 데이터베이스 작업을 분리함으로써 코드의 가독성과 유지보수를 용이하게 했습니다. 주요 기능으로는 메모 추가, 선택, 삭제, 및 모든 메모 삭제가 포함되며 데이터베이스로 통합되어 사용자의 메모 정보를 영구적으로 저장할 수 있습니다.

데이터 베이스 모듈(memo_dbhandler.py)

데이터베이스와 관련된 작업들을 수행하는 모듈로, 다음과 같은 역할을 합니다:

  1. 데이터베이스 설정 및 테이블 생성 (setup_db()) - 데이터베이스 연결을 생성하고 테이블이 없는 경우 생성합니다.
  2. 메모 삽입 (insert_memo()) - 새 메모를 삽입하고 삽입된 메모의 ID를 반환합니다.
  3. 메모 삭제 (delete_memo()) - 특정 메모 ID를 통해 메모를 삭제합니다.
  4. 모든 메모 삭제 (clear_memos_db()) - 데이터베이스에 있는 모든 메모를 삭제합니다.
  5. 메모 조회 (fetch_memos()) - 데이터베이스에 저장된 모든 메모를 가져옵니다.
import psycopg

def setup_db():
    # Set up database connection
    conn = psycopg.connect(
        dbname="postgres",
        user="postgres",
        password="xxxxxxx",
        host="xxxxxxxxx",
        port="5432"
    )
    cursor = conn.cursor()

    # Create memo table if it doesn't exist
    cursor.execute(
        """
        CREATE TABLE IF NOT EXISTS memos (
            id SERIAL PRIMARY KEY,
            content TEXT NOT NULL,
            bgcolor VARCHAR(7) NOT NULL
        )
        """
    )
    conn.commit()
    return conn, cursor

def insert_memo(cursor, conn, content, bgcolor):
    # Insert memo into the database
    cursor.execute(
        "INSERT INTO memos (content, bgcolor) VALUES (%s, %s) RETURNING id",
        (content, bgcolor)
    )
    memo_id = cursor.fetchone()[0]
    conn.commit()
    return memo_id

def delete_memo(cursor, conn, memo_id):
    # Delete memo from the database
    cursor.execute("DELETE FROM memos WHERE id = %s", (memo_id,))
    conn.commit()

def clear_memos_db(cursor, conn):
    # Clear all memos from the database
    cursor.execute("DELETE FROM memos")
    conn.commit()

def fetch_memos(cursor):
    # Fetch all memos from the database
    cursor.execute("SELECT id, content, bgcolor FROM memos")
    return cursor.fetchall()

 

memo_dbhandler.py 파일의 코드를 상세히 분석해 보겠습니다. 이 파일은 데이터베이스와 관련된 모든 작업을 처리하며, 이를 통해 메인 애플리케이션의 코드가 더욱 깔끔하게 유지될 수 있습니다. 각 함수는 특정한 데이터베이스 기능을 담당하여, 유지보수가 쉬운 구조로 나뉘어 있습니다.

 

코드 분석

1. setup_db() 함수

def setup_db():
    # Set up database connection
    conn = psycopg.connect(
        dbname="postgres",
        user="postgres",
        password="xxxxxxx",
        host="xxxxxxxxx",
        port="5432"
    )
    cursor = conn.cursor()

    # Create memo table if it doesn't exist
    cursor.execute(
        """
        CREATE TABLE IF NOT EXISTS memos (
            id SERIAL PRIMARY KEY,
            content TEXT NOT NULL,
            bgcolor VARCHAR(7) NOT NULL
        )
        """
    )
    conn.commit()
    return conn, cursor
  • setup_db 함수는 데이터베이스 연결을 설정하고 메모를 저장할 테이블을 생성하는 기능을 합니다.
    • psycopg.connect(): 데이터베이스 연결을 설정합니다. 여기서 데이터베이스 이름, 사용자명, 비밀번호, 호스트, 포트 번호 등을 지정합니다.
    • conn.cursor(): 데이터베이스에 명령을 실행할 수 있도록 커서를 생성합니다.
    • CREATE TABLE IF NOT EXISTS memos: 만약 memos 테이블이 존재하지 않는다면, 이 테이블을 생성합니다. 이 테이블은 id(자동 증가), content(메모의 내용), bgcolor(메모 배경색)을 저장합니다.
    • conn.commit(): 데이터베이스에 변경 사항을 저장합니다.
    • return conn, cursor: 설정된 연결과 커서를 반환하여 다른 함수에서 사용합니다.

2. insert_memo() 함수

def insert_memo(cursor, conn, content, bgcolor):
    cursor.execute(
        "INSERT INTO memos (content, bgcolor) VALUES (%s, %s) RETURNING id",
        (content, bgcolor)
    )
    memo_id = cursor.fetchone()[0]
    conn.commit()
    return memo_id
  • insert_memo 함수는 새로운 메모를 데이터베이스에 삽입하는 기능을 수행합니다.
    • SQL 쿼리: INSERT INTO memos (content, bgcolor)를 사용하여 새로운 메모를 삽입하고, RETURNING id를 통해 새로 삽입된 메모의 ID를 반환합니다.
    • cursor.fetchone(): 삽입된 메모의 ID를 가져옵니다.
    • conn.commit(): 데이터베이스에 변경 사항을 저장합니다.
    • 반환값: 새로 삽입된 메모의 ID를 반환합니다. 이는 이후에 메모를 화면에 표시할 때 참조하기 위해 사용됩니다.

3. delete_memo() 함수

def delete_memo(cursor, conn, memo_id):
    cursor.execute("DELETE FROM memos WHERE id = %s", (memo_id,))
    conn.commit()
  • delete_memo 함수는 특정 메모를 삭제하는 기능을 수행합니다.
    • SQL 쿼리: DELETE FROM memos WHERE id = %s를 사용하여 특정 ID를 가진 메모를 삭제합니다.
    • conn.commit(): 데이터베이스에 변경 사항을 저장합니다.

4. clear_memos_db() 함수

def clear_memos_db(cursor, conn):
    cursor.execute("DELETE FROM memos")
    conn.commit()
  • clear_memos_db 함수는 데이터베이스에 저장된 모든 메모를 삭제합니다.
    • SQL 쿼리: DELETE FROM memos를 사용하여 모든 메모를 삭제합니다.
    • conn.commit(): 변경 사항을 데이터베이스에 저장합니다.

5. fetch_memos() 함수

def fetch_memos(cursor):
    cursor.execute("SELECT id, content, bgcolor FROM memos")
    return cursor.fetchall()
  • fetch_memos 함수는 데이터베이스에서 모든 메모를 조회하는 기능을 수행합니다.
    • SQL 쿼리: SELECT id, content, bgcolor FROM memos를 사용하여 모든 메모를 선택합니다.
    • cursor.fetchall(): 선택된 모든 메모의 결과를 가져와 반환합니다.
    • 반환된 값은 리스트로, 각 메모는 (id, content, bgcolor) 형식의 튜플로 저장되어 있습니다.

 

728x90

메모 UI 앱 (memo.py)

import flet as ft
from memo_dbhandler import setup_db, insert_memo, delete_memo, clear_memos_db, fetch_memos

def main(page: ft.Page):
    # Set up database connection
    conn, cursor = setup_db()

    # Set page properties
    page.title = "Flet Memo App"
    page.window.width = 400
    page.window.height = 700
    page.theme_mode = "light"  # Set theme mode to Light

    # AppBar
    app_bar = ft.AppBar(
        leading=ft.Icon(ft.icons.MENU),
        title=ft.Text("Flet Memo Test"),
        center_title=True,
        bgcolor=ft.colors.INDIGO,
        actions=[
            ft.IconButton(ft.icons.SEARCH),
            ft.IconButton(ft.icons.SETTINGS)
        ]
    )

    # TextField for memo input
    memo_input = ft.TextField(
        label="메모 입력",
        multiline=True,
        width=400
    )

    # Dropdown for selecting memo background color with color preview
    def update_color_picker_bg(e):
        color_picker.bgcolor = color_picker.value
        page.update()

    # Dropdown for selecting memo background color with color preview
    color_picker = ft.Dropdown(
        label="배경 색 선택",
        options=[
            ft.dropdown.Option("#FFFFE0", text="Light Yellow"),
            ft.dropdown.Option("#ADD8E6", text="Light Blue"),
            ft.dropdown.Option("#90EE90", text="Light Green"),
            ft.dropdown.Option("#FFB6C1", text="Light Pink"),
            ft.dropdown.Option("#D3D3D3", text="Light Gray")
        ],
        value="#FFFFE0",  # Default to light yellow color
        on_change = update_color_picker_bg
    )
    color_picker.bgcolor = color_picker.value

    # Memo buttons
    add_memo_button = ft.ElevatedButton("메모 입력", on_click=lambda e: add_memo())
    delete_button = ft.ElevatedButton("메모 삭제", on_click=lambda e: delete_selected_memo())
    clear_button = ft.ElevatedButton("모두 삭제", on_click=lambda e: clear_memos())


    # Row to hold memo buttons
    button_row = ft.Row(
        controls=[add_memo_button, delete_button, clear_button],
        alignment= ft.MainAxisAlignment.SPACE_BETWEEN
    )

    # GridView to display memos like sticky notes
    memo_grid = ft.GridView(
        expand=True,
        max_extent=150,
        child_aspect_ratio=1.0,
        spacing=10,
        run_spacing=10
    )

    # Variable to keep track of the selected memo
    selected_memo = [None]

    # Load existing memos from the database
    def load_memos():
        rows = fetch_memos(cursor)
        for row in rows:
            memo_container = ft.Container(
                content=ft.Text(row[1]),
                padding=10,
                bgcolor=row[2],
                border_radius=8,
                on_click=lambda e, memo_id=row[0]: select_memo(memo_id)
            )
            memo_container.data = row[0]  # Store the memo ID for future reference
            memo_grid.controls.append(memo_container)
        page.update()

    # Function to add a memo to GridView and database
    def add_memo():
        if memo_input.value:
            # Insert memo into the database
            memo_id = insert_memo(cursor, conn, memo_input.value, color_picker.value)

            # Create memo container and add it to the grid
            memo_container = ft.Container(
                content=ft.Text(memo_input.value),
                padding=10,
                bgcolor=color_picker.value,
                border_radius=8,
                on_click=lambda e, memo_id=memo_id: select_memo(memo_id)
            )
            memo_container.data = memo_id  # Store the memo ID for future reference
            memo_grid.controls.append(memo_container)
            memo_input.value = ""
            page.update()

    # Function to select a memo
    def select_memo(memo_id):
        # Find the selected memo in the GridView and highlight it
        for memo in memo_grid.controls:
            memo.border = None
            if memo.data == memo_id:
                selected_memo[0] = memo
                memo.border = ft.border.all(2, ft.colors.RED)
        page.update()

    # Function to delete the selected memo from GridView and database
    def delete_selected_memo():
        if selected_memo[0] is not None:
            # Delete memo from the database
            delete_memo(cursor, conn, selected_memo[0].data)

            # Remove memo from the GridView
            memo_grid.controls.remove(selected_memo[0])
            selected_memo[0] = None
            page.update()

    # Function to clear all memos from GridView and database
    def clear_memos():
        # Clear all memos from the database
        clear_memos_db(cursor, conn)

        # Clear all memos from the GridView
        memo_grid.controls.clear()
        selected_memo[0] = None
        page.update()

    # Add controls to page
    page.add(
        app_bar,
        memo_input,
        color_picker,
        button_row,
        memo_grid
    )

    # Load memos from the database on startup
    load_memos()

ft.app(target=main)

이 코드는 Flet 라이브러리를 사용하여 메모 애플리케이션을 만드는 프로그램으로, 데이터베이스 관련 코드를 memo_dbhandler.py라는 별도의 파일에 분리해 관리하도록 설계되어 있습니다. 각 요소와 기능을 세부적으로 분석해보겠습니다.

 

1. 라이브러리 임포트 및 데이터베이스 핸들러 사용

import flet as ft
from memo_dbhandler import setup_db, insert_memo, delete_memo, clear_memos_db, fetch_memos
  • flet: Flet은 Python으로 UI를 구성하기 위한 라이브러리입니다. 이 코드는 UI 요소를 만드는 데 Flet을 사용합니다.
  • memo_dbhandler 모듈을 통해 데이터베이스 연결, 데이터 삽입, 삭제 등의 작업을 수행하는 함수들을 가져옵니다. 이는 코드 재사용성과 가독성을 높이는 역할을 합니다.

2. 메인 함수 정의 (main)

def main(page: ft.Page):
    # Set up database connection
    conn, cursor = setup_db()
  • setup_db() 함수는 데이터베이스 연결과 커서를 설정하여 반환합니다. 이 커서는 데이터베이스 명령어를 실행하는 데 사용됩니다.

3. 페이지 설정

page.title = "Flet Memo App"
page.window.width = 400
page.window.height = 600
page.theme_mode = "light"  # Set theme mode to Light
  • 페이지 제목을 설정하고, 창 크기를 400x600으로 설정합니다. 테마 모드를 Light로 설정하여 밝은 색조의 사용자 인터페이스를 제공하도록 합니다.

4. 상단바 (AppBar)

app_bar = ft.AppBar(
    title=ft.Text("Flet Memo Test"),
    center_title=True,
    bgcolor=ft.colors.BLUE,
    actions=[
        ft.Icon(ft.icons.MENU)
    ]
)
  • AppBar는 페이지 상단에 있는 제목 표시줄입니다.
    • 타이틀: "Flet Memo Test"라는 제목을 중앙에 배치합니다.
    • 배경색: 색상은 블루로 설정했습니다.
    • 액션 아이콘: 메뉴 아이콘을 추가해 사용자에게 추가 기능을 제공할 수 있습니다.

5. 메모 입력 필드와 배경색 선택 드롭다운

memo_input = ft.TextField(
    label="메모 입력",
    multiline=True,
    expand=True,
    width=page.width - 40
)
  • 메모 입력 필드는 사용자가 메모를 작성할 수 있는 공간입니다. 여러 줄 입력이 가능하도록 multiline=True로 설정했습니다.
color_picker = ft.Dropdown(
    label="배경 색 선택",
    options=[
        ft.dropdown.Option("#FFFFE0", text="Light Yellow"),
        ft.dropdown.Option("#ADD8E6", text="Light Blue"),
        ft.dropdown.Option("#90EE90", text="Light Green"),
        ft.dropdown.Option("#FFB6C1", text="Light Pink"),
        ft.dropdown.Option("#D3D3D3", text="Light Gray")
    ],
    value="#FFFFE0",
    on_change=update_color_picker_bg
)
  • 배경 색 선택 드롭다운: 사용자가 새 메모의 배경색을 선택할 수 있습니다. 초기 색상은 연한 노랑 (#FFFFE0)으로 설정되어 있습니다.
  • update_color_picker_bg 함수는 배경 색상이 선택될 때마다 드롭다운의 배경색을 업데이트합니다.

6. 메모 버튼 및 레이아웃 설정

add_memo_button = ft.ElevatedButton("메모 입력", on_click=lambda e: add_memo())
delete_button = ft.ElevatedButton("선택된 메모 삭제", on_click=lambda e: delete_selected_memo())
clear_button = ft.ElevatedButton("모든 메모 삭제", on_click=lambda e: clear_memos())

button_row = ft.Row(
    controls=[add_memo_button, clear_button, delete_button],
    alignment="spaceBetween"
)
  • 버튼들: 세 가지 버튼이 있습니다. 메모 입력, 선택된 메모 삭제, 모든 메모 삭제 버튼이 각각의 기능을 수행합니다.
  • 버튼 배치 행 (Row): 버튼들을 한 행에 배치하며, spaceBetween 정렬을 통해 버튼 간의 간격을 균등하게 유지합니다.

7. 메모 표시를 위한 GridView

memo_grid = ft.GridView(
    expand=True,
    max_extent=150,
    child_aspect_ratio=1.0,
    spacing=10,
    run_spacing=10
)
  • GridView는 메모를 마치 포스트잇처럼 정렬해 보여주는 역할을 합니다.
    • expand=True를 사용해 그리드가 화면 크기에 맞게 확장됩니다.
    • max_extent=150는 각 메모의 최대 크기를 설정합니다.
    • spacingrun_spacing을 통해 각 메모 사이의 간격을 설정합니다.

8. 데이터베이스와 관련된 주요 함수

load_memos()

def load_memos():
    rows = fetch_memos(cursor)
    for row in rows:
        memo_container = ft.Container(
            content=ft.Text(row[1]),
            padding=10,
            bgcolor=row[2],
            border_radius=8,
            on_click=lambda e, memo_id=row[0]: select_memo(memo_id)
        )
        memo_container.data = row[0]
        memo_grid.controls.append(memo_container)
    page.update()
  • 데이터베이스에 저장된 모든 메모를 불러와 화면에 표시합니다.
  • 각 메모는 Container로 그리드에 추가되며, 메모의 배경색과 내용을 표시합니다.
  • 클릭 시 select_memo 함수가 호출되어 메모를 선택합니다.

add_memo()

def add_memo():
    if memo_input.value:
        memo_id = insert_memo(cursor, conn, memo_input.value, color_picker.value)
        memo_container = ft.Container(
            content=ft.Text(memo_input.value),
            padding=10,
            bgcolor=color_picker.value,
            border_radius=8,
            on_click=lambda e, memo_id=memo_id: select_memo(memo_id)
        )
        memo_container.data = memo_id
        memo_grid.controls.append(memo_container)
        memo_input.value = ""
        page.update()
  • 메모 추가: 메모 입력 필드에 작성된 텍스트와 선택된 배경색을 사용해 데이터베이스에 새로운 메모를 추가하고, 그리드에 표시합니다.
  • 메모 ID를 통해 메모를 관리하며, 클릭 시 특정 메모를 선택할 수 있도록 합니다.

select_memo(memo_id)

def select_memo(memo_id):
    for memo in memo_grid.controls:
        memo.border = None
        if memo.data == memo_id:
            selected_memo[0] = memo
            memo.border = ft.border.all(2, ft.colors.RED)
    page.update()
  • 메모 선택: 사용자가 특정 메모를 선택하면 해당 메모에 빨간색 테두리를 표시해 선택되었음을 알립니다.
  • selected_memo 리스트를 사용해 현재 선택된 메모를 추적합니다.

delete_selected_memo()

def delete_selected_memo():
    if selected_memo[0] is not None:
        delete_memo(cursor, conn, selected_memo[0].data)
        memo_grid.controls.remove(selected_memo[0])
        selected_memo[0] = None
        page.update()
  • 선택된 메모 삭제: 데이터베이스에서 해당 메모를 삭제하고, 그리드에서도 제거합니다.
  • 선택된 메모가 없을 경우 함수가 아무 작업도 수행하지 않습니다.

clear_memos()

def clear_memos():
    clear_memos_db(cursor, conn)
    memo_grid.controls.clear()
    selected_memo[0] = None
    page.update()
  • 모든 메모 삭제: 데이터베이스의 모든 메모를 삭제하고, 화면에 표시된 모든 메모도 제거합니다.

9. 페이지에 컨트롤 추가 및 초기 메모 로드

page.add(
    app_bar,
    Row([memo_input, color_picker], alignment="spaceBetween"),
    button_row,
    memo_grid
)

load_memos()
  • 페이지에 상단바, 메모 입력 필드와 배경색 선택을 포함한 행, 버튼 행, 그리고 메모 그리드를 추가합니다.
  • load_memos() 함수를 호출하여 프로그램 시작 시 데이터베이스에서 메모를 불러옵니다.

메모장

728x90

'Python for Beginners' 카테고리의 다른 글

Flet로 만든 별다방 키오스크(Kiosk)  (0) 2024.11.11
Flet GridView로 만든 계산기  (1) 2024.11.08
Flet ListTitle  (0) 2024.11.07
Flet ListView  (0) 2024.11.05
Flet 날씨 App  (1) 2024.11.05
Comments