0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

同じGUIツールをPowerShellとPythonで実装してみた

0
Posted at

0. きっかけ

PowerShellで作っていたツールをLinux環境で使いたくなったから。

1. ツールの詳細

RGB値を入力して色を確認できる簡易ツール。
Windows用としてPowerShell+WinForms、
Linux用としてPython+Tkinterで作成。
可能な限り同じ操作感・同じ機能になるよう実装した。

2. 完成画面

PowerShell版

RGBエディタ PowerShell版

Python版

RGBエディタ Python版

3. 影付き文字の実装差異

3-1. PowerShell+WinForms側

Labelを2つズラして重ねることで実装。
影用Labelを親にして、その上に文字用Labelを重ねることで、
比較的シンプルに影付き文字を表現できた。

rgb-editor.ps1(抜粋)
#▼ラベル(影)
$lbs = New-Object System.Windows.Forms.Label
$lbs.Text = $text + ":"
$lbs.Top = $y + 1
$lbs.Left = 1 + 1
$lbs.Width = 23
$lbs.Height = 20
$lbs.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$lbs.ForeColor = [System.Drawing.Color]::Silver
$mainForm.Controls.Add($lbs)

#▼ラベル
$lb = New-Object System.Windows.Forms.Label
$lb.Parent = $lbs
$lb.Text = $lbs.Text
$lb.Top = - 1
$lb.Left = - 1
$lb.Width = $lbs.Width
$lb.Height = $lbs.Height
$lb.TextAlign = [System.Drawing.ContentAlignment]::MiddleRight
$lb.ForeColor = [System.Drawing.Color]::Black
$lb.BackColor = [System.Drawing.Color]::FromARGB(0, 255, 255, 255)
$lbs.Controls.Add($lb)

3-2. Python+Tkinter側

TkinterのLabelは背景色が透過できないため、
Canvasの上に文字列2つをズラして作成した。

rgb-editor.py(抜粋)
# 影作成
text = self.canvas.create_text(
  x + 1, y + 1,
  text = label_text,
  fill = "silver"
)
# 文字作成
text = self.canvas.create_text(
  x, y,
  text = label_text,
  fill = "black"
)

影付き文字そのものはcreate_text()を2回呼び出すだけ。
しかし、描画位置を決定するために、

  • フォント取得
  • metrics取得
  • 文字列幅取得
  • Canvasサイズ計算

といった下準備が必要となり、実際のコード量は大きく増えた。
また、Canvasのサイズ計算にScaleおよびEntryのサイズ情報を利用しているため、
Canvasの生成順序も画面上の配置順とは一致していない。

4. 入力補正の実装差異

4-1. PowerShell+WinForms側

TextChangedイベントで補正処理を実施。

rgb-editor.ps1(抜粋)
#▼ScrollBarとTextBoxの値連携
$sb.Add_ValueChanged({
  $tb.Text = $sb.Value
}.GetNewClosure())

$tb.Add_TextChanged({
  RangeRGB $tb
  $sb.Value = $tb.Text
  ChangeColor # ←補正処理用関数
}.GetNewClosure())

4-2. Python+Tkinter側

StringVar.trace_add()とEntryのPasteイベントで補正処理を実施。

PowerShell版では TextChanged イベントを利用することで、
入力補正と色変更処理をほぼ1か所に集約できた。

一方Tkinter版では、StringVar.trace_add()で入力変更を拾えば良いと思っていたが、
貼り付け操作では期待したように処理できなかったため、
Pasteイベントを追加で処理することにした。

その結果、入力補正に関するコードは複数のイベントハンドラへ分散する形となった。
特に貼り付け処理はWinFormsより実装量が大きく、
選択範囲の置換とカーソル位置補正を自前で行う必要があった。

▼イベント登録

rgb-editor.py(抜粋)
#▼Entry(column=2)
self.textvar = tk.StringVar(value = 127) # 初期値
self.textvar.trace_add("write", self.on_entry_change)
self.entry = tk.Entry(
  self,
  width = 3,
  justify = "center",
  bd = 1,
  highlightthickness = 0,
  textvariable = self.textvar
)
self.on_entry_change()
self.entry.bind("<KeyPress-Up>", self.increment)
self.entry.bind("<KeyPress-Down>", self.decrement)
self.entry.bind("<<Paste>>", self.on_paste)
self.entry.grid(row=0, column=2, sticky="e")

▼呼び出し関数

rgb-editor.py(抜粋)
def on_scale_change(self, value):
  self.textvar.set(value)
  ChangeColor()

def on_entry_change(self, *args):
  self.textvar.set(
    self.RangeRGB(self.entry.get())
  )
  self.scale.set(
    int(self.textvar.get())
  )

def on_paste(self, event):
  # クリップボードから値取得
  try:
    paste_txt = event.widget.clipboard_get()
    txt = event.widget.get()
  except tk.TclError:
    return "break"
  
  # 選択範囲の文字列を削除
  if event.widget.selection_present():
    select_start = min(
      event.widget.index(tk.ANCHOR),
      event.widget.index(tk.INSERT)
    )
    select_end = max(
      event.widget.index(tk.ANCHOR),
      event.widget.index(tk.INSERT)
    )
    event.widget.delete(select_start, select_end)
    pos = select_start
  else:
    pos = event.widget.index(tk.INSERT)
  
  # クリップボードの文字を貼り付け
  event.widget.insert(pos, paste_txt)
  event.widget.icursor(pos + len(paste_txt))
  return "break"

イベントが複数に分散しているのは、 入力経路ごとに発生条件が異なるため。

5. 作ってみた感想

同じツールでも、GUIライブラリや言語が変わると実装方法はかなり異なる。

PowerShell+WinFormsでは比較的素直に実装できる部分でも、
Python+Tkinterでは別のアプローチが必要になる場面があった。
特にTkinterはイベント処理周りの考え方がWinFormsと大きく異なり、
実装中に何度も悩まされた。

ただし最終的には、ほぼ同じ操作感で実現できた。
Tkinterのイベント、まぢパねぇ :tired_face:

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?