[update] pybfm.py を TkinterDnD2 がなくても起動するよう変更

This commit is contained in:
ocogeclub 2022-08-11 20:33:56 +09:00
parent 36c3497492
commit e92fbfc6ed
3 changed files with 226 additions and 215 deletions

4
.gitignore vendored
View File

@ -6,5 +6,7 @@ build/
*.bak *.bak
*.old *.old
out/
out/ .mypy_cache
tkinterdnd2

View File

@ -1,215 +1,224 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from tkinter import * from tkinter import *
from tkinterdnd2 import * try:
import os from tkinterdnd2 import *
import sys except ImportError:
import pyboard dnd = False
import serial.tools.list_ports else:
from tkinter import filedialog dnd = True
import os
##### 引数 ##### import sys
args = sys.argv import pyboard
try: import serial.tools.list_ports
dev = args[1] from tkinter import filedialog
except IndexError as err:
dev = False ##### 引数 #####
else: args = sys.argv
dev = (dev=='-f') try:
dev = args[1]
##### グローバル変数 ##### except IndexError as err:
gport = None dev = False
else:
##### イベントハンドラ ##### dev = (dev=='-f')
# リストボックスにドロップ
def listbox_drop(event): ##### グローバル変数 #####
files = listbox.tk.splitlist(event.data) gport = None
putfiles(files)
# キーボード ##### イベントハンドラ #####
def input_key(ev): # リストボックスにドロップ
if ev.keysym == 'F5': def listbox_drop(event):
reload() files = listbox.tk.splitlist(event.data)
elif ev.keysym == 'Delete': putfiles(files)
rmfiles() # キーボード
# ダブルクリック def input_key(ev):
def dbl_click(ev): if ev.keysym == 'F5':
run() reload()
# 右クリックメニュー elif ev.keysym == 'Delete':
def pop_menu(ev): rmfiles()
listbox.select_clear(0, END) # ダブルクリック
listbox.select_set(listbox.nearest(ev.y)) def dbl_click(ev):
pmenu.post(ev.x_root, ev.y_root) run()
# 右クリックメニュー
##### pyboard関数 ##### def pop_menu(ev):
# 接続・repl開始 listbox.select_clear(0, END)
def connect(): listbox.select_set(listbox.nearest(ev.y))
global gport pmenu.post(ev.x_root, ev.y_root)
try:
pyb = pyboard.Pyboard(gport) ##### pyboard関数 #####
except pyboard.PyboardError as err: # 接続・repl開始
gport = None def connect():
listbox.delete(0, END) global gport
set_title('Lost device : Please reload') try:
raise pyboard.PyboardError('Lost device') pyb = pyboard.Pyboard(gport)
pyb.enter_raw_repl(False) except pyboard.PyboardError as err:
return pyb gport = None
# repl終了・切断 listbox.delete(0, END)
def disconnect(pyb): set_title('Lost device : Please reload')
try: raise pyboard.PyboardError('Lost device')
pyb.exit_raw_repl() pyb.enter_raw_repl(False)
except Exception as err: return pyb
pass # repl終了・切断
try: def disconnect(pyb):
pyb.close() try:
except Exception as err: pyb.exit_raw_repl()
pass except Exception as err:
# ファイル送信 (複数可)(files: list of local filepath) pass
def putfiles(files): try:
pyb = connect() pyb.close()
for src in files: except Exception as err:
if os.path.exists(src): pass
if os.path.isfile(src): # ファイル送信 (複数可)(files: list of local filepath)
dest = os.path.basename(src) def putfiles(files):
print('ファイル "%s" を転送' % src) pyb = connect()
pyb.fs_put(src, dest) for src in files:
else: if os.path.exists(src):
print('フォルダは転送できません : %s' % src) if os.path.isfile(src):
else: dest = os.path.basename(src)
print('ファイル "%s" は見つかりません。' % f) print('ファイル "%s" を転送' % src)
ls(pyb) pyb.fs_put(src, dest)
disconnect(pyb) else:
# ポートスキャン:アルファベット順で一番若いポートを返す print('フォルダは転送できません : %s' % src)
def find_device(): else:
global gport print('ファイル "%s" は見つかりません。' % f)
for p in sorted(serial.tools.list_ports.comports()): ls(pyb)
if p.hwid.startswith('USB'): disconnect(pyb)
gport = p.device # ポートスキャン:アルファベット順で一番若いポートを返す
set_title(gport) def find_device():
break global gport
else: for p in sorted(serial.tools.list_ports.comports()):
gport = None if p.hwid.startswith('USB'):
set_title('No device') gport = p.device
raise OSError('Device not found') set_title(gport)
# 再読込:ここのみデバイスの再スキャンが入る break
def reload(): else:
if not gport: gport = None
find_device() set_title('No device')
if gport: raise OSError('Device not found')
listfiles() # 再読込:ここのみデバイスの再スキャンが入る
# ファイルリスト取得だけを行う def reload():
def listfiles(): if not gport:
pyb = connect() find_device()
ls(pyb) if gport:
disconnect(pyb) listfiles()
# ファイルリストを取得し、リストボックスに表示 (pyb: pyboard handle, src: target directory on device) # ファイルリスト取得だけを行う
def ls(pyb, src='/'): def listfiles():
cmd = ( pyb = connect()
"import uos\nfor f in uos.listdir(%s):\n" ls(pyb)
" print(f)" disconnect(pyb)
% (("'%s'" % src) if src else "") # ファイルリストを取得し、リストボックスに表示 (pyb: pyboard handle, src: target directory on device)
) def ls(pyb, src='/'):
retval = pyb.exec(cmd) cmd = (
files = retval.decode('utf-8').splitlines() "import uos\nfor f in uos.listdir(%s):\n"
listbox.delete(0, END) " print(f)"
for f in files: % (("'%s'" % src) if src else "")
listbox.insert(END, f) )
# ウィンドウタイトル (title: string) retval = pyb.exec(cmd)
def set_title(title): files = retval.decode('utf-8').splitlines()
root.title('PyBfm - ' + title) listbox.delete(0, END)
# デバイス上のファイルを実行 for f in files:
def run(follow=False): listbox.insert(END, f)
selected = listbox.curselection() # ウィンドウタイトル (title: string)
if len(selected): def set_title(title):
src = listbox.get(selected[0]) root.title('PyBfm - ' + title)
ext = os.path.splitext(src)[1] # デバイス上のファイルを実行
if ext == '.py': def run(follow=False):
cmd = 'exec(open("%s").read())' % src selected = listbox.curselection()
pyb = connect() if len(selected):
try: src = listbox.get(selected[0])
if follow: ext = os.path.splitext(src)[1]
print (pyb.exec(cmd).decode('utf-8')) if ext == '.py':
else: cmd = 'exec(open("%s").read())' % src
pyb.exec_raw_no_follow(cmd) pyb = connect()
except Exception as err: try:
print("Runtime error.") if follow:
print('Done.') print (pyb.exec(cmd).decode('utf-8'))
disconnect(pyb) else:
else: pyb.exec_raw_no_follow(cmd)
print('このファイルは実行できません') except Exception as err:
# ファイル選択ダイアログからファイル送信 print("Runtime error.")
def putdlg(): print('Done.')
fpath = filedialog.askopenfilename() disconnect(pyb)
if fpath: else:
putfiles([fpath]) print('このファイルは実行できません')
# ファイル受信 # ファイル選択ダイアログからファイル送信
def getfile(): def putdlg():
selected = listbox.curselection() fpath = filedialog.askopenfilename()
if len(selected): if fpath:
src = listbox.get(selected[0]) putfiles([fpath])
ext = os.path.splitext(src)[1] # ファイル受信
dest = filedialog.asksaveasfilename( def getfile():
initialfile=src, selected = listbox.curselection()
defaultextension=ext, if len(selected):
filetypes=[('変更なし', ext), ('全てのファイル', '.*')] src = listbox.get(selected[0])
) ext = os.path.splitext(src)[1]
if dest: dest = filedialog.asksaveasfilename(
pyb = connect() initialfile=src,
pyb.fs_get(src, dest) defaultextension=ext,
disconnect(pyb) filetypes=[('変更なし', ext), ('全てのファイル', '.*')]
# デバイス上のファイル削除(複数可) )
def rmfiles(): if dest:
selected = listbox.curselection() pyb = connect()
if len(selected): pyb.fs_get(src, dest)
pyb = connect() disconnect(pyb)
for i in selected: # デバイス上のファイル削除(複数可)
src = listbox.get(i) def rmfiles():
pyb.fs_rm(src) selected = listbox.curselection()
print('Deleted %s' % src) if len(selected):
ls(pyb) pyb = connect()
disconnect(pyb) for i in selected:
# 何もしない関数 src = listbox.get(i)
def do_nothing(): pyb.fs_rm(src)
pass print('Deleted %s' % src)
ls(pyb)
##### メイン ##### disconnect(pyb)
# 何もしない関数
# メインウィンドウの生成 def do_nothing():
root = TkinterDnD.Tk() pass
root.title('PyBfm')
root.geometry('400x300') ##### メイン #####
pmenu = Menu(root, tearoff=0)
pmenu.add_command(label="実行", command=run) # メインウィンドウの生成
if dev: if dnd:
pmenu.add_command(label="実行 (追跡)", command=lambda:run(True)) root = TkinterDnD.Tk()
pmenu.add_command(label="送る", command=putdlg) else:
pmenu.add_command(label="取得", command=getfile) root = Tk()
pmenu.add_command(label="削除", command=rmfiles) root.title('PyBfm')
pmenu.add_command(label="再読込", command=reload) root.geometry('400x300')
pmenu.add_command(label="閉じる", command=do_nothing) pmenu = Menu(root, tearoff=0)
# root.config(bg='#cccccc') pmenu.add_command(label="実行", command=run)
# Frameウィジェットの生成 if dev:
frame = Frame(root) pmenu.add_command(label="実行 (追跡)", command=lambda:run(True))
# Listboxウィジェットの生成 pmenu.add_command(label="送る", command=putdlg)
listbox = Listbox(frame, selectmode=EXTENDED) pmenu.add_command(label="取得", command=getfile)
listbox.drop_target_register(DND_FILES) pmenu.add_command(label="削除", command=rmfiles)
listbox.dnd_bind('<<Drop>>', listbox_drop) pmenu.add_command(label="再読込", command=reload)
listbox.bind("<KeyPress>", input_key) pmenu.add_command(label="閉じる", command=do_nothing)
listbox.bind("<Double-Button-1>", dbl_click) # root.config(bg='#cccccc')
listbox.bind("<Button-3>", pop_menu) # Frameウィジェットの生成
# スクロールバーの生成 frame = Frame(root)
scroll = Scrollbar(frame, orient=VERTICAL) # Listboxウィジェットの生成
listbox.configure(yscrollcommand=scroll.set) listbox = Listbox(frame, selectmode=EXTENDED)
scroll.config(command=listbox.yview) if dnd:
# ウィジェットの配置 listbox.drop_target_register(DND_FILES)
frame.pack(expand=True,fill=BOTH) listbox.dnd_bind('<<Drop>>', listbox_drop)
listbox.pack(expand=True,fill=BOTH, side=LEFT) listbox.bind("<KeyPress>", input_key)
scroll.pack(side=RIGHT, fill=Y) listbox.bind("<Double-Button-1>", dbl_click)
listbox.bind("<Button-3>", pop_menu)
try: # スクロールバーの生成
find_device() scroll = Scrollbar(frame, orient=VERTICAL)
except Exception as err: listbox.configure(yscrollcommand=scroll.set)
pass scroll.config(command=listbox.yview)
else: # ウィジェットの配置
listfiles() frame.pack(expand=True,fill=BOTH)
listbox.pack(expand=True,fill=BOTH, side=LEFT)
scroll.pack(side=RIGHT, fill=Y)
try:
find_device()
except Exception as err:
pass
else:
listfiles()
root.mainloop() root.mainloop()