Pythonツール tkinter プログラム

Pythonで作る自動クリックスケジューラー:指定時刻に自動でマウスクリックを実行

概要

本記事では、Pythonを使用して指定した時刻に自動的にマウスクリックを実行するツールの作成方法について解説します。このツールは、GUIインターフェースを備えており、複数のクリックタスクをスケジュール管理することができます。

使用例

  • オンラインチケット予約での自動クリック
  • 定期的なシステム操作の自動化
  • Webサービスの予約投稿
  • オンラインゲームでの定時アクション

必要なPythonライブラリとインストール方法

このプログラムを実行するには、以下のライブラリが必要です:

pip install tkinter
pip install pyautogui

※tkinterは通常、Pythonのデフォルトインストールに含まれています。

使用手順

  1. プログラムを起動すると、GUIウィンドウが表示されます
  2. 日付と時刻を設定します(年/月/日/時/分/秒)
  3. 「クリック位置を設定」ボタンをクリックし、2秒以内に目的の位置にマウスカーソルを移動させます
  4. クリック位置が設定されたら、「クリック予約」ボタンで予約を確定します
  5. 予約したタスクは予約リストに表示され、残り時間がカウントダウンされます
  6. 必要に応じて、予約のキャンセルや全予約のキャンセルが可能です

注意点

  1. 過去の時刻は指定できません
  2. クリック位置を設定する前に予約することはできません
  3. プログラム実行中はPCをスリープさせないでください
  4. 画面解像度が変更されると、クリック位置がずれる可能性があります
  5. 重要な操作や決済関連での使用は推奨しません

プログラム

下記のコードをメモ帳などに丸々コピーしてpythonファイル(auto-click-scheduler.py)にしてください。

import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime
import pyautogui
import time
import threading

class ScheduledClick:
    def __init__(self, time, x, y, timer=None):
        self.time = time
        self.x = x
        self.y = y
        self.timer = timer

class AutoClickScheduler:
    def __init__(self, root):
        self.root = root
        self.root.title("Auto Click Scheduler")
        self.root.geometry("600x500")
        
        # スケジュール済みのクリックタスクリスト
        self.scheduled_tasks = []
        
        # GUI要素の作成
        self.create_widgets()
        
        # カウントダウン更新用
        self.countdown_thread = threading.Thread(target=self.update_countdown, daemon=True)
        self.countdown_thread.start()
        
    def create_widgets(self):
        # 日付入力フレーム
        date_frame = ttk.LabelFrame(self.root, text="日付設定", padding=10)
        date_frame.pack(fill="x", padx=10, pady=5)
        
        # 年の入力
        ttk.Label(date_frame, text="年:").grid(row=0, column=0, padx=5)
        self.year_var = tk.StringVar(value=str(datetime.now().year))
        self.year_entry = ttk.Entry(date_frame, textvariable=self.year_var, width=6)
        self.year_entry.grid(row=0, column=1, padx=5)
        
        # 月の入力
        ttk.Label(date_frame, text="月:").grid(row=0, column=2, padx=5)
        self.month_var = tk.StringVar(value=str(datetime.now().month))
        self.month_entry = ttk.Entry(date_frame, textvariable=self.month_var, width=4)
        self.month_entry.grid(row=0, column=3, padx=5)
        
        # 日の入力
        ttk.Label(date_frame, text="日:").grid(row=0, column=4, padx=5)
        self.day_var = tk.StringVar(value=str(datetime.now().day))
        self.day_entry = ttk.Entry(date_frame, textvariable=self.day_var, width=4)
        self.day_entry.grid(row=0, column=5, padx=5)
        
        # 時間入力フレーム
        time_frame = ttk.LabelFrame(self.root, text="時刻設定", padding=10)
        time_frame.pack(fill="x", padx=10, pady=5)
        
        # 時の入力
        ttk.Label(time_frame, text="時:").grid(row=0, column=0, padx=5)
        self.hour_var = tk.StringVar(value="00")
        self.hour_entry = ttk.Entry(time_frame, textvariable=self.hour_var, width=4)
        self.hour_entry.grid(row=0, column=1, padx=5)
        
        # 分の入力
        ttk.Label(time_frame, text="分:").grid(row=0, column=2, padx=5)
        self.minute_var = tk.StringVar(value="00")
        self.minute_entry = ttk.Entry(time_frame, textvariable=self.minute_var, width=4)
        self.minute_entry.grid(row=0, column=3, padx=5)
        
        # 秒の入力
        ttk.Label(time_frame, text="秒:").grid(row=0, column=4, padx=5)
        self.second_var = tk.StringVar(value="00")
        self.second_entry = ttk.Entry(time_frame, textvariable=self.second_var, width=4)
        self.second_entry.grid(row=0, column=5, padx=5)
        
        # クリック位置の設定ボタン
        self.position_button = ttk.Button(self.root, text="クリック位置を設定", command=self.set_click_position)
        self.position_button.pack(pady=10)
        
        # クリック位置の表示ラベル
        self.position_label = ttk.Label(self.root, text="クリック位置: 未設定")
        self.position_label.pack(pady=5)
        
        # 予約ボタン
        self.schedule_button = ttk.Button(self.root, text="クリック予約", command=self.schedule_click)
        self.schedule_button.pack(pady=10)
        
        # 予約リストのフレーム
        list_frame = ttk.LabelFrame(self.root, text="予約リスト", padding=10)
        list_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        # スクロールバー付きリストボックス
        self.scrollbar = ttk.Scrollbar(list_frame)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.task_listbox = tk.Listbox(list_frame, yscrollcommand=self.scrollbar.set, height=8)
        self.task_listbox.pack(fill="both", expand=True)
        
        self.scrollbar.config(command=self.task_listbox.yview)
        
        # 選択した予約のキャンセルボタン
        self.cancel_button = ttk.Button(self.root, text="選択した予約をキャンセル", command=self.cancel_selected)
        self.cancel_button.pack(pady=5)
        
        # 全予約のキャンセルボタン
        self.cancel_all_button = ttk.Button(self.root, text="全予約をキャンセル", command=self.cancel_all)
        self.cancel_all_button.pack(pady=5)
        
        # クリック位置の保存
        self.click_x = None
        self.click_y = None
    
    def set_click_position(self):
        """クリック位置を設定する"""
        self.root.iconify()  # ウィンドウを最小化
        time.sleep(2)  # 2秒待機
        
        # マウス位置を取得
        self.click_x, self.click_y = pyautogui.position()
        self.position_label.config(text=f"クリック位置: ({self.click_x}, {self.click_y})")
        
        self.root.deiconify()  # ウィンドウを復元
        messagebox.showinfo("設定完了", "クリック位置を設定しました")
    
    def schedule_click(self):
        """クリックを予約する"""
        if self.click_x is None or self.click_y is None:
            messagebox.showerror("エラー", "クリック位置を設定してください")
            return
        
        try:
            # 予約時刻の設定
            target_time = datetime(
                int(self.year_var.get()),
                int(self.month_var.get()),
                int(self.day_var.get()),
                int(self.hour_var.get()),
                int(self.minute_var.get()),
                int(self.second_var.get())
            )
            
            # 現在時刻との比較
            if target_time <= datetime.now():
                messagebox.showerror("エラー", "過去の時刻は指定できません")
                return
            
            # 新しいタスクの作成
            timer = threading.Timer(
                (target_time - datetime.now()).total_seconds(),
                self.execute_click,
                args=[target_time]
            )
            timer.start()
            
            # タスクの保存
            scheduled_click = ScheduledClick(target_time, self.click_x, self.click_y, timer)
            self.scheduled_tasks.append(scheduled_click)
            
            # リストボックスに追加
            self.update_task_list()
            
            messagebox.showinfo("予約完了", f"以下の時刻にクリックを予約しました:\n{target_time.strftime('%Y/%m/%d %H:%M:%S')}")
            
        except ValueError:
            messagebox.showerror("エラー", "正しい日時を入力してください")
    
    def execute_click(self, target_time):
        """予約したクリックを実行する"""
        pyautogui.click(self.click_x, self.click_y)
        
        # 実行済みタスクの削除
        self.scheduled_tasks = [task for task in self.scheduled_tasks if task.time != target_time]
        self.root.after(0, self.update_task_list)  # GUIスレッドでリスト更新
    
    def cancel_selected(self):
        """選択した予約をキャンセルする"""
        selection = self.task_listbox.curselection()
        if not selection:
            messagebox.showinfo("通知", "キャンセルする予約を選択してください")
            return
            
        index = selection[0]
        task = self.scheduled_tasks[index]
        task.timer.cancel()
        self.scheduled_tasks.pop(index)
        self.update_task_list()
        messagebox.showinfo("キャンセル完了", "選択した予約をキャンセルしました")
    
    def cancel_all(self):
        """全ての予約をキャンセルする"""
        if not self.scheduled_tasks:
            messagebox.showinfo("通知", "キャンセルする予約はありません")
            return
            
        for task in self.scheduled_tasks:
            task.timer.cancel()
        self.scheduled_tasks.clear()
        self.update_task_list()
        messagebox.showinfo("キャンセル完了", "全ての予約をキャンセルしました")
    
    def update_task_list(self):
        """予約リストを更新する"""
        self.task_listbox.delete(0, tk.END)
        for task in sorted(self.scheduled_tasks, key=lambda x: x.time):
            self.task_listbox.insert(tk.END, 
                f"{task.time.strftime('%Y/%m/%d %H:%M:%S')} - ({task.x}, {task.y})")
    
    def update_countdown(self):
        """カウントダウンの更新"""
        while True:
            if self.scheduled_tasks:
                for task in self.scheduled_tasks:
                    remaining = (task.time - datetime.now()).total_seconds()
                    if remaining > 0:
                        hours = int(remaining // 3600)
                        minutes = int((remaining % 3600) // 60)
                        seconds = int(remaining % 60)
                        
                        # リストボックスの項目を更新
                        index = self.scheduled_tasks.index(task)
                        self.root.after(0, lambda: self.task_listbox.delete(index))
                        self.root.after(0, lambda i=index, t=task, h=hours, m=minutes, s=seconds: 
                            self.task_listbox.insert(i, 
                                f"{t.time.strftime('%Y/%m/%d %H:%M:%S')} - ({t.x}, {t.y}) "
                                f"[残り {h:02d}:{m:02d}:{s:02d}]"))
            
            time.sleep(1)  # 1秒ごとに更新

if __name__ == "__main__":
    root = tk.Tk()
    app = AutoClickScheduler(root)
    root.mainloop()

あるいは、下のテキストファイルをダウンロードし、「.txt」を「.py」に変えることでそのまま使えます。

まとめ

このプログラムを使用することで、以下のような利点があります:

  1. 直感的なGUIで簡単に操作可能
  2. 複数のクリックタスクを同時にスケジュール管理
  3. 視覚的なカウントダウン表示でタスクの管理が容易
  4. タスクの追加・キャンセルが自由自在

プログラムの改善点や新機能の要望がありましたら、コメント欄でお知らせください。より使いやすいツールにアップデートしていきたいと思います。

-Pythonツール, tkinter, プログラム