PythonでGUIしましょ
最近は、めっきりGUIプログラミングをすることがなくなりました。
Borland製品でゴリゴリ書いたり、MFCであぁだこぉだしたりしたのも、今は昔。
GUIっていったって、まぁHTMLとか書いてれば済むようなプログラムばっかり書いてたので、スタンドアローンのGUIとかひさしぶり。
そんなんC#で書けば?ってまぁそうなんだけど。
ただ、退屈な仕事はPythonにやらせてるってのもあり、いろんなクラスライブラリをつくちゃった関係で、PythonでGUIしたくなったわけですね。
つくるもの
今回はですね、PICで作成したガジェットのデータをCOM経由(USBのやつ)でデータを受け取るってやつです。
実際には、電圧を測って、それを受け取ります。
正確には、0.05秒刻みで電圧の変化をグラフにしたくて、、という、DIY的にはレアな要求要件ですね。
まぁここでは、PythonのGUIの話なので、そこらへんの細かいことは省略です。
何を使う?
ためしにChatGPTに聞いて見ましょう。
出てきたのは次の5つ。細かいことは省略。
①Tkinter ②PyQt/PySide ③Kivy ④wxPython ⑤PyGTK
で、、簡単で、追加のInstallのいらない、Tkinterを使ってみることにします。
ためす
本を買いました。
本を買うことの良し悪しはいろいろありますが、まぁとにかく買いました。
では、やってみます。
import tkinter as TKTK
hira = TKTK.Tk()
hira.title("Hello ! Hiraide ! ")
hira.geometry("250x200+800+400")
hira.mainloop()
おーー!
確かに簡単だ!
地味に、簡単に座標を指定できるとこがよいね。
10コ動かしてタイルみたいにするのが、簡単にできるってことだもんね。
もちろん、こんなことしてもダメだよ。
import tkinter as TKTK
hira = TKTK.Tk()
hira.title("Hello ! Hiraide ! ")
hira.geometry("250x200+400+400")
hira.mainloop()
hira2 = TKTK.Tk()
hira2.title("Hello ! Hiraide ! ")
hira2.geometry("250x200+800+400")
hira2.mainloop()
hira.mainloop() でブロッキングしちゃいますからね。
そう、そーゆーときはThread
import threading
import tkinter as TKTK
def execA():
hira = TKTK.Tk()
hira.title("Hello ! Hiraide ! ")
hira.geometry("250x200+400+400")
hira.mainloop()
def execB():
hira = TKTK.Tk()
hira.title("Hello ! Hiraide ! ")
hira.geometry("250x200+800+400")
hira.mainloop()
#-------------------------------------------------------
if __name__ == '__main__':
Q = threading.Thread(target = execA,)
Q.start()
R = threading.Thread(target = execB,)
R.start()
では、クラス化します
もう、基本C++屋出身ですからね。何は無くてもクラスですね。
クラス名は、、hiraGuiにします。
そう、ここに罠が潜んでいることは、、この時点ではまだ知らなかったのです(o^^o)
。。。
。。。
。。。
。。。
。。。
エラー多発。。➡調べる。
どうやら、
tkinterのメインループをメインスレッド以外で実行するのは不可能
という記事を発見。
じゃぁ、03.pyはなんでちゃんと動作してんねん!
って話にはなるけど、、まぁそこは技術的に突き詰めるより、いろんなパターンをやってみることにする。
そして挫折
そうです。早々と。いろいろやってみて、あれこれしてみて、、
一見マルチスレッドで動作しそうな挙動をすることもあるのだけれど、
結局ダメ。
まぁもともとダメらしいので。
一応、やるだけやって気が済みました。
心機一転、やり直し
ということで、マルチスレッドがダメだとすると、クラスにする意味は無いのかと言うと、、Pythonは、私からすると
便利な謎仕様というのがあって、インスタンスなのか定義なのかよくわからないような使い方が可能なので、ここは、staticで使う前提ながら、そしてシングルトーン前提でありながら、継承して便利に使うには、、的な感じで、クラスを書き始めてみます。
日本語ちょっとおかしいけど。
import threading
import multiprocessing
import tkinter as TKTK
from tkinter import messagebox
#-----------------------------------------
class hiraGui2:
#---------------------------------------
title = "TTTitle"
geometry = "600x200+200+400"
AR = []
#---------------------------------------
def clicked():
messagebox.showinfo("1","2")
#--------------------------
def exec():
hiraGui2.T = TKTK.Tk()
hiraGui2.T.title( hiraGui2.title )
hiraGui2.T.geometry( hiraGui2.geometry )
n = len(hiraGui2.AR)
for w in range(n):
#----------------------------------------
if(hiraGui2.AR[w]["type"] == "BTN"):
btn_1 = TKTK.Button(
hiraGui2.T
,text=hiraGui2.AR[w]["text"]
,command=hiraGui2.AR[w]["com"]
)
btn_1.pack(expand=True)
#----------------------------------------
hiraGui2.T.mainloop()
#--------------------------
def setTitle(v):
hiraGui2.title = v
#--------------------------
def setGeometry(v):
hiraGui2.geometry = v
#--------------------------
#-------------------------------------------------------
if __name__ == '__main__':
class A(hiraGui2):
def clicked():
messagebox.showinfo("111","222")
o = {
"type":"BTN"
,"text":"牡丹だよ"
,"com": A.clicked
}
A.AR.append(o)
o2 = {
"type":"BTN"
,"text":"牡丹222だよ"
,"com": hiraGui2.clicked
}
A.AR.append(o2)
A.exec()
まぁ座標の指定とかはあとからつければよい話なので。
では、どういうのを作りたいか考えながら、やってきます。
ラベル表示と、それを外から変更
ということで、ラベルに文字を表示したあと、別スレッドから、その文字を変更してみます。
メインのスレッドでTkinterを動作させれば、、別に、マルチスレッドでもOKなので。
では、、やってみよう!
import time
import threading
import multiprocessing
import tkinter as TKTK
from tkinter import messagebox
#-----------------------------------------
class hiraGui2:
#---------------------------------------
title = "TTTitle"
geometry = "600x200+200+400"
AR = []
TEXTAR = []
#---------------------------------------
def clicked():
messagebox.showinfo("1","2")
#--------------------------
def exec():
hiraGui2.T = TKTK.Tk()
hiraGui2.T.title( hiraGui2.title )
hiraGui2.T.geometry( hiraGui2.geometry )
n = len(hiraGui2.AR)
for w in range(n):
#----------------------------------------
if(hiraGui2.AR[w]["type"] == "BTN"):
btn_1 = TKTK.Button(
hiraGui2.T
,text=hiraGui2.AR[w]["text"]
,command=hiraGui2.AR[w]["com"]
)
btn_1.pack(expand=True)
#----------------------------------------
elif(hiraGui2.AR[w]["type"] == "LBL"):
lbl_1 = TKTK.Label(
hiraGui2.T
,text=hiraGui2.AR[w]["text"]
)
lbl_1.pack(expand=True)
hiraGui2.TEXTAR.append(lbl_1)
#----------------------------------------
hiraGui2.T.mainloop()
#--------------------------
def setTitle(v):
hiraGui2.title = v
#--------------------------
def setGeometry(v):
hiraGui2.geometry = v
#--------------------------
#-------------------------------------------------------
def execA(o):
print("execA",o)
time.sleep(1)
o.TEXTAR[0]["text"] = "いきなりかよ!"
#-------------------------------------------------------
if __name__ == '__main__':
#-----------------------------------------
class A(hiraGui2):
def clicked():
messagebox.showinfo("111","222")
#-----------------------------------------
Q = threading.Thread(target = execA,args=(A,))
Q.start()
#-----------------------------------------
o2 = {
"type":"LBL"
,"text":"らべらべらべる"
,"com": hiraGui2.clicked
}
A.AR.append(o2)
o = {
"type":"BTN"
,"text":"牡丹だよ"
,"com": A.clicked
}
A.AR.append(o)
A.exec()