統合趣味環境

その都度、気になったことを綴ります。

tkinterで画面サイズがうまく得られない案件

内容:画面サイズが正確に得られない

題名の通り.tkinterwinfo_screenwidth()winfo_screenheight()で,カタログスペックどおりに画面サイズが得られない!

Python標準ライブラリのctypesを使って正確なカタログスペックの値が得られたよ.

Pythonを使って画像の表示位置を調整したい人,例えば画面のど真ん中に画像を出してオープニング画面(スプラッシュ画面)を出したい人などに役立つといいな.

きっかけ Python 3.8 -> Python 3.10にしたとき

同じ症状で悩んでいる人もいるのではないかと思うので,きっかけとなった問題点から順に書いていくことにする(この問題点の方は未だ改善されず).

引き続き,Pythonでレンズ解析ソフトを組んでいます.

やさしいコードを目指し「なるべくPythonにデフォで付いてくるライブラリを使う」という方針で組んでいますが*1,そうすると使えるGUIパッケージはtkinterの一択.

ここでPython3.8のtkinterで不具合があり,表を書くときに使うtreeviewの行の色を変えるときに

(treeview名).tag_configure((tagの名前), foreground=(色), background=(色))

だけだとなぜか動作せず,その前に

def fixed_map(option):
        return [elm for elm in style.map('Treeview', query_opt=option) if elm[:2] != ('!disabled', '!selected')]

style.map('Treeview', foreground=fixed_map('foreground'), background=fixed_map('background'))

というオマジナイを書かねばならない*2.ただしstyleはttk.Style()で得るものとする.例えばstyle=ttk.Style()

これだけだと行の色が変わる.

が,表作成の時に行数を過剰にしてしまった余分な領域は白塗りのままとなるから,不格好なのだ.

これを避けるには事前にstyle.theme_use("alt")とかを用いて(altの他にも"clam"などが動作する),

style.configure("Treeview", background=(色), fieldbackground=(色), foreground=(色))

を入れる.

これだと前のオマジナイとかは必要なく,一括して「行の背景色」,「余白の色」,「行の文字色」が設定できる.はずだった.

実際はそうならず(泣),余白の色だけ変わって残りは元のまま白地に黒字である.前のオマジナイを入れてもダメ.

このとき使っていたPythonのバージョンが3.8だった.「これを最新の3.10にすれば既に改善されているかしら(全然バグの報告が無いから皆さん動いてるみたいだし)」?と思ったのがきっかけである.

アップデートして,パッケージ全部入れ直して,いざ動作させると...

あれ?オープニング画面が真ん中に表示されない!

tkinterで自称:画面サイズが得られる方法と実際,その解決法

全体的にこれが良い解答だと思う(→)*3

冒頭に書いた通り,tkinterwinfo_screenwidth()winfo_screenheight()で画面サイズが得られるはずである.

ただ,高解像度スクリーンではシステム側で解像度を調整しているらしく*4,この関数では調整後のニセの値が帰ってくる.

つまり,システム上どんな解像度で動いているかを知るには十分なのだが,そもそもの画面サイズが必要になる1280×700pxの画像を画面のど真ん中に出したいなどの要求では無理が生じる.

そこでPython標準ライブラリのctypesを用い,

import ctypes
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
[scw, sch] = [user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)]

とすれば変数scwschに正しい値が得られる.

他の疑問

なぜ3.8できちんと動いていたんだ?

また,画像サイズがなぜか前より小さくなった.

どうも調べてみると前のサイズがデカかったらしく,今までは上手に画像の解像度を読み替えて何となく動いていたらしい.