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)を追記して、つなげることができました。

2024年6月23日日曜日

lubuntu 24.04 LTSでwxPython4.2.1

古いPCにLinuxを入れて使えるようにしています。 Lubuntu 24.04 LTSを古いデスクトップPCに入れて使っています。 リモートデスクトップとpythonくらいしか利用しませんので 古いパソコンでも十分な用途です。 pythonは、python3が利用でます。 さて、GUIにwxPythonをよく利用していたのですが、 そのようなスクリプトを動かすときにwxPythonをインストールする必要があります。 Windowsでは、pipを用いてインストールしていますが、 lubuntuでは、aptを使ってインストールするようです。
apt install python3-wxtools
でインストールできました。

さて、これで使えるなら問題よいのですが、しばしば 仮想環境を利用することが増えています。python3では、 すぐにvenvが利用できるようになっています。 たとえば、

mkdir myproject
cd myproject
python3 -m venv myenv
として、myprojectフォルダの中に、 そのプロジェクト用のmyenvという仮想環境を作って利用したりします。 その仮想環境を利用するには、
cd myproject
source myenv/bin/activate
として、仮想環境のフォルダ内にあるactivateスクリプトを用いて利用できるようにします。 アクティベートするといいます。 ここで pip install numpy とすると仮想環境にnumpyがインストールされるわけです。 ある環境がアクティベートされた状態で起動されるpythonでは、 その環境にインストールされたモジュールが利用できるというわけです。 環境を戻すには、deactivateを実行します。

さて、この仮想環境へはpipを用いてモジュールをインストールします。 pip install wxPythonとしてwxPythonををpipでインストールしようとすると、 ビルドエラーが出て停止してしまいました。 こちら https://wxpython.org/blog/2017-08-17-builds-for-linux-with-pip/index.html のサイトを参考にしてインストールをしました。

"What You Need"の箇所にビルドに必要なライブラリが記載されています。 地道にひとつづつインストールしていきます。 私の環境では、

sudo apt install python-dev
sudo apt install libgtk-3-dev
sudo apt install libgstreamer1.0-dev
sudo apt install libgstreamer-plugins-base1.0-dev
sudo apt install libglu1-mesa-dev mesa-common-dev freeglut3-dev
sudo apt list |grep libwebkit2gtk
sudo apt install libwebkit2gtk-4.1-dev
sudo apt install libjpeg-dev
sudo apt install libpng-dev
sudo apt install libtiff-dev
sudo apt install libsdl-dev
sudo apt install libnotify-dev
sudo apt install libsm-dev
としていきました。すでにインストールされているものもいくつかありましたが、
順番に検索エンジンを利用しながら確認していきました。
途中どれをインストールするかlistを見て確認したりもしています。

あとは、"Build Steps"にあることを順番にしていくだけです。もちろん、 ファイル名はダウンロードされたものに合わせて修正します。 書いてある通りにすると無事にwheelファイルがビルドされ、 wxPythonを利用することができるようになりました。

このようにしてpython3.12でwxPython4.2.1が動きました。 ただし、現在ダウンロードされたファイルをコンパイルしたものは、 pythonを起動してimport wxのあとすぐにquit()してもセグメンテーションフォールトを起こします。 "wxpython 4.2.1 segmentation fault"で検索してみるとすでに報告はあるようです。 とりあえずは利用できるので、修正を待ちます。 ちなみに、仮想環境ではなくaptでインストールした環境ではそのようなエラーは起こっていません。

DELL Inspiron Mini9 にDebian 12 bookwormをインストールしてみた

使っていないDell Inspiron Mini9がありました。 もともとWindows XPで使っていたものです。 XPのサポート切れからしばらくたち、 当時のWebブラウザを使っても開けないページも増えてきました。 そのうちLinuxでも入れてみようと置いてあったが、 32bitアーキテクチャがサポート対象から外されて行っている傾向があるので、 Debian12(bookworm)を試してみました。

作業した部屋のネットワーク環境がwifiだけの場所だったので、 ネットワークがすぐに使えるとは考えられないため、 debian-12.5.0-i386-DVD-1.iso をダウンロードしました。 ファイルSHA256SUMS.txtもダウンロードします。 インストール用のUSBは、手元にあった16GBのものを利用しました。 isoのサイズは、およそ3.7GBですので、こんな大きなものは必要なかったでしょう。 USBの作成環境は目の前にあるWindows11のノートパソコンです。

まず、ダウンロードしたisoイメージのハッシュ値を計算して確認します。 コマンドプロンプトを開いて、ダウンロードフォルダへ移動し以下のコマンドでSHA256のハッシュ値を調べます。

certutil -hashfile debian-12.5.0-i386-DVD-1.iso SHA256
出力された文字列とSHA256SUMS.txtの中にあるDVD-1.isoのハッシュ値を比較し 同じものであることを確認します。 正しくダウンロードされていたら、このisoイメージをUSBに書き込み インストール用のUSBを作成します。

USBへのisoイメージの書き込みには、Rufus 4.5(rufus-4.5p.exeポータブル版)を利用しました。 Deviceで、書き込む先のUSBを選んで、ブートの種類の箇所の選択ボタンを押してISOイメージを選択します。 パーティション構成はMBR、ターゲットシステムはBIOSまたはUEFIが選ばれた状態になっています。 書き込むUSBによるのでしょうが、 フォーマットオプションのファイルシステムは、FAT32(規定)クラスターサイズは8192バイト(規定)となっています。 すべてデフォルト状態のままスタートして書き込みを開始しました。 3.7GBのイメージの書き込みなので、時間はかかりましたが、インストール用USBが作成されました。

Mini9にインストール用USBを刺して、起動します。 キー2を押してBIOS設定を開いてUSB優先で起動できるように設定し、再び起動させます。 あとは、グラフィカルインストーラーで指示に従ってインストールしていきます。 私のMini9はUS配列キーボードなのでキーボードの選択で米国を選びました。 途中wifiのところでb43-ucode15.fwといファームウェアが必要だよと言われますが、 ここでは無視して続けていきます。 Mini9は、Etherの口がありますので、あとでネットワークケーブルを使って接続して設定するつもりでいます。 DHCPで接続が試みられますが、現時点でケーブルの接続もしていないので、接続されないまま続けます。 パーティションは推奨設定(初心者用設定)で進めて、 ソフトウェアの選択でデスクトップ環境にGNOMEではなくLXDEを択しました。 トラブルなくインストールが終了し、起動ディスクを抜いて再起動かけると無事に起動させることができました。

ネットワークケーブルが利用できる場所に移動して、ケーブルを接続するとDHCPで問題なく接続されました。 DVDでインストールしたので、リポジトリの設定ができていないので、 /etc/apt/sources.list ファイルを編集しました。 suコマンドでスーパーユーザーになって編集します。 Googleで、"debian bookworm repository"を検索して設定を参考にさせていただきました。

ファイルを編集したのちapt updateし、apt upgradeしてみますと問題はなさそうです。 firefoxがインストールされているので、youtubuに接続してみると動画はカクカクですが音もちゃんと出ています。 add userで、sudoグループにユーザー名を追加し、sudoできるようににしました。

日本語入力は、fcitx-mozcを利用します。 apt install fcitx-mozcをし、 apt remove uim-mozcをしました。

タッチパッドは、タップでクリックができなかったので、 パス/etc/X11/xorgconf.d/に30-touchpad.confというファイルを作成しました。 内容は、以下のとおりです。

Section "InputClass"
Identifier "touchpad"
Driver "libinput"
MatchIsTouchpad "on"
Option "Tapping" "on"
EndSection

wifiでの接続ですが、 https://wiki.debian.org/bcm43xx を参考にして、

deb http://deb.debian.org/debian/ bookworm main contrib non-free
を/etc/apt/source.listに追加し、 sudo apt updateを行った後、
sudo apt install firmware-b43-installer
をします。メニューの設定から高度なネットワーク設定でwifiのアクセスポイントを追加したら 利用できるようになりました。 LibreOffice 7.4が入っているので動かしてみても、問題はなさそうです。 pythonも3.11が利用できています。 SMPlayerでSMTubeを使って、YouTubeを観てみたら滑らかに再生できました。 古くて小さいノートパソコンですが、用途によっては現役として十分利用できそうです。