LoginSignup
1
3

ffmpegの処理をtkinterでGUI化(その2: コンソール風出力表示)

Last updated at Posted at 2023-02-08

前回の続きです.
*この記事の続きはこちら

やりたいこと

  • 前回は一行ずつffmpegからの標準出力が表示されるプログレスバーを作った↓
    before.gif
  • これだと,通しで出力を確認することができない.出力内容をコピペすることもできない.
  • そこで,コンソールで表示されるときと同じようにテキストボックスに表示させる.
  • 完成したもの↓
    Animation.gif

GUIの内容

  • ffmpegで処理中に出力されるメッセージが一行ずつテキストボックスに追加される.
  • テキストボックスは一番下の最新行が表示されるよう自動にスクロールする.
  • テキストボックスの右側にスクロールバーをつける.
  • テキストボックスはキーボードからのキー入力を受け付けない(出力の中身は編集できないようにする)
  • ただし,Ctrl+Cは有効として,テキストボックス内の出力をマウスで選択してコピー可能とする.

環境

Windows 10 Pro, Python 3.7, miniconda(conda 4.11.0)

コード

import os, subprocess
import tkinter as tk
from tkinter import ttk, messagebox
import threading

command = "ffmpeg hogehoge" # ffmpegの処理コマンド

def start():
    progress = tk.Toplevel()
    progress.geometry("750x350")
    progress.title("processing...")
    progress.grab_set()
    progress.focus_set()
    bar = ttk.Progressbar(progress,mode='indeterminate')
    bar.pack(side = tk.TOP, fill = tk.X)

    info = tk.Text(progress)
    info.bind("<Key>", lambda e: ctrlEvent(e))
    scrollbar = tk.Scrollbar(progress, orient=tk.VERTICAL, command=info.yview)
    scrollbar.pack(side = tk.RIGHT, fill = tk.Y)
    info["yscrollcommand"] = scrollbar.set
    info.pack(side = tk.TOP, anchor = tk.W, fill = tk.BOTH)

    bar.start()

    def ctrlEvent(event):
        if(event.state & 2**2 == 4 and event.keysym=='c' ):
            return
        else:
            return "break"

    def process():
        p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True,universal_newlines=True)
        
        for line in p.stdout:
            info.insert(tk.END, line)
            info.see("end")

        try:
            outs, errs = p.communicate()
        except subprocess.TimeoutExpired:
            pass
        else:
            p.terminate()
            bar.stop()

    th1 = threading.Thread(target=process)
    th1.start()


root = tk.Tk()
button = tk.Button(root, text = "start", command = start)
button.pack()

root.mainloop()

ポイント

テキストボックスは一番下の最新行が表示されるよう自動スクロール

  • .see()を使う.
info.see("end")

テキストボックスの右側にスクロールバー

  • スクロールバーウィジェットを.pack()してからテキストウィジェットを.pack()しないとスクロールバーが正しい位置に表示されない.

テキストボックスはキーボードからのキー入力を受け付けない

ただし,Ctrl+Cは有効

  • ただし,上記ページに書かれているように,この方法(textbox.bind("<Key>", lambda a: "break"))だとCtrl+Cを受け付けてくれないので,例外として Ctrl+Cをバインドする.
  • 上記ページに記載されている条件if(12==event.state and event.keysym=='c' ):だと,上手くいかなかったので,if(event.state & 2**2 == 4 and event.keysym=='c' ):に変更した.
    参考: Python GUIプログラミング tkinter Canvas state Mod3
def ctrlEvent(event):
        if(event.state & 2**2 == 4 and event.keysym=='c' ):
            return
        else:
            return "break"
info.bind("<Key>", lambda e: ctrlEvent(e))
  • コピー動作の様子
    Animation2.gif

最後までお読みいただきありがとうございました.

1
3
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
3