2024年7月18日木曜日

tkinterのoptionmenuを使う

tkinterでGUIを作るとき、選択肢から選ばせるようなときにつかうウィジットで、 tkinter.OptionMenuがあります。wxPythonなら、wx.Choiceを使うところです。 普通に選択肢を用意しておいて、使うならシンプルなのですが、 選択肢をユーザーの操作に応じて変化させたいときがあります。 そのような場合のメモを残しておきます。

tkinterでは、ウィジットと結び付けて、その値を保持したり変更を監視したりできるオブジェクトがあります。文字列ならtkinter.StringVar()というものです。ここでは、それを用いてOptionMenuの値を監視します。trace()メソッドを使って、値が設定されたときにon_selected()が呼び出されるようにそておきます。

選択肢を変更するのが、OptionMenuSetChoices()という名前で作った関数です。選ばれたときの値の設定を通して、on_selected()が呼び出されます。OptionMenuの選択状態と、値を保持するオブジェクトが結びついているため、それを変更するとOptionMenuの表示も変更されます。

動作を試すのに、選択肢を100個増やすボタン、最初に移動するボタン、最後に移動するボタンを配置っしておきました。 Windows11、Python 3.8.3の環境で試しています。

import tkinter as tk

def OptionMenuSetChoices(opmenu, var, choices):
    opmenu['menu'].delete(0, "end")
    for i, choice in enumerate(choices):
        opmenu['menu'].add_command(label=choice, command=tk._setit(var, choice))

class APPFRAME(tk.Frame):
    def __init__(self, master, **kwargs):
        super(APPFRAME, self).__init__(master=master, **kwargs)

        self.var = tk.StringVar(self, "default")
        self.var.trace('w', self.on_selected)

        self.choices = [self.var.get()]
        self.opmenu = tk.OptionMenu(self, self.var, *self.choices)
        self.opmenu.pack()
        OptionMenuSetChoices(self.opmenu, self.var, self.choices)

        btn = tk.Button(self, text='Set Choices', command=self.on_set_choices)
        btn.pack()
        btn_first = tk.Button(self, text='Go First', command=self.on_go_first)
        btn_first.pack()
        btn_last = tk.Button(self, text='Go Last', command=self.on_go_last)
        btn_last.pack()

    def on_selected(self, *args):
        print(self.var.get())

    def on_set_choices(self, *args):
        self.choices = ["choice: %02d" % (i+1) for i in range(100)] 
        OptionMenuSetChoices(self.opmenu, self.var, self.choices)
        self.on_go_first()

    def on_go_first(self):
        self.var.set(self.choices[0])
    
    def on_go_last(self):
        self.var.set(self.choices[-1])

def main():
    root = tk.Tk()
    app = APPFRAME(root)
    app.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

2024年7月15日月曜日

Debian12でplaysound(python)を使う

Debian12をDell mini9に入れ、python3.11が使えるので遊んでいます。 Pythonは、とてもよいプログラミング言語環境だと思いますが、 Linuxの場合は、外部モジュールを入れるのにaptを使ったりする必要があるようで、 いろいろ混乱します。

今回使いたいモジュールは、playsoundです。効果音などmp3を再生したいことがときどきあります。MacBookでlubuntu 20.04も使っていて、そちらで書いたコードをmini9に持ってきて動かそうとしたら、playsoundを使えるようにするまでに手間取りましたのでメモしておきます。

Linuxでpythonのモジュールは、aptを使うなりして、例えば、xxxモジュールなら、

sudo apt install python3-xxx
のようにしますが、playsoundは、pipからインストールするようです。

lubuntuのほうでは、pip install playsoundでインストールできました。ただし、このままだとエラーで再生できませんでした。Gstreamerのpythonバインディングが必要とのことで、以下のようにインストールすることで使えるようになりました。

sudo apt install python3-gst-1.0

mini9でのDebian12では、以下のようにして使いました。 まずは、同じようにgstreamerバインディングをインストールします。 さらにpygobjectをインストールするために、 そのビルドに必要なライブラリをインストールします。

sudo apt install libgirepository1.0-dev
sudo apt install libcairo2-dev

pipを使うために、venvで仮想環境を作り、その中でpipを使ってplaysound、pygobjectをインストールしました。pipとvenvを使うのに、そちらもインストールが必要でした。

sudo apt install python3-pip
sudo apt install python3-venv
mkdir test
python3 -m venv myenv
source myenv/bin/activate
pip install playsound
pip install pygobject
これでpython3を使って、playsoundモジュールを利用することができました。

実際動かしたいコードは、tkinterも使っていましたので、

sudo apt install python3-tk
も行ってtkinterを使えるようにしました。

Dynabook UX/23にDebian 12をインストール

Dell mini9のために32bit(i386)用のDebian12のインストールUSBを作ったのでdynabook UX/23にもインストールしてみた。こちらは古いものですが、キーボードが打ちやすいネットブックです。CPUは、Atom N280なで、32bitのものをいれることになります。メモリは2GBに増設してあってWindows XPで動いていました。

Windows XPのHDDはそのまま残しておいて、Netacの内臓SSD256GB(2.5インチ、SATA、厚さ7mm)のものを購入して交換しました。 バッテリーをはずした後に、本体の裏ブタをトルクスドライバー(T6)で開けて、HDDをスライドさせると簡単に外れました。蓋のほうにスペーサーがついていて、取り付け時は、HDDが外れないようにスライドさせるスペースが埋まるようになっていました。取り外したHDDについている金具を取り外して、新しいSSDに取り付けて、同じように本体に収めました。この金具を取り付けている4本のネジが緩まないように強く締まっていましたので、外すのにネジ山をつぶさないように注意が必要でした。

ふたを閉めてもとにもどしたら、バッテリーをもどして、電源ケーブルをつなぎます。Debian12のインストール用のUSBを本体に差してから、電源ボタンを入れて、F2キーを押しておくと、BIOS画面になりました。電源を入れる前にUSBキーを刺してあるので、それが認識されています。起動先としてUSBを優先に設定して、起動させます。

UX/23は、Dell mini9と違って、wifiをすぐに認識しました。インストール用のネットワーク経路に、どちらかの接続が選べるようです。デスクトップ環境をDell mini9と同じようにLXDEでインストールしました。なにも問題なくインストールは終了し、Debian12が起動しました。

wifiは、connmanというネットワークのマネージャーで設定するようです。 ネットワークの設定は、いろいろあって分かりにくいですね。 Network Manager(nmcli)を使ってもよいとありますが、いろいろ試すのも面倒です。 とりあえず、connman setupを選ぶと、正常にwifiのリストが表示され、問題なく接続はされました。よくわからないのは、ここからで別の場所でwifiを使おうとすると、アクセスポイントには接続されますが、いろいろなWebページは開かないという状況になりました。インストールした場所のwifiでは、正常につながっているようです。どうやら、DHCP経由で、DNSがうまく設定されないようすです。ConnmanによるDNSのマネージメントについていろいろ報告があるみたいですが、とりあえず/etc/resolv.confにGoogle Public DNS(8.8.8.8と8.8.4.4)を追記して、つなげることができました。