【Windows11】出力するスピーカー/ヘッドホンの切り替え

私のPCの場合、音を出力するサウンドのデバイス(スピーカー)はモニタ、USBスピーカー、有線ヘッドホン、Bluetoothヘッドホンとあるのですが、有線のヘッドホンだけは接続しても自動で出力を切り替えてくれなく、手動で出力を変更する必要がありました。

そのスピーカー/ヘッドホンの出力を切り替える方法は以下のように行います。

 

タスクバー右側のスピーカーのアイコンをクリックします。

表示されたウィンドウのボリューム調整のスライダの右側にある > マークをクリックします。

すると、接続されているスピーカー/ヘッドホンの一覧が表示されるので、出力したいデバイスをこの中から選んでクリックすると、音の出力先が変更されます。

他にもタスクバーのスピーカーのアイコンを右クリックしサウンドの設定をクリックすると、より詳細な設定が可能です。

この画面では、出力するスピーカーの切り替えの他にも、入力(マイク)の設定や、スピーカーの左右のバランス変更などが行えます。

左右のバランスを変更するには、スピーカーやヘッドホンの表示の右側に表示されている> の部分をクリックします。

この時表示されたウィンドウの左チャンネル右チャンネルの部分のスライダを調整することで、ステレオの左右バランスを調整します。

【Windows11】OneDriveのフォルダ移動

最近のPCはCドライブがSSDで主にプログラムインストール用。DドライブはHDDでファイル保存用と別れている場合が多いと思いますが、OneDriveはCドライブに作成されているので、これをDドライブへ移動させたい!

という事で、OneDriveフォルダの移動方法です。

基本的に以下の手順で行います。

OneDriveのリンク解除

フォルダの移動

OneDriveフォルダの指定

OneDriveのリンク解除

タスクバー右側の雲マークを右クリックします。

表示されたメニューの設定をクリックします。

表示されたウィンドウのアカウントタブのこのPCのリンク解除をクリックします。

表示されたウィンドウのアカウントのリンク解除をクリックします。

リンクが解除されるまで時間がかかるので、しばらく待ちます。

実際にリンクが解除されると、下のように表示されますが、一旦、ウィンドウを閉じずに放置して、次のOneDriveのフォルダを移動します。

OneDriveフォルダの移動

OneDriveのフォルダはデフォルトで、

   C:\Users\[ユーザー名]\OneDrive

にあるので、OneDriveのフォルダごと、希望の場所へ移動します。

私の場合、以下の場所へ移動しました。

    D:\Cloud\OneDrive

OneDriveフォルダの指定

OneDriveのフォルダを移動後、先ほど放置していたウィンドウからOneDriveの設定を行います。

メールアドレスの部分に自分のMicrosoft365アカウントのメールアドレスを入力し、サインインをクリックします。

次にパスワードを入力し、サインインをクリックします。

すると、元々設定されていたOneDriveのフォルダが左下に表示されているので、場所の変更をクリックします。

次に、今回移動したフォルダの場所(OneDriveのフォルダ)を指定し、フォルダーの選択をクリックします。

OneDriveフォルダは既にこのコンピューターに存在します

と表示されますが、今回は、フォルダを移動したいので、このフォルダーを使用をクリックします。

これで、設定そのものは完了です。

あとは、画面に従って次へ進めていけはOKです。

【Windows11】回復ドライブ(リカバリーディスク)の作成

以前はパソコンを購入すると、リカバリーディスクが添付されていましたが、最近では、添付されていない事も多いかと思います。

そこで、PCを購入したら、いざという時のために、まずは回復ドライブの作成をお勧めします。

以下はWindows11の時の回復ドライブの作成方法を紹介します。
回復ドライブの作成には、1時間程度かかるので、時間に余裕のある時に行ってください。

USBメモリの準備

まず、回復ドライブの作成には、16GB以上のUSBメモリが必要になるので準備します。
回復ドライブ作成時にUSBメモリがフォーマットされるので、注意してください。

私は、この↓USBメモリを購入しました。

 

ちなみに、このUSBを選んだのは、余白に文字を書けたので。

回復ドライブの作成

準備したUSBメモリは、USBポートに刺しておきます。

スタートボタンをクリックし、右上のすべてのアプリをクリックします。

次にWindowsツールをクリックします。

Windowツール画面右側の下の方に回復ドライブのアイコンがあるので、これをダブルクリックします。

すると

このアプリがデバイスに変更を加えることを許可しますか?

と表示されるので、はいをクリックします。

次に、システムファイルを回復ドライブにバックアップしますのチェックが入ったまま、次へをクリックすると、お待ちくださいのウィンドウが表示されますが、1分少々待ちます

すると刺したUSBメモリが表示されるので、このドライブが正しいか?確認します。
USBメモリはフォーマットされるので、注意してください。
表示されているドライブが正しければ次へをクリックします。

USBメモリがフォーマットされるため、確認画面が表示されますが、問題なければ作成をクリックします。

ここから、回復ドライブの作成に1時間程度かかるので、ひたすら待ちます。

作成が完了すると、下のようなウィンドウが表示されるので、完了をクリックし、これで終了です。

最終的に作成されたUSBメモリのプロパティを確認すると、8.22GB使用していました。

確かに16GBのメモリがあれば十分なようですが、回復ドライブは、年に1回、作成する事が推奨とのことで、サイズも増えそうだし、32GBのメモリを買いましたが、まぁ、いっか。。

【Windows11】初期インストール済みアプリ一覧

最近、WindowsPCを新規購入しました!

何もインストールをしていない真っさらな状態は、あまり無いので、Windows10からWindows11へアップデートしたとき、インストールされているアプリの一覧をまとめました。

PCの環境によっても異なると思いますので、個人的メモです。。

 

アプリの一覧は、スタートボタンの右ボタン→アプリ→アプリと機能より確認しました。

  • 3Dビューア
  • AV1 Video Extension
  • Cortana
  • Disney+
  • Groove ミュージック
  • Intel(R) Optane(TM) Memory and Storage
  • Microsoft Edge
  • Microsoft Edge WebView2 Runtime
  • Microsoft OneDrive
  • Microsoft Solitaire Collection
  • Microsoft Store
  • Microsoft Teams
  • Microsoft To Do
  • Microsoft Visual C++ 2015-2019 Redistributable(x64) – 14.22.27821
  • Microsoft Visual C++ 2015-2019 Redistributable(x86) – 14.22.27821
  • Microsoft Whiteboard
  • Microsoft ニュース
  • Microsoft フォト
  • Mixed Reality ポータル
  • MPEG-2 ビデオ拡張機能
  • Norton Security
  • NVIDIA FrameView SDK 1.1.4923.29968894
  • NVIDIA GeForce Exprience 3.23.0.74
  • NVIDIA HD オーディオ ドライバー 1.3.38.60
  • NVIDIA PhysX システム ソフトウェア 9.19.0218
  • NVIDIA グラフィックスドライバー 471.41
  • Office
  • OneNote
  • People
  • Power Automate
  • PowerDVD for THIRDWAVE
  • Realtek Audio Console
  • Realtek Audio Driver
  • Skype
  • Snipping Tool
  • Spotify
  • Stream
  • Windows Terminal
  • Windows セキュリティー
  • Xbox
  • Xbox Game Bar
  • Xbox Live
  • アラーム&クロック
  • インテル(R) マネジメント・エンジン・コンポーネント
  • カメラ
  • ゲームサービス
  • スマホ同期アプリ
  • ヒント
  • フィードバック Hub
  • ペイント
  • ペイント 3D
  • ボイスレコーダー
  • マップ
  • メール/カレンダー
  • メッセージング
  • メモ帳
  • 映画&テレビ
  • 天気
  • 電卓
  • 日本語 ローカル エクスペリエンス パック
  • 付箋
  • 問い合わせ

個人的に気になったのは、C++ Redistributableが 2015-2019 は入っている部分。

逆に言うと、それ以外はインストールしないといけない。

【Windows11】動作可能な.NET Frameworkのバージョン

何もインストールしていないWindows11のPCで.NET Frameworkで作成したプログラムは動作するのか?を調べてみました。

※実際にはWindows10から何もインストールせずにWindows11へアップデートしたPC環境で評価しました。

 

結論からすると、exeが.NET Framework4以降であれば、Windows11で動作します。
.NET Framework4未満であれば、別途、.NET Frameworkをインストールする必要があります。

.NET Framewok4以上のexeから参照している.NET FrameworkのDLLが、.NET Framework4未満でも動作します。

評価方法

Visual StudioでC#のWindows Formsのプログラムを作成し、対象のフレームワークを変えながらビルドし、Windows11のPCで動作確認を行いました。

結果

評価.NET Frameworバージョン 結果
2.0 ×
3.0 ×
3.5 ×
4
4.5
4.5.1
4.5.2
4.6
4.6.1
4.7.2
4.8

 

.NET Framework4未満のプログラムを実行すると、下のウィンドウが表示されるので、

この機能をダウンロードしてインストールする

をクリックし、.NET Frameworkをインストールしてください。

【Python/tkinter】図形の編集(削除、移動、変形など)

線や円などの図形の描画のページでは、tkinterでCanvas上に図形を描画しましたが、描画後に図形の移動や移動や変形、削除などを行う事ができ、その方法を紹介します。

ちょうどWordやExcelのように図形を選択し、移動や変形、削除、表示する順番の変更(最前面へ移動、最背面へ移動)などを行う操作と似ているので、これをイメージしてください。

実際にtkinterで、どのように図形を編集するのか?を紹介します。

tagとid

図形を編集するために、それぞれの図形を識別する必要があり、識別のためにid もしくは tag を用います。

id は create_line のように create_ から始まるメソッドを実行するたびに、1から始まるシリアル番号が返されます。

tag は図形を識別するために、create_ から始まるメソッドの tag オプションに任意文字列を指定します。
この文字列は重複していてもよく、複数の図形に同じtagの名前を指定すると、WordやExcelでいうところのグループ化のような事ができます。

(サンプル)

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

root.mainloop()

(実行結果)

このプログラムを実行すると、id1=1, id2=2 となります。

 

以降は、このサンプルをベースに説明します。
また、tag もしくは idを tagOrId と表現します。

図形の削除(delete)

図形を削除します。

.delete(tagOrId)

.delete(“all”) とすると、Canvas上のすべての図形を削除します。
.delete(id1, “rect”)のように複数のtagOrIdを指定することもできます。

(例)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

# 線の削除(id指定)
canvas.delete(id1)
# 線の削除(tag指定)
#canvas.delete("line")

 

 

 

 

 

図形の相対移動(move)

現在の位置からのX方向、Y方向の移動量を指定して、図形を移動します。(相対移動)

.move(tagOrId, x, y)
tagOrId 移動する図形のid もしくは tag
x X方向(右方向が正)に移動する量
y Y方向(下方向が正)に移動する量

(例)

# 線の描画
id1 = canvas.create_line(20, 10, 280, 190, fill = "Red", width = 5, tag="line")
# 矩形の描画
id2 = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")

# 矩形の移動(相対座標指定指定)
canvas.move(id2, 50, -30)

 

 

 

 

 

図形の拡大縮小(sacle)

点(xOffset, yOffset)を基点とした拡大縮小

.scale(tagOrId, xOffset, yOffset, xScale, yScale)
tagOrId 拡大縮小する図形のid もしくは tag
xOffset 基点となる点のx座標
yOffset 基点となる点のy座標
xScale
X方向(幅方向)の倍率
yScale Y方向(高さ方向)の倍率

(例1)矩形の左上の座標を基点として拡大縮小

# 矩形の描画
id = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")
canvas.create_rectangle(100,50,200,150) # 移動前の位置

# (xOffset, yOffset)を基点とした拡大縮小
canvas.scale(id, 100, 50, 1.5, 0.5) # 矩形の左上の座標を基点に拡大縮小

 

 

 

 

 

(例2)矩形の中心を基点として拡大縮小

# 矩形の描画
id = canvas.create_rectangle(100,50,200,150, fill="Yellow",width = 3, tag="rect")
canvas.create_rectangle(100,50,200,150) # 移動前の位置

# (xOffset, yOffset)を基点とした拡大縮小
canvas.scale(id, 150, 100, 1.5, 0.5) # 矩形の中心を基点に拡大縮小

 

 

 

 

 

図形を構成している座標を指定して変形(coords)

図形を作成した時の座標を書き換えます。

引数にtagOrIdのみを指定すると、図形を構成している座標を[x0, y0, x1, y1, …, xn, yn]のリストで取得します。

.coords(tagOrId, x0, y0, x1, y1, ..., xn, yn)

(例1)図形を構成している座標を指定して変形

# 線の描画
id = canvas.create_line(20, 10, 150, 190, 280, 50, fill = "Red", width = 5, tag="line")
canvas.create_line(20, 10, 150, 190, 280, 50) # 移動前の位置
# 図形を構成している座標を指定して変形
canvas.coords(id, 20, 50, 150, 120, 280, 100)

 

 

 

 

 

(例2)図形を構成している座標を取得し、部分的に座標を変更する

# 線の描画
id = canvas.create_line(20, 10, 150, 190, 280, 50, fill = "Red", width = 5, tag="line")
canvas.create_line(20, 10, 150, 190, 280, 50) # 移動前の位置
# 図形を構成している座標の取得
points = canvas.coords(id)
print(points) # [20.0, 10.0, 150.0, 190.0, 280.0, 50.0]
# 部分的に座標を修正
points[2:4]=[200, 80]
# 図形の変形
points = canvas.coords(id, points)

 

 

 

 

 

前面へ移動(lift)

図形の重なり具合を調整します。

tagOrIdで指定した図形をaboveThisの上へ移動します。

.lift(tagOrId, aboveThis)
tagOrId 重なりを調整する図形のid もしくは tag
aboveThis 移動先の図形のid もしくは tag
指定しない場合、最前面へ移動します。

(例)

# 矩形の描画
id1 = canvas.create_rectangle(20,20,120,120, fill="Red",width = 3)
# 線の描画
id2 = canvas.create_line(5,95,220,95, fill="Green",width = 10)
# 矩形の描画
id3 = canvas.create_rectangle(70,70,170,170, fill="Blue",width = 3)

# 矩形(id3)を矩形(id1)の上へ移動
canvas.lift(id3, id1)

 

 

 

 

 

背面へ移動(lower)

図形の重なり具合を調整します。

tagOrIdで指定した図形をbelowThisの下へ移動します。

.lower(tagOrId, belowThis)
tagOrId 重なりを調整する図形のid もしくは tag
belowThis 移動先の図形のid もしくは tag
指定しない場合、最背面へ移動します。

(例)

# 矩形の描画
id1 = canvas.create_rectangle(20,20,120,120, fill="Red",width = 3)
# 線の描画
id2 = canvas.create_line(5,95,220,95, fill="Green",width = 10)
# 矩形の描画
id3 = canvas.create_rectangle(70,70,170,170, fill="Blue",width = 3)

# 矩形(id3)を最背面移動
canvas.lower(id3)

 

 

 

 

 

参考

https://tkdocs.com/shipman/canvas-methods.html

【Python/tkinter】Canvas(キャンバス)の作成

【Python/tkinter】線や円などの図形の描画

【Python/tkinter】線や円などの図形の描画

前回は、Pillowで線や円などの図形の描画について説明しましたが、今回はtkinterでCanvasウィジェットの上に図形を描画する方法についてです。

前半では、線や矩形、楕円などのメソッドについて説明し、後半にこれらメソッドを用いて下図のような図形を描画するサンプルを示しています。

Pillowとtkinterで大きく異なるのは、Pillowでは画像の上に線などの図形を描画すると、図形データが画像データに反映されましたが、tkinterではCanvasウィジェットの上に図形を配置するイメージとなります。

ちょうどWordやExcelで図形を描画する事に似ています。

Wordの画面

 

Word/Excelでは図形の編集で、図形の移動や選択、削除、配置の順番の最前面へ移動/最背面へ移動などができますが、tkinterでも同様のことが出来ます。

tkinterでの図形の編集方法については図形の編集で説明しています。

ここでは、図形や画像を動画のように繰り返し描画すると、図形のオブジェクトが増え、描画速度が遅くなるため、図形を削除する必要がある事を覚えておいてください。
図形の削除方法は最後の部分に書きました。

簡単なサンプル

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

# 線の描画
canvas.create_line(20, 10, 280, 190, fill = "Blue", width = 5)

root.mainloop()

図形の種類

図形はCanvasクラスにcreate_で始まる名前のメソッドが用意されています。

メソッド名 図形の種類
create_arc 円弧
create_bitmap ビットマップ
create_image イメージ
create_line 直線、折れ線
create_oval 楕円、円
create_polygon ポリゴン(閉じた多角形)
create_rectangle 矩形
create_text 文字
create_window ウィンドウ(ウィジェットの配置)

● 直線、折れ線

id = Canvas.create_line(x0, y0, x1, y1, ..., xn, yn, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
arrow 線の矢印の設定をします。
arrow=tk.FIRST のとき、始点に矢印を追加
arrow=tk.LAST のとき、終点に矢印を追加
arrow=tk.BOTH のとき、両方に矢印を追加
arrowshape 矢印の形状を(d1, d2, d3)のタプルで指定します。
初期値:arrowshape=(8, 10, 3)
capstyle 線の端の形状を設定します。
初期値:capstyle=tk.BUTT
(参考)https://tkdocs.com/shipman/cap-join-styles.html
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 線色を指定します。
joinstyle 折れ線のつなぎ目のスタイルを設定します。
(参考)https://tkdocs.com/shipman/cap-join-styles.html
offset 線のパターン(stipple)のパターンの開始位置を指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 線の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 線の識別用番号

● 矩形(四角形)

id = Canvas.create_rectangle(x0, y0, x1, y1, option, ...)
x0,y0… 左上の座標(x0, y0)と右下の座標(x1, y1)を指定します。
描画される矩形は、(x0, y0)の座標を含み、(x1, y1)より1画素内側に描画されます。
activedash マウスポインタが図形上にあるときの輪郭線の破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが図形上にあるときの塗りつぶしの色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが図形上にあるときの輪郭線の色を設定します。
activeoutlinestipple マウスポインタが図形上にあるときの輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
activewidth マウスポインタが図形上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledoutline
線が無効状態(state=tk.DISABLED)のときの輪郭線の色を設定します。
disabledoutlinestipple 線が無効状態(state=tk.DISABLED)のときの 輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledstipple 線が無効状態(state=tk.DISABLED)のときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 塗りつぶしの色を指定します。
offset 塗りつぶしのパターン(stipple)のパターンの開始位置を指定します。
outline
輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 矩形の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 矩形の識別用番号

● 文字

id = Canvas.create_text(x, y, option, ...)
x, y 文字を表示する位置の座標(x, y)を指定します。
座標の位置(文字の左上や中央など)はanchorオプションに依存します。
activestipple マウスポインタが文字上にあるときの塗りつぶしのパターンを設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
disabledfill 文字が無効状態(state=tk.DISABLED)のときの文字色を設定します。
disabledstipple 線文字無効状態(state=tk.DISABLED)のときの文字のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
fill 文字色を指定します。
font 文字のフォントを指定します。
justify
文字列を複数行のまたぐときの、左寄せ(tk.LEFT)、中央寄せ(tk.CENTER)、右寄せ(tk.RIGHT)を設定します。
offset 線のパターン(stipple)のパターンの開始位置を指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags 文字の識別用任意文字列もしくは、文字列のタプルを指定します。
text 描画する文字列を指定します。(日本語可)
width 文字列を描画する領域の幅を指定します。
描画する文字(text)が幅(width)より大きい場合、文字列は押し返し表示されます。
戻り値 id, 線の識別用番号

●楕円、円

id = C.create_oval(x0, y0, x1, y1, option, ...)
x0,y0,x1,y1 左上の座標(x0, y0)と右下の座標(x1, y1)を指定します。
描画される矩形は、(x0, y0)の座標を含み、(x1, y1)より1画素内側に描画されます。
activedash マウスポインタが図形上にあるときの輪郭線の破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが図形上にあるときの塗りつぶしの色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが図形上にあるときの輪郭線の色を設定します。
activeoutlinestipple マウスポインタが図形上にあるときの輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
activewidth マウスポインタが図形上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledoutline
線が無効状態(state=tk.DISABLED)のときの輪郭線の色を設定します。
disabledoutlinestipple 線が無効状態(state=tk.DISABLED)のときの 輪郭線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledstipple 線が無効状態(state=tk.DISABLED)のときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 領域を塗りつぶす色を指定します。
offset 塗りつぶしのパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
outlinestipple 輪郭線のパターンを指定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags 楕円の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 楕円の識別用番号

●ビットマップ

ビットマップの描画を行います。
ここでいうビットマップは二値化された画像で、一般的な画像の描画はcreate_imageを用います。
(参考)https://tkdocs.com/shipman/bitmaps.html

id = C.create_bitmap(x, y, *options ...)
x, y ビットマップを表示する位置の座標(x, y)を指定します。
座標の位置(ビットマップの左上や中央など)はanchorオプションに依存します。。
activebackground マウスポインタがビットマップ上にあるときの背景色を設定します。
activebitmap マウスポインタがビットマップ上にあるときのビットマップを設定します。
activeforeground マウスポインタがビットマップ上にあるときのビットマップの色を設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER 
background ビットマップの背景色を指定します。
bitmap 表示するビットマップを指定します。
disabledbackground 無効状態(state=tk.DISABLED)のときの背景色を設定します。
disabledbitmap 無効状態(state=tk.DISABLED)のときのビットマップを設定します。
disabledforeground 線が無効状態(state=tk.DISABLED)のときのビットマップの色を設定します。
foreground ビットマップの色を指定します。
state ビットマップの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags ビットマップの識別用任意文字列もしくは、文字列のタプルを指定します。
戻り値 id, ビットマップの識別用番号

●イメージ

イメージ(Pillow(PIL)のPhotoImage もしくは tkinterのBitmapImage,PhotoImage)の描画を行います。

id = C.create_image(x, y, *options ...)
x, y ビットマップを表示する位置の座標(x, y)を指定します。
座標の位置(ビットマップの左上や中央など)はanchorオプションに依存します。
activeimage マウスポインタが画像上にあるときのイメージを設定します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
disabledimage 無効状態(state=tk.DISABLED)のときのイメージを設定します。
image イメージを指定します。
通常はPillow(PIL)のPhotoImageを指定します。
state ビットマップの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags イメージの識別用任意文字列もしくは、文字列のタプルを指定します。
戻り値 id, イメージの識別用番号

● ポリゴン

id = Canvas.create_polygon(x0, y0, x1, y1, ..., xn, yn, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが線上にあるときの輪郭線の色を設定します。
activelinestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
fill 塗りつぶす色を指定します。
joinstyle 折れ線のつなぎ目のスタイルを設定します。
tk.ROUND, tk.BEVEL, tk.MITER
(参考)https://tkdocs.com/shipman/cap-join-styles.html
offset 線のパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
smooth smooth=True のとき、折れ線はスプライン曲線となります。
splinesteps スプライン曲線のセグメント数を設定します。
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
tags ポリゴンの識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, ポリゴンの識別用番号

● 円弧

id = Canvas.create_arc(x0, y0, x1, y1, option, ...)
x0,y0… 線の始点と終点、もしくは折れ線を構成する交点の座標を指定します。
activedash マウスポインタが線上にあるときの破線のスタイルを設定します。
(例)activedash=(5,3) 
activefill マウスポインタが線上にあるときの線色を設定します。
(例)activefill=”Red”
activeoutline
マウスポインタが線上にあるときの輪郭線の色を設定します。
activelinestipple マウスポインタが線上にあるときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
activestipple マウスポインタが図形上にあるときの塗りつぶしのパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(例)activestipple= ‘gray50’  のとき(参考)https://tkdocs.com/shipman/bitmaps.html
activewidth マウスポインタが線上にあるときの線幅を設定します。
dash 輪郭線の破線スタイルを(線の長さ, 間隔)のタプルで設定します。
(例)dash=(5,3)
dashoffset 破線の開始位置を設定します。
disableddash 線が無効状態(state=tk.DISABLED)のときの破線のスタイルを設定します。
disabledfill 線が無効状態(state=tk.DISABLED)のときの線色を設定します。
disabledstipple 線が無効状態(state=tk.DISABLED)のときの線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
disabledwidth 線が無効状態(state=tk.DISABLED)のときの線幅を設定します。
extent 開始角度(start)から終了位置までの角度(反時計周りが正)
fill 塗りつぶす色を指定します。
offset 線のパターン(stipple)のパターンの開始位置を指定します。
outline 輪郭線の色を指定します。
outlineoffset 輪郭線のパターン(outlinestipple)のパターンの開始位置を指定します。
outlinestipple 輪郭線のパターンを指定します。
start
円弧の開始位置の角度(度)を指定します。3時方向が0度
state 線の状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
stipple 線のパターンを設定します。
‘gray75’, ‘gray50’, ‘gray25’, ‘gray12’, ‘hourglass’, ‘info’, ‘questhead’, ‘question’, ‘warning’ のいづれか
(参考)https://tkdocs.com/shipman/bitmaps.html
style
円弧のスタイルを指定します。
tk.PIESLICE (初期値) tk.CHORD tk.ARC
tags 円弧の識別用任意文字列もしくは、文字列のタプルを指定します。
width 線幅を指定します。
戻り値 id, 円弧の識別用番号

● ウィンドウ

Canvas上にウィジェットを配置します。

id = Canvas.create_window(x, y, option, ...)
x, y 文字を表示する位置の座標(x, y)を指定します。
座標の位置(文字の左上や中央など)はanchorオプションに依存します。
anchor 表示位置の座標の基準となる位置を指定します。
(初期値)anchor=tk.CENTER
height ウィジェットを配置する幅を設定します。
state ウィンドウの状態を設定します。
(初期値)state=tk.NORMAL
state=tk.HIDDEN のとき、線の非表示
state=tk.DISABLEDのとき、マウスオーバーの処理の無効
tags ウィンドウの識別用任意文字列もしくは、文字列のタプルを指定します。
width
ウィジェットを配置する高さを設定します。
window 配置するウィジェットオブジェクトを設定します。
戻り値 id, ウィンドウの識別用番号

備考

色の指定は”Red”, ”Green”などの色の名前の文字列を使うか、R,G,Bの順で16進数で指定(#FF0000だと赤)するか、(R,G,B)のタプルで指定します。

(参考)

HTML Color Names
W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Py…

楕円や円弧の座標指定位置は、下図のようになります。

サンプル

各種図形のオプション設定を行ったサンプルです。

import tkinter as tk
import os
from PIL import ImageTk

root = tk.Tk()
root.geometry("600x750")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

#######################################
# 線
canvas.create_line(10,   20, 290,  20)                  # オプションなし
canvas.create_line(310,  20, 590,  20, width = 5)       # 線幅5

canvas.create_line(10,   40, 290,  40, arrow=tk.FIRST)  # 始点の矢印
canvas.create_line(310,  40, 590,  40, arrow=tk.LAST)   # 終点の矢印
canvas.create_line(10,   60, 290,  60, arrow=tk.BOTH)   # 両方の矢印
canvas.create_line(310,  60, 590,  60, arrow=tk.BOTH, arrowshape=(24, 25, 8))   # 矢印のサイズ指定

canvas.create_line(10,   80, 290,  80, dash=(5, 3))         # 破線
canvas.create_line(310,  80, 590,  80, dash=(20, 3, 5, 3))  # 破線(1点鎖線)

canvas.create_line(10,  100, 290, 100, width = 15, capstyle=tk.BUTT)        # 終端形状
canvas.create_line(310, 100, 590, 100, width = 15, capstyle=tk.PROJECTING)  
canvas.create_line(10,  120, 290, 120, width = 15, capstyle=tk.ROUND)

canvas.create_line(10,  140, 290, 140, width = 15, stipple='gray12') # 線のパターン
canvas.create_line(310, 140, 590, 140, width = 15, stipple='gray50')

canvas.create_line(10, 160, 150, 180, 300, 160, 450, 180, 590, 160 ) # 折れ線


#######################################
# 矩形
canvas.create_rectangle(10, 200, 290, 220)              # オプションなし
canvas.create_rectangle(310,200, 590, 220, width = 5)   # 線幅5
canvas.create_rectangle(10, 240, 290, 260, fill="Blue") # 塗りつぶしの色指定
canvas.create_rectangle(310,240, 590, 260, fill="Green", outline="Red",width = 2) # 塗りつぶし、輪郭線の色指定

#######################################
# 文字
canvas.create_text(10, 300, text="あいうえお", anchor=tk.NW, font=("",20))   # 基準位置左上
canvas.create_oval(5, 295, 15, 305, fill="Red")

canvas.create_text(300, 300, text="あいうえお", font=("",20))                # 基準位置指定なし(CENTER)
canvas.create_oval(295, 295, 305, 305, fill="Red")

canvas.create_text(590, 300, text="あいうえお", anchor=tk.SE, font=("",20))  # 基準位置右下
canvas.create_oval(585, 295, 595, 305, fill="Red")

canvas.create_text(10, 340, text="あいうえお\nかきくけこ\nさしすせそ", anchor=tk.NW,font=("",20))          # 改行文字
canvas.create_text(310, 340, text="あいうえおかきくけこさしすせそ", anchor=tk.NW, width=120, font=("",20)) # 折り返し幅指定

#######################################
# 楕円
canvas.create_oval(10,450,290, 500)

#######################################
# ビットマップ
canvas.create_bitmap(310,450,bitmap='hourglass')

#######################################
# イメージ
if os.path.exists("Mandrill.png"):
    image = ImageTk.PhotoImage(file = "Mandrill.png")
    canvas.create_image(10,520,image=image, anchor=tk.NW)

#######################################
# ポリゴン
canvas.create_polygon(10,600,150,650,300,600,450,650,550,650)

#######################################
# 円弧
canvas.create_arc(10,670,60, 720)
canvas.create_arc(80,670,130, 720, extent=120)
canvas.create_arc(150,670,200, 720, extent=120, start=30)
canvas.create_arc(220,670,270, 720, extent=120, style=tk.CHORD)
canvas.create_arc(290,670,320, 720, extent=120, style=tk.ARC)

#######################################
# ウィンドウ(Canvas内にウィジェットの配置)
label = tk.Label(root, text = "ラベル", fg = "Red", font = ("", 14, "bold"))
canvas.create_window(300, 740, window=label, width = 300)

root.mainloop()

実行結果

注意点

tkinterのcreate_で始まるメソッドで線や画像などをCanvas上に描画すると、図形が重なっていて見えていなくても、各図形はオブジェクトとして認識しています。
(関数のスコープが外れても、図形のオブジェクトが自動で解放される事はありません。)

そのため、動画のように図形を何回も描画し続けると、オブジェクトの数(描画した図形の数)に比例して描画速度が低下します。

例えば、以下のようなプログラムを実行してみます。

import tkinter as tk
import time

root = tk.Tk()
root.geometry("500x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

colors = ("Red", "Green", "Blue")

for k in range(100):
    start = time.time()
    for i in range(100):
        canvas.create_line(0, i * 2, 500, i * 2, fill = colors[k%3])
    canvas.update()
    # 線100本分の描画時間    
    print((k+1)*100, time.time() - start)

root.mainloop()

実行結果

処理時間

このようにならないように、どこかのタイミングで描画した図形を削除する必要があるのですが、Canvasクラスにdelete()メソッドがあるので、これを用います。

delete()メソッドは、引き数にcreate_XXXXXメソッドで指定したtagの文字列もしくは戻り値のid番号を指定すると、その図形を削除することができます。

また、delete(“all”)と指定することで、すべての図形を削除することも可能です。

そこで、先ほどのプログラムを少し修正して、

import tkinter as tk
import time

root = tk.Tk()
root.geometry("500x200")

# Canvasの作成
canvas = tk.Canvas(root, bg = "white")
# Canvasを配置
canvas.pack(fill = tk.BOTH, expand = True)

colors = ("Red", "Green", "Blue")

for k in range(100):
    start = time.time()

    # 図形の削除
    canvas.delete("lines")
    # canvas.delete("all") # ←今回はこれでも同じ

    for i in range(100):
        canvas.create_line(0, i * 2, 500, i * 2, fill = colors[k%3], tag="lines")
    canvas.update()
    # 線100本分の描画時間  
    print((k+1)*100, time.time() - start)

root.mainloop()

処理時間

参考記事

https://tkdocs.com/shipman/canvas.html

【Python/tkinter】Canvas(キャンバス)の作成

【Python/tkinter】図形の編集(削除、移動、変形など)

【Python/tkinter】Canvasに画像を表示する

【Python/Pillow】線や円などの図形の描画

【Python/Pillow】線や円などの図形の描画

Pythonで線や円などの図形を書く方法としては、OpenCVやtkinterなどを用いても出来ますが、今回はPillowを用いて描画する方法です。tkinterの場合はこちらを参照ください。

Pillowで図形を描画するには、描画先のImageオブジェクトからImageDrawオブジェクトを作成し、このImageDrawオブジェクトに対して線などを描画を行います。

ImageDrawオブジェクトに線などを描画すると、書いたデータはImageオブジェクトに反映されます。

簡単なサンプル

from PIL import Image, ImageDraw

# カラーの画像データ(Imageオブジェクト)の作成
img = Image.new("RGB", (300, 100), "White")
# ImageDrawオブジェクトの作成
draw = ImageDraw.Draw(img)

# 直線の描画
draw.line([(10, 90), (290, 10)], fill = "Blue", width = 10)

# 画像の表示
img.show()

図形の種類

● 直線、折れ線

ImageDraw.line(xy, fill=None, width=0, joint=None)
xy 始点と終点、もしくは折れ線を構成する交点の座標をタプルのリスト[(x, y), (x, y), (x, y),・・・]
もしくは x,y座標のリスト[x, y, x, y, x, y,・・・]で指定します。
fill 線色を指定します。
width 線幅を指定します。
joint 折れ線の場合の、つなぎ目の状態を指定します。

何も指定しない(None)と線の継ぎ目に切れ目ができます。

“curve”を指定すると、丸く繋いでくれます。

● 矩形(四角形)

ImageDraw.rectangle(xy, fill=None, outline=None, width=1)
xy 左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
fill 領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。
width 線幅を指定します。

● 角の丸い矩形

ImageDraw.rounded_rectangle(xy, radius=0, fill=None, outline=None, width=1)
xy 左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
radius 角の半径を指定します。
fill 領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。
width 線幅を指定します。

● 楕円、円

ImageDraw.ellipse(xyfill=Noneoutline=Nonewidth=1)
xy 左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
fill 領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。
width 線幅を指定します。

● ポリゴン(折れ線の始点と終点を結んだ図形)

ImageDraw.polygon(xy, fill=None, outline=None)
xy 折れ線を構成する交点の座標をタプルのリスト[(x, y), (x, y), (x, y),・・・]
もしくは x,y座標のリスト[x, y, x, y, x, y,・・・]で指定します。
fill 閉じた領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。

● 正n角形

ImageDraw.regular_polygon(bounding_circle, n_sides, rotation=0, fill=None, outline=None)
bounding_circle 多角形に外接する円の中心(x, y)および半径r を指定します。
指定方法
(x, y, r) および ((x, y), r)
n_sides  何角形かを指定します。 3以上
rotation  回転角度を度数で指定します。
fill 閉じた領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。

● 円弧

ImageDraw.arc(xy, start, end, fill=None, width=0)
xy 円弧を構成する楕円を囲む矩形の左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
start 円弧の始点の角度(3時方向が0度、時計周りが正)を指定します。
end 円弧の終点の角度(3時方向が0度、時計周りが正)を指定します。
fill 線色を指定します。
width 線幅を指定します。

● 円弧(始点と終点が直線で結ばれた状態)

ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1)
xy 円弧を構成する楕円を囲む矩形の左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
start 円弧の始点の角度(3時方向が0度、時計周りが正)を指定します。
end 円弧の終点の角度(3時方向が0度、時計周りが正)を指定します。
fill 閉じた領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。
width 線幅を指定します。

● 円弧(始点と終点がそれぞれ原点と直線で結ばれた状態)

ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1)
xy 円弧を構成する楕円を囲む矩形の左上と右下の座標をタプルのリスト[(x0, y0), (x1, y1)]
もしくは x,y座標のリスト[x0, y0, x1, y1]で指定します。
start 円弧の始点の角度(3時方向が0度、時計周りが正)を指定します。
end 円弧の終点の角度(3時方向が0度、時計周りが正)を指定します。
fill 閉じた領域を塗りつぶす色を指定します。
outline 輪郭線の色を指定します。
width 線幅を指定します。

● 点

ImageDraw.point(xy, fill=None)
xy 点の座標をタプルのリスト[(x, y), (x, y), (x, y),・・・]
もしくは x,y座標のリスト[x, y, x, y, x, y,・・・]で指定します。
fill 点の色を指定します。

 

備考

色の指定は”Red”, ”Green”などの色の名前の文字列を使うか、R,G,Bの順で16進数で指定(#FF0000だと赤)するか、(R,G,B)のタプルで指定します。

(参考)

https://www.w3schools.com/colors/colors_names.asp

楕円や円弧の座標指定位置は、下図のようになります。

サンプルプログラム

from PIL import Image, ImageDraw
import random # 点のランダム表示用

# カラーの画像データ(Imageオブジェクト)の作成
img = Image.new("RGB", (600, 700), "White")
# ImageDrawオブジェクトの作成
draw = ImageDraw.Draw(img)

# 直線
draw.line([(10, 60), (290, 10)], fill = "Blue", width = 3)

# 折れ線
draw.line([(10, 100), (150, 180), (290, 100)], fill = "Green", width = 20)
draw.line([(10, 200), (150, 280), (290, 200)], fill = "Red", width = 20, joint="curve")

# 四角形
draw.rectangle([(10, 300), (290, 380)], fill = "#FF8C00", outline="#DC143C", width = 5)

# 角の丸い四角形
draw.rounded_rectangle([(10, 400), (290, 480)], radius = 15, fill = (0, 0, 255), outline="Red", width = 5)

# 楕円
draw.ellipse([(10, 500), (290, 580)], fill = "Magenta", outline="Cyan", width = 5)
# 円
draw.ellipse([(110, 600), (190, 680)], fill = "Green", outline="Yellow", width = 5)

# ポリゴン(始点と終点を結んだ多角形)
draw.polygon([(310, 0), (450, 30), (590, 0), (590, 80), (450, 50), (310, 80)], fill = "Red", outline="FireBrick")
draw.polygon([(310, 100), (410, 180), (490, 100), (590, 180)], fill = "blue", outline="red")

# 正n角形
draw.regular_polygon((450, 240, 40), 5, 0, fill = "blue", outline="red")

# 円弧
draw.arc([(310, 300), (590, 380)], 0, 240, fill = "Blue", width = 5)

# 円弧(始点と終点を結ぶ)
draw.chord([(310, 400), (590, 480)], 0, 240, fill = "Blue", outline="Red", width = 5)

# 円弧(始点・終点と原点を結ぶ)
draw.pieslice([(310, 500), (590, 580)], 0, 240, fill = "Blue", outline="Red", width = 5)

# 点
for i in range(1000):
    x = random.randrange(310, 590)
    y = random.randrange(600, 680)
    # 点の描画
    draw.point((x,y), fill = "Blue")

# 画像の保存
img.save("image.png")

# 画像の表示
img.show()

(実行結果)

参照ページ

https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html

https://www.w3schools.com/colors/colors_names.asp

関連記事

【Python/tkinter】線や円などの図形の描画

【Windows11】電卓の新機能

Windows11に標準的に搭載されている電卓のアプリですが、Windows11ではグラフ計算の機能が追加されていました。

Windows10の電卓の機能では、左上の3本線の部分をクリックすると、標準、関数電卓、プログラマー、日付の計算、各種コンバーターの機能がありましたが、ここにグラフ計算が追加されました。

右上の式を入力してくださいの部分に x と y を使った関数を書くと、グラフで表示してくれます。

上図のグラフはシグモイド関数とその微分ですが、以下のように書きました。

y=1/(1+e^(-x))

y=e^(-x)/(1+e^(-x))^2

 

その他にもWindows10にも同じ機能がありますが、個人的に気になった機能を書いておきます。

Windows11の電卓ではこれだけの機能があります。

通貨

その日のレートを取得して、通貨の変換を行います。

日付の計算

開始と終了の日にちを指定し、2つの日にちの差を計算してくれます。

時間

マイクロ秒、ミリ秒、秒、分、時間、日、週、年のそれぞれの時間を変換します。

【Windows11】Google Chromeをデフォルトのブラウザとして設定する

Windows11にアップデートすると、デフォルトのブラウザが勝手にMicrosoft Edgeに変更されてしまい、デフォルトのブラウザをGoogle Chromeへ変更したいと思います。

まず、Google Chromeを起動すると、

Google Chromeはデフォルトのブラウザとして設定されていませんと表示されるので、デフォルトとして設定のボタンをクリックします。

すると、規定のアプリの画面が表示されるので、 Google Chromeをクリックします。

次にファイル形式やリンクなどごとの既定のアプリを設定できる画面が表示されるので、私は

.htm, .html, HTTP, HTTPS

の4つの既定のアプリをGoogle Chromeに設定しました。

設定方法は、各ファイル形式などの右側に表示されているリンク部分をクリックします。

すると、切替の確認画面が表示されるので、強制的に変更するをクリックします。

各ファイル形式やリンクを開く事のできるアプリの一覧が表示されるので、この中からGoogle Chromeを選択して、OKをクリックします。

同様にして、.htm, .html, HTTP, HTTPSの既定アプリをGoogle Chromeに変更します。

 

※HTTPとHTTPSの既定のアプリをGoogle Chromeに設定しないと、Google Chromeの起動時に、Google Chromeはデフォルトのブラウザとして設定されていませんの警告が表示されます。

【Python】ファイル、ディレクトリの存在確認

ファイル、ディレクトリの存在を確認するには、osモジュールの isfile, isdir, existsを用います。

isfile ファイルの存在の確認
isdir ディレクトリの存在の確認
exists ファイル もしくは ディレクトリの存在の確認
(ファイル、ディレクトリの区別なく存在確認します)

 

(サンプル)

カレントディレクトリ直下に \images\Porrots.bmp というファイルがある場合の例です。

import os

# ファイルが存在するか?
exist = os.path.isfile("images/Parrots.bmp")
print("ファイルの存在: ", exist)
exist = os.path.isfile("images")
print("ファイルの存在: ", exist)

# ディレクトリが存在するか?
exist = os.path.isdir("images/Parrots.bmp")
print("ディレクトリの存在: ", exist)
exist = os.path.isdir("images")
print("ディレクトリの存在: ", exist)

# ファイルもしくはディレクトリが存在するか?
exist = os.path.exists("images/Parrots.bmp")
print("ファイルもしくはディレクトリの存在: " , exist)
exist = os.path.exists("images")
print("ファイルもしくはディレクトリの存在: " , exist)

(実行結果)

 

注意点

ファイル名を相対パスで指定した場合、カレントディレクトリが移動しているとファイル存在の結果が意図した結果にならない場合があります。

カレントディレクトリを取得するには、osモジュールのgetcwd()メソッドを用います。

(参考)

【Python/os】カレントディレクトリの取得/設定

【Python】tkinterのGUIにmatplotlibのグラフを表示する

matplotlibを使ってグラフを表示すると、通常は、matplotlib独自のウィンドウで表示されますが、これをtkinterのGUIに組み込んで表示する方法を紹介します。

基本的な処理の流れとしては、matplotlibのFigureクラスでグラフの描画領域を確保し、グラフ描画用の座標軸を作成します。

FigureCanvasTkAggクラスで作成したFigureとFigureの配置先のウィジェットを指定し、matplotlib用のキャンバスを作成します。

グラフを描画する時は、作成した軸に対してグラフを描画し、最後にFigureCanvasTkAggクラスで作成したオブジェクトのdraw()メソッドを呼び出して、グラフを表示します。

 

以下にできるだけシンプルにしたサンプルを示します。

import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title('matplotlib graph')

        #-----------------------------------------------

        # matplotlib配置用フレーム
        frame = tk.Frame(self.master)
        
        # matplotlibの描画領域の作成
        fig = Figure()
        # 座標軸の作成
        self.ax = fig.add_subplot(1, 1, 1)
        # matplotlibの描画領域とウィジェット(Frame)の関連付け
        self.fig_canvas = FigureCanvasTkAgg(fig, frame)
        # matplotlibのツールバーを作成
        self.toolbar = NavigationToolbar2Tk(self.fig_canvas, frame)
        # matplotlibのグラフをフレームに配置
        self.fig_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

        # フレームをウィンドウに配置
        frame.pack()

        # ボタンの作成
        button = tk.Button(self.master, text = "Draw Graph", command = self.button_click)
        # 配置
        button.pack(side = tk.BOTTOM)

        #-----------------------------------------------

    def button_click(self):
        # 表示するデータの作成
        x = np.arange(-np.pi, np.pi, 0.1)
        y = np.sin(x)
        # グラフの描画
        self.ax.plot(x, y)
        # 表示
        self.fig_canvas.draw()

root = tk.Tk()
app = Application(master=root)
app.mainloop()

(実行結果)

 

ポイント

Figureは、今回のやり方とは別に、通常のmatplotlibのウィンドウで表示する場合は、

import matplotlib.pyplot as plt

fig = plt.figure()

のようにする場合もありますが、このようにすると、tkinterで作成したウィンドウの×ボタンでプログラムを終了させても、プロセスが終了しない状態になってしまうので、注意が必要です。

参考

https://matplotlib.org/stable/gallery/user_interfaces/embedding_in_tk_sgskip.html

【Python/tkinter】CanvasにStretchDIBitsで画像を表示する

tkinterでOpenCVなどの画像データ(numpyのndarray)をCanvasに表示する場合、画像がカラーだと、BGRからRGBに変換し、numpy→Pillow→PhotoImageと変換して、ようやくCanvasに画像を表示します。

さらに内部的にはおそらくRGBからBGRに変換している?と思います。

そのためnumpyの画像データをCanvasに表示するのは、かなり遅い。

VB6.0をメインで使っていた時代は遅い処理はWin32APIを使って高速に処理をするのが定番でしたが、Pythonで出来ないのか?調べてみました。

tkinterのCanvasにWin32APIのStretchDIBitsで画像を表示するとき、よく分からなかったポイントは2つ。

●Canvasのウィンドウハンドルをどのように取得するのか?

●numpyの配列(ndarray)のポインタの取得方法は?

これさえクリアできれば、なんとかなります。

Canvasのウィンドウハンドルの取得方法

Canvasに限らす、ウィジェットのウィンドウハンドルを取得するにはwinfo_id()関数を使います。

(例)

# Canvasの作成
canvas = tk.Canvas()
# キャンバスのウィンドウハンドルを取得
hWnd = canvas.winfo_id()

numpy配列のポインタの取得方法

numpy配列(ndarray)のデータのポイントを取得するには、ctypes.data_as()関数でポインタを取得します。

(例)

# 画像データの読み込み
img = cv2.imread("image.bmp", cv2.IMREAD_UNCHANGED)
# 画像データ(numpayのndarrayの配列)からポインタの取得
ptr_img = img.ctypes.data_as(ctypes.POINTER(ctypes.c_byte))

StretchDIBitsでCanvasに画像を表示するサンプル

できるだけシンプルなサンプルを作成しました。

imreadの部分のコメントを切り替えると、カラー/グレースケールの表示が可能になります。

import ctypes
import tkinter as tk

import cv2

# ----------------------------------------------------------------------
# 	構造体などの定義
# ----------------------------------------------------------------------
SRCCOPY		    = 0x00CC0020
DIB_RGB_COLORS  = 0

# StretchBlt() Modes
BLACKONWHITE = 1
WHITEONBLACK = 2
COLORONCOLOR = 3
HALFTONE     = 4

class RECT(ctypes.Structure):
    _fields_ = [
        ('left', ctypes.wintypes.LONG),
        ('top', ctypes.wintypes.LONG),
        ('right', ctypes.wintypes.LONG),
        ('bottom', ctypes.wintypes.LONG)
        ]

class BITMAPINFOHEADER(ctypes.Structure):
    _fields_ = [
        ('biSize', ctypes.wintypes.DWORD),
        ('biWidth', ctypes.wintypes.LONG),
        ('biHeight', ctypes.wintypes.LONG),
        ('biPlanes', ctypes.wintypes.WORD),
        ('biBitCount', ctypes.wintypes.WORD),
        ('biCompression', ctypes.wintypes.DWORD),
        ('biSizeImage', ctypes.wintypes.DWORD),
        ('biXPelsPerMeter', ctypes.wintypes.LONG),
        ('biYPelsPerMeter', ctypes.wintypes.LONG),
        ('biClrUsed', ctypes.wintypes.DWORD),
        ('biClrImportant', ctypes.wintypes.DWORD)
        ]

class RGBQUAD(ctypes.Structure):
    _fields_ = [
        ('rgbBlue', ctypes.wintypes.BYTE),
        ('rgbGreen', ctypes.wintypes.BYTE),
        ('rgbRed', ctypes.wintypes.BYTE),
        ('rgbReserved', ctypes.wintypes.BYTE)
    ]

class BITMAPINFO(ctypes.Structure):
    _fields_ = [
        ('bmiHeader', BITMAPINFOHEADER),
        ('bmiColors', RGBQUAD * 256)
        ]

# ----------------------------------------------------------------------
root = tk.Tk()
root.title("StretchDIBitsで画像の表示")       # ウィンドウタイトル
root.geometry("500x300")     # ウィンドウサイズ(幅x高さ)

# ----------------------------------------------------------------------
# Canvasの作成
canvas = tk.Canvas()
# Canvasを配置
canvas.pack(expand = True, fill = tk.BOTH)

# 画像の読込
#img = cv2.imread("Parrots.bmp", cv2.IMREAD_GRAYSCALE)  # グレースケールとして読み込む
img = cv2.imread("Parrots.bmp", cv2.IMREAD_COLOR)       # カラーとして読み込む
if len(img.shape) >= 3:
    # カラーの場合
    src_height, src_width, src_ch = img.shape
else:
    # グレースケールの場合
    src_height, src_width = img.shape
    src_ch = 1

# 画像データ(numpayのndarrayの配列)のポインタ
ptr_img = img.ctypes.data_as(ctypes.POINTER(ctypes.c_byte))

# ----------------------------------------------------------------------
# ヘッダの作成
bi = BITMAPINFO()
bi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
bi.bmiHeader.biWidth = src_width
bi.bmiHeader.biHeight = -src_height
bi.bmiHeader.biPlanes = 1
bi.bmiHeader.biBitCount = 8 * src_ch

# カラーパレット
for i in range(256):
    bi.bmiColors[i].rgbBlue = i
    bi.bmiColors[i].rgbGreen = i
    bi.bmiColors[i].rgbRed = i
    bi.bmiColors[i].rgbReserved = 255

# ----------------------------------------------------------------------
# キャンバスのウィンドウハンドルを取得
hWnd = canvas.winfo_id()

# キャンバスの領域取得
canvas.update() # 領域を取得するために一旦更新しておく
win_rect = RECT()
ctypes.windll.user32.GetClientRect(hWnd, ctypes.byref(win_rect))

# デバイスコンテキストハンドルの取得
hDC = ctypes.windll.user32.GetDC(hWnd)

# ストレッチモードの設定(BLACKONWHITE, WHITEONBLACK, COLORONCOLOR, HALFTONE)
ctypes.windll.gdi32.SetStretchBltMode(hDC , COLORONCOLOR)

# 描画
ctypes.windll.gdi32.StretchDIBits(
    hDC, 
    win_rect.left, win_rect.top, win_rect.right, win_rect.bottom, # 描画先の領域
    0, 0, src_width, src_height,  # 描画元(画像)の領域
    ptr_img, ctypes.byref(bi), DIB_RGB_COLORS, SRCCOPY)

# 解放
ctypes.windll.user32.ReleaseDC(hWnd, hDC)

# ----------------------------------------------------------------------
root.mainloop()

(実行結果)
カラー画像の場合

グレースケールの場合

まとめ

カメラの画像データはOpenCVに限らず、numpyのndarrayで取得される事が多く、カラー画像の場合はデータの並びがBGRなので、StretchDIBitsを使うと、BGR→RGBの変換など無く、ダイレクトにCanvasに画像を表示することができます。

これで、高速に画像を表示できるようになるはず?!

ただ、最近はベタにWin32APIを使って画像を表示する事も少なくなってきたので、情報が少ないのが難点でしょうか?

【matplotlib】複数グラフの表示

matplotlibで普通に1つのグラフを表示する場合は以下のようにします。

import numpy as np
import matplotlib.pyplot as plt

# 表示するデータの作成
x = np.arange(-np.pi, np.pi, 0.1)
y = np.sin(x)

# グラフの描画
fig = plt.figure() # 省略可
plt.plot(x, y)
plt.show()

(実行結果)

plt.figure()の部分は省略可能ですが、グラフのサイズなどのオプション設定が可能です。

(参考)

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.figure.html#matplotlib.pyplot.figure

 

このグラフに複数のグラフを同時に表示する場合は add_subplot()関数を使って以下のようにします。

import numpy as np
import matplotlib.pyplot as plt

# 表示するデータの作成
x = np.arange(-np.pi, np.pi, 0.1)

y0 = np.cos(x * 0)
y1 = np.cos(x * 1)
y2 = np.cos(x * 2)
y3 = np.cos(x * 3)
y4 = np.cos(x * 4)
y5 = np.cos(x * 5)

# グラフ領域の作成
fig = plt.figure(figsize = [5.8, 4])

# 座標軸の作成
ax1 = fig.add_subplot(2, 3, 1)
ax2 = fig.add_subplot(2, 3, 2)
ax3 = fig.add_subplot(2, 3, 3)
ax4 = fig.add_subplot(2, 3, 4)
ax5 = fig.add_subplot(2, 3, 5)
ax6 = fig.add_subplot(2, 3, 6)

# データのプロット
ax1.plot(x, y0)
ax2.plot(x, y1)
ax3.plot(x, y2)
ax4.plot(x, y3)
ax5.plot(x, y4)
ax6.plot(x, y5)

# グラフの表示
plt.show()

(実行結果)

 

add_subplotの書式は以下の通りです。

add_subplot(何行, 何列, 何番目)

add_subplotではグラフ領域を何行何列で分割するか?を指定し、グラフの表示位置を何番目の位置に表示するか?を指定します。

何番目か?は、下図のように左上からの順番を1始まりの番号で指定します。

(参考)

https://matplotlib.org/stable/api/figure_api.html?highlight=add_subplot#matplotlib.figure.Figure.add_subplot

複数グラフを表示する時の行数、列数は、すべて同じにする必要は無く、混在させる事も可能です。

import numpy as np
import matplotlib.pyplot as plt

# 表示するデータの作成
x = np.arange(-np.pi, np.pi, 0.1)

y1 = np.cos(x * 1)
y2 = np.cos(x * 2)
y3 = np.cos(x * 3)

# グラフ領域の作成
fig = plt.figure(figsize = [5.8, 4])

# 座標軸の作成
ax1 = fig.add_subplot(2, 3, 1) # 2行3列の1番目
ax2 = fig.add_subplot(2, 3, 2) # 2行3列の2番目
ax3 = fig.add_subplot(2, 3, 3) # 2行3列の3番目
ax4 = fig.add_subplot(2, 1, 2) # 2行1列の2番目

# データのプロット
ax1.plot(x, y1)
ax2.plot(x, y2)
ax3.plot(x, y3)
ax4.plot(x, y1+y2+y3)

# グラフの表示
plt.show()

(実行結果)

【Python/tkinter】ツールバーの作成

tkinterにはToolBarのような、ツールバー用のウィジェットは無いのですが、ツールバーをFrameButtonを使って作ります。

フレームにアイコン付きのボタンを左側に配置するだけですが。。

(作成したツールバーのイメージ)

  • ファイルを開く
  • フォルダを開く
  • 保存

の3つのボタンを配置しています。

 

(ソースコード)

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk

class Application(tk.Frame):
    def __init__(self, master = None):
        super().__init__(master)

        self.master.title("ToolBar")    # ウィンドウタイトル
        self.master.geometry("300x200") # ウィンドウサイズ(幅x高さ)

        #---------------------------------------
        #  ツールバー
        #---------------------------------------     
        
        # ツールバー用Frame
        frame_toolbar = tk.Frame(self.master, bg = "gray90")
        
        #-------------------------
        # ボタン
        # ファイルを開く
        self.ico_open_file = ImageTk.PhotoImage(file = "OpenFile_16x.png")
        btn_open_file = tk.Button(frame_toolbar, command = self.open_file_click, image = self.ico_open_file)
        # フォルダを開く
        self.ico_open_folder = ImageTk.PhotoImage(file = "OpenFolder_16x.png")
        btn_open_folder = tk.Button(frame_toolbar, command = self.open_folder_click, image = self.ico_open_folder)
        # 保存
        self.ico_save = ImageTk.PhotoImage(file = "Save_16x.png")
        btn_save = tk.Button(frame_toolbar, command = self.save_click, image = self.ico_save)

        #-------------------------
        # ボタンをフレームに配置
        btn_open_file.pack(side = tk.LEFT, padx = (5, 0)) # 左側だけ隙間を空ける
        btn_open_folder.pack(side = tk.LEFT)
        btn_save.pack(side = tk.LEFT)

        #-------------------------
        # ツールバーをウィンドウに配置
        frame_toolbar.pack(fill=tk.X)
        #---------------------------------------     

    def open_file_click(self):
        '''[ファイルを開く]がクリックされたとき'''
        filename = filedialog.askopenfilename()
        print(filename)

    def open_folder_click(self):
        '''[フォルダを開く]がクリックされたとき'''
        dir_name = filedialog.askdirectory()
        print(dir_name)

    def save_click(self):
        '''[保存]がクリックされたとき'''
        filename = filedialog.asksaveasfilename()
        print(filename)

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

アイコンファイルはマイクロソフトのVisual Studio Image Libraryより入手しました。

https://www.microsoft.com/en-us/download/details.aspx?id=35825

【Python/Pillow(PIL)】画像データの新規作成

画像データ(PIL.Image)を画像ファイルなどからではなく、新規に作成するには、Imageモジュールのnew関数を使います。

new関数の書式は以下の通り

PIL.Image.new(mode, size, color=0)
mode 画像のモードを設定します。
主なものとして、
“L”      8bitグレースケール
“RGB”  3x8bit カラー画像
詳細はこちらを参照ください。
size 画像のサイズを(幅, 高さ)のタプルで指定します。
color 画像全体のデータの色の値を指定します。
初期値は黒となります。
カラーの場合は、(R, G, B)のように各チャンネルごとの値のタプルで指定します。

 

グレースケール画像を作成するには、以下のようにします。

from PIL import Image

# グレースケールの画像データを作成
img = Image.new("L", (320, 240))
# 画像の表示
img.show()

(実行結果)

初期値を指定すると

# 輝度値を指定して画像データを作成
img = Image.new("L", (320, 240), 128)
# 画像の表示
img.show()

(実行結果)

カラー画像の場合は以下のようにします。

# カラー画像データを作成
img = Image.new("RGB", (320, 240), (0, 128, 255))
# 画像の表示
img.show()

(実行結果)