はじめに
こんにちは!今回は、Pythonとpygameを使って、シンプルで使いやすいフローチャート作成ツールを作ってみました。この記事では、ツールの要件、仕様、実装方法、そして使い方までを詳しく解説します。
📋 要件
- 複数の図形(開始/終了、処理、判断、入出力)を配置できること
- 図形間を線で接続できること
- 図形内にテキストを入力できること
- 直感的な操作で図形の配置と接続ができること
- シンプルで分かりやすいユーザーインターフェース
🛠️ 仕様
-
画面レイアウト
- 左側にパレット(図形選択用サイドバー)
- 右側にキャンバス(フローチャート作成エリア)
-
図形
- 種類:楕円(開始/終了)、長方形(処理)、ひし形(判断)、平行四辺形(入出力)
- 各図形に4つの接続端子(上下左右)
-
操作方法
- 図形の追加:パレットからドラッグ&ドロップ
- 図形の移動:ドラッグ
- 線の接続:端子をクリックして別の端子をクリック
- テキスト入力:図形をクリックして選択後、キーボード入力
-
視覚的フィードバック
- 線を引いている途中で仮の線を表示
🚀 実装
それでは、実際のコードを見ていきましょう。
import pygame
import sys
# 色の定義
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
LIGHT_BLUE = (173, 216, 230)
LIGHT_GREEN = (144, 238, 144)
LIGHT_PINK = (255, 182, 193)
LIGHT_YELLOW = (255, 255, 224)
GRAY = (200, 200, 200)
# 画面サイズ
WIDTH = 1000
HEIGHT = 600
SIDEBAR_WIDTH = 200
class Shape:
def __init__(self, x, y, width, height, color, shape_type):
self.rect = pygame.Rect(x, y, width, height)
self.color = color
self.text = ""
self.shape_type = shape_type
self.connectors = [
pygame.Rect(x, y + height // 2 - 5, 10, 10),
pygame.Rect(x + width - 10, y + height // 2 - 5, 10, 10),
pygame.Rect(x + width // 2 - 5, y, 10, 10),
pygame.Rect(x + width // 2 - 5, y + height - 10, 10, 10)
]
def draw(self, screen):
if self.shape_type == "rectangle":
pygame.draw.rect(screen, self.color, self.rect)
elif self.shape_type == "oval":
pygame.draw.ellipse(screen, self.color, self.rect)
elif self.shape_type == "diamond":
points = [
(self.rect.centerx, self.rect.top),
(self.rect.right, self.rect.centery),
(self.rect.centerx, self.rect.bottom),
(self.rect.left, self.rect.centery)
]
pygame.draw.polygon(screen, self.color, points)
elif self.shape_type == "parallelogram":
offset = self.rect.width // 4
points = [
(self.rect.left + offset, self.rect.top),
(self.rect.right, self.rect.top),
(self.rect.right - offset, self.rect.bottom),
(self.rect.left, self.rect.bottom)
]
pygame.draw.polygon(screen, self.color, points)
for connector in self.connectors:
pygame.draw.rect(screen, BLACK, connector)
font = pygame.font.Font(None, 24)
text_surface = font.render(self.text, True, BLACK)
text_rect = text_surface.get_rect(center=self.rect.center)
screen.blit(text_surface, text_rect)
def contains(self, pos):
return self.rect.collidepoint(pos)
def get_connector(self, pos):
for i, connector in enumerate(self.connectors):
if connector.collidepoint(pos):
return i
return None
def move(self, dx, dy):
self.rect.move_ip(dx, dy)
for connector in self.connectors:
connector.move_ip(dx, dy)
class FlowchartTool:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("フローチャートメーカー")
self.clock = pygame.time.Clock()
self.shapes = []
self.lines = []
self.dragging_shape = None
self.selected_shape = None
self.line_start = None
self.font = pygame.font.Font(None, 24)
self.palette = [
Shape(20, 20, 160, 80, LIGHT_BLUE, "oval"),
Shape(20, 120, 160, 80, LIGHT_GREEN, "rectangle"),
Shape(20, 220, 160, 80, LIGHT_PINK, "diamond"),
Shape(20, 320, 160, 80, LIGHT_YELLOW, "parallelogram")
]
self.dragging_new = False
def run(self):
while True:
self.handle_events()
self.draw()
self.clock.tick(60)
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # 左クリック
self.handle_left_click(event.pos)
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
self.handle_left_release(event.pos)
elif event.type == pygame.MOUSEMOTION:
self.handle_mouse_motion(event.pos, event.rel)
elif event.type == pygame.KEYDOWN:
if self.selected_shape:
if event.key == pygame.K_BACKSPACE:
self.selected_shape.text = self.selected_shape.text[:-1]
elif event.key == pygame.K_RETURN:
self.selected_shape = None
else:
self.selected_shape.text += event.unicode
def handle_left_click(self, pos):
for shape in self.palette:
if shape.contains(pos):
self.dragging_new = True
new_shape = Shape(pos[0], pos[1], 160, 80, shape.color, shape.shape_type)
self.shapes.append(new_shape)
self.dragging_shape = new_shape
return
for shape in self.shapes:
connector = shape.get_connector(pos)
if connector is not None:
if self.line_start is None:
self.line_start = (shape, connector)
else:
start_shape, start_connector = self.line_start
if start_shape != shape:
self.lines.append((self.line_start, (shape, connector)))
self.line_start = None
return
if shape.contains(pos):
self.dragging_shape = shape
self.selected_shape = shape
return
self.selected_shape = None
self.line_start = None
def handle_left_release(self, pos):
if self.dragging_new:
self.dragging_new = False
if pos[0] < SIDEBAR_WIDTH:
self.shapes.pop()
self.dragging_shape = None
return
self.dragging_shape = None
def handle_mouse_motion(self, pos, rel):
if self.dragging_shape:
self.dragging_shape.move(rel[0], rel[1])
def draw(self):
self.screen.fill(WHITE)
pygame.draw.rect(self.screen, GRAY, (0, 0, SIDEBAR_WIDTH, HEIGHT))
for shape in self.shapes:
shape.draw(self.screen)
for line in self.lines:
start_shape, start_connector = line[0]
end_shape, end_connector = line[1]
start_pos = start_shape.connectors[start_connector].center
end_pos = end_shape.connectors[end_connector].center
pygame.draw.line(self.screen, BLACK, start_pos, end_pos, 2)
if self.line_start:
start_shape, start_connector = self.line_start
start_pos = start_shape.connectors[start_connector].center
pygame.draw.line(self.screen, BLACK, start_pos, pygame.mouse.get_pos(), 2)
for shape in self.palette:
shape.draw(self.screen)
pygame.display.flip()
if __name__ == "__main__":
tool = FlowchartTool()
tool.run()
🎨 主要な機能の解説
-
Shape クラス
- 各図形(楕円、長方形、ひし形、平行四辺形)を表現
- 図形の描画、移動、テキスト表示を管理
- 4つの接続端子を持つ
-
FlowchartTool クラス
- メインのアプリケーションロジックを管理
- イベント処理(マウス操作、キーボード入力)
- 図形の配置、線の接続、画面の描画を制御
-
図形の追加と移動
- パレットからドラッグ&ドロップで新しい図形を追加
- 既存の図形をドラッグして移動
-
線の接続
- 2つの端子を順にクリックして線を引く
- 接続中は仮の線を表示してフィードバックを提供
-
テキスト入力
- 図形をクリックして選択し、キーボードで入力
🖱️ 使い方
- 左側のパレットから必要な図形を選び、ドラッグしてキャンバスに配置します。
- 図形をクリック&ドラッグで移動できます。
- 線を引くには、以下の手順で行います:
- 最初の図形の端子(小さな黒い四角)をクリックします。
- マウスを動かすと、仮の線が表示されます。
- 別の図形の端子をクリックすると、線が確定します。
- 図形をクリックして選択し、キーボードでテキストを入力できます。
🌈 今後の改善案
- 線の種類(直線、曲線、矢印)を選択できる機能
- 図形のリサイズ機能
- フローチャートの保存と読み込み機能
- テキストのフォントやサイズの変更機能
- 取り消し(Undo)と再実行(Redo)機能
🎉 さいごに
このツールを使えば、簡単にフローチャートを作成できます。プログラムの流れやビジネスプロセスの可視化に役立つでしょう。ぜひ、このコードを基に自分だけのカスタマイズを加えて、さらに素晴らしいツールに進化させてください!
Happy Flowcharting! 🚀✨