"""
ベイズ最適化/ガウス過程回帰GUIアプリケーション
概要:
`bayes_gp_plain_shimizu.py` の機能をグラフィカルユーザーインターフェースを通じて提供します。
入力ファイルの指定、ベイズ最適化のパラメータ設定、実行、結果表示を行います。
詳細説明:
本スクリプトは、TkinterをベースとしたGUIアプリケーションフレームワークである`tklib`を利用して構築されています。
ユーザーはGUIを通じてデータファイルの選択、ガウス過程回帰およびベイズ最適化に関連する様々なパラメータ
(例: 2Dグリッドのサイズ、探索回数、乱数基底の数、アクイジション関数の種類など)を設定できます。
設定されたパラメータはバックエンドの計算エンジン `bayes_gp_plain_shimizu` に渡され、解析が実行されます。
解析結果は出力ファイルに保存されます。
関連リンク:
:doc:`bayes_gp_gui_shimizu_usage`
"""
import sys
from sys import exit
import os
import time
import openpyxl
import tkinter
from numpy import exp, log, log10, sin, cos, tan, arcsin, arccos, arctan, sqrt
v = os.environ.get('tklibPath', None)
if v:
tklib_path = v
else:
script_path = sys.argv[0]
tkProgRoot = os.path.join(script_path, '../../..')
tklib_path = os.path.abspath(os.path.join(tkProgRoot, 'tklib/python'))
print(f"Add [{tklib_path}] to PYTHONPATH by sys.path.append()")
sys.path.append(tklib_path)
from tklib.tkutils import getarg, getintarg, getfloatarg, pint, pfloat, terminate, get_os, split_file_path, get_dirname
from tklib.tkinifile import tkIniFile
from tklib.tkparams import tkParams
from tklib.tkgui.tkapplication_gui import tkApplication_GUI
import tklib.tkgui.tktkinter as tktkinter
import bayes_gp_plain_shimizu as c_engine
"""
GUI for bayes_gp_plain.py
"""
usage_str = '''
"(i) usage: python {}".format(sys.argv[0])
'''[1:-1]
#==============================================
# Global bariables
#==============================================
prog_name = 'Bayes/GP GUI'
version = [1, 3, 1]
#=============================
# Treat argments
#=============================
[ドキュメント]
def usage(app):
"""
アプリケーションのコマンドライン使用方法を表示します。
概要:
引数として渡されたアプリケーションインスタンスが持つ使用方法文字列を標準出力に出力します。
詳細説明:
主にコマンドラインからスクリプトが誤った形で呼び出された際に、
正しい使用方法をユーザーに提示するために使用されます。
:param app: アプリケーションインスタンス。usage_str属性を持ちます。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:returns: None
"""
# cparams = app.get_params()
# app.usage(infile = cparams.infile)
for s in app.usage_str.split('\n'):
cmd = 'print({})'.format(s.rstrip())
eval(cmd)
[ドキュメント]
def initialize(app, config):
"""
アプリケーションのグローバル変数と設定を初期化します。
概要:
Tkinter変数、ファイルタイプ、リソースディレクトリ、および設定可能な設定値を初期設定します。
詳細説明:
GUIの起動時に一度だけ呼び出され、アプリケーション全体で使用される基本的なパス、
デフォルトの設定値、GUIウィジェットと連携するための変数を設定します。
configオブジェクトの各種属性にデフォルト値が割り当てられ、
その型が定義されることで、設定ファイルからの読み込み時に自動的な型変換が可能になります。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: 設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:returns: None
"""
#================================
# Global variables
#================================
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
# Non-configurable configuration
app.prm_file_type = [('prm file', '*.prm')]
app.data_file_type = [('data file', '*.csv')]
app.resource_dir = os.path.join(app.script_dir, 'resource')
# Configurable configuration
config = app.config
config.lang = 'en'
config.debug = 0
config.print_level = 0
config.confirm_on_exit = True
config.minsize = [200, 200]
config.geometry = "507x447"
config.left_pane_width = 500
config.message_box_width = 100
config.message_box_height = 4
config.head_label_width = 10
config.entry_width = 30
config.button_width = 12
# Define var types in config for auto type conversion in config.read_parameters()
config.editor_path = ''
config.infile = ''
config.outfile = ''
config.outresfile = ''
config.score_mode = 'EI'
config.program_path = ''
[ドキュメント]
def update_vars(app, cparams):
"""
コマンドライン引数に基づいてパラメータを更新します。
概要:
この関数は現在、実装がコメントアウトされており、コマンドライン引数からのパラメータ更新は行いません。
将来的な拡張のために残されています。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:returns: None
"""
argv = app.argv
# if len(argv) <= 1:
# app.terminate(usage = usage)
# cparams.infile = getarg(1, cparams.infile)
[ドキュメント]
def copy_tkvars(app, cparams, tkvars):
"""
Tkinterウィジェットの変数(tkvars)の値を計算パラメータ(cparams)と設定(config)にコピーします。
概要:
GUI上の入力フィールドや選択ボックスの値(tkinter.StringVarなど)を、
計算エンジンのパラメータオブジェクトとアプリケーションの設定オブジェクトの対応する属性に転送します。
詳細説明:
主に、GUI上でユーザーが設定を変更した後、実際の計算や設定保存のためにその値を内部データ構造に反映させる際に使用されます。
`cparams`と`config`オブジェクトの属性が、`tkvars`辞書に格納されたTkinter変数の現在の値で更新されます。
特に`figsize`はリスト形式に変換されて`cparams`に設定されます。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param tkvars: Tkinterウィジェットの変数を格納する辞書。キーはパラメータ名、値はtkinter.StringVarなどの変数。
:type tkvars: dict
:returns: None
"""
config = app.configparams
# for key in ["script_path", "prmpath", "infile", "outfile", "max_num_probes", "num_search_each", "num_rand_basis", "interval", "score_mode"]:
for key in ["program_path", "infile", "outfile",
"nx_2D", "ny_2D",
"max_num_probes", "num_search_each", "num_rand_basis", "interval", "score_mode", "random_seed", "standardize",
"fontsize", "legend_fontsize"]:
cparams.set_attr(key, tkvars[key].get())
for key in ["program_path", "infile", "outfile", "outresfile","fontsize", "legend_fontsize"]:
config.set_attr(key, tkvars[key].get())
cparams.set_attr('figsize', [tkvars['fig_width'].get(), tkvars['fig_height'].get()])
[ドキュメント]
def copy_config(app, cparams, config):
"""
設定パラメータ(config)の値を計算パラメータ(cparams)にコピーします。
概要:
アプリケーションの全体設定オブジェクトから、計算エンジンで使用されるパラメータオブジェクトへ、
共通のキーを持つ設定値を転送します。
詳細説明:
`config`オブジェクトと`cparams`オブジェクトの両方に存在する属性について、
`cparams`の該当属性を`config`の値で更新します。
これにより、GUIの設定ダイアログ等で変更されたアプリケーション全体の設定が、
計算ロジックにも適用されるようにします。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param cparams: 計算エンジンのパラメータオブジェクト。このオブジェクトが更新されます。
:type cparams: tklib.tkparams.tkParams
:param config: アプリケーション全体の設定パラメータオブジェクト。このオブジェクトから値がコピーされます。
:type config: tklib.tkparams.tkParams
:returns: None
"""
keys0 = config.__dict__.keys()
for key in cparams.__dict__.keys():
if key in keys0:
cparams.set_attr(key, cparams.get(key, None))
[ドキュメント]
def create_graph_tab(app, config, cparams, parent_notebook):
"""
グラフ関連のパラメータ設定タブをノートブックに追加します。
概要:
グラフの幅、高さ、フォントサイズ、凡例フォントサイズを設定するための入力ボックスを含むタブを作成し、
指定された親ノートブックに追加します。
詳細説明:
このタブは、出力されるグラフの視覚的なプロパティをユーザーが調整できるように設計されています。
各パラメータは数値入力ボックスとして提供され、デフォルト値へのリセットやヘルプ表示機能も備えています。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param parent_notebook: タブを追加する親ノートブックウィジェット。
:type parent_notebook: tkinter.ttk.Notebook
:returns: 作成されたタブのフレーム。
:rtype: tktkinter.Frame
"""
config = app.configparams
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
page1_frame = tktkinter.Frame(app, parent_notebook, bg = 'dim gray')
page1_frame.pack()
parent_notebook.add(page1_frame, text = app.p('Graph'))
notebook_frame = page1_frame
# Graph parameter block
graph_grid_frame = tkinter.Frame(page1_frame)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, graph_grid_frame,
varname = "fig_width", vartype = 'int',
defval = [config, 12], from_ = 1, to = 100, increment = 1, box_width = 6,
reset_val = 12,
# help_text = 'Width of graph window. Default: 12',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 4)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, graph_grid_frame,
varname = "fig_height", vartype = 'int',
defval = [config, 8], from_ = 1, to = 100, increment = 1, box_width = 6,
reset_val = 8,
# help_text = 'Hight of graph window. Default: 8',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 5)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, graph_grid_frame,
varname = "fontsize", vartype = 'int',
defval = [config, 16], from_ = 1, to = 100, increment = 1, box_width = 6,
reset_val = 16,
help_text = 'Size of graph font. Default: 16',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 6)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, graph_grid_frame,
varname = "legend_fontsize", vartype = 'int',
defval = [config, 8], from_ = 1, to = 100, increment = 1, box_width = 6,
reset_val = 8,
help_text = 'Size of legend font. Default: 8',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 7)
return notebook_frame
[ドキュメント]
def create_main_tab(app, config, cparams, parent_notebook):
"""
メインの解析設定タブをノートブックに追加します。
概要:
入力・出力ファイルのパス設定、解析実行ボタン、およびベイズ最適化の主要パラメータ設定のための
ウィジェットを含むタブを作成し、指定された親ノートブックに追加します。
詳細説明:
このタブはアプリケーションの中心的な機能を提供します。
ユーザーはデータファイル (`infile`) を選択し、予測結果 (`outfile`) と状態保存ファイル (`outresfile`) のパスを自動生成・設定できます。
「analyze」と「validate」ボタンで解析を実行し、コマンドライン版の「usage」や「citation」も表示できます。
また、2Dグリッドの解像度 (`nx_2D`, `ny_2D`)、プローブ数 (`max_num_probes`), 各探索の数 (`num_search_each`)、
ランダム基底の数 (`num_rand_basis`)、ハイパーパラメータ更新間隔 (`interval`)、
アクイジション関数 (`score_mode`)、乱数シード (`random_seed`)、テストデータの割合 (`fraction_test`)、
およびデータの標準化 (`standardize`) といった、ベイズ最適化の重要なパラメータを設定するためのコントロールを提供します。
下部にはメッセージ表示用のテキストボックスも含まれます。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param parent_notebook: タブを追加する親ノートブックウィジェット。
:type parent_notebook: tkinter.ttk.Notebook
:returns: 作成されたタブのフレーム。
:rtype: tktkinter.Frame
"""
config = app.configparams
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
page1_frame = tktkinter.Frame(app, parent_notebook, bg = 'dim gray')
page1_frame.pack()
parent_notebook.add(page1_frame, text = app.p('Analyze'))
notebook_frame = page1_frame
applications = app.get_external_apps(config.get("editor_path", None))
path_grid_frame = tkinter.Frame(page1_frame)
# Parameter path frame
"""
tktkinter.make_path_frame(app, cparams, page1_frame, path_grid_frame,
tkvars, varname = 'prmpath',
file_type = [("Parameter", "*.prm"), ("All", "*.*")],
working_dir = '.',
is_print = True, igridrow = 0)
"""
# Input path frame
def open_file(input_entry, output_entry, outres_entry, file_type = None, ini_dir = None):
ini = tkIniFile(path = config.inifile)
if ini_dir is None:
ini_dir = ini.get_string(section = "work_dir", key = "last_dir", def_val = '.', is_print = False)
tktkinter.path_button_click(app, input_entry, file_type = file_type, ini_dir = ini_dir)
file_path = input_entry.get()
outfile = app.replace_path(file_path,
template = ["{dirname}", "{filebody}-predict{i}.xlsx"], ext_dict = {'i': '{i}'})
output_entry.set(outfile)
cparams.outfile = outfile
outresfile = app.replace_path(file_path,
template = ["{dirname}", "{filebody}-save{i}.npz"], ext_dict = {'i': '{i}'})
outres_entry.set(outresfile)
cparams.outresfile = outresfile
ini.write_string(section = "work_dir", key = "last_dir", value = dir, is_print = False)
tktkinter.make_path_frame(app, cparams, page1_frame, path_grid_frame,
tkvars, varname = 'infile',
file_type = [("Excel", "*.xlsx"), ("CSV", "*.csv"), ("All", "*.*")],
working_dir = '.',
head_label_width = config.head_label_width,
entry_width = config.entry_width,
button_width = config.head_label_width,
edit_button_width = 0,
shell_button_width = 0,
open_command = lambda app, cparams, file_type, ini_dir: \
open_file(tkvars["infile"], tkvars["outfile"], tkvars["outresfile"], file_type, ini_dir = None),
# post_open_command = lambda: post_open(tkvars["infile"], tkvars["outfile"]),
is_print = True, igridrow = 1)
# Output path frame
tktkinter.make_path_frame(app, cparams, page1_frame, path_grid_frame,
tkvars, varname = 'outfile',
file_type = [("Excel", "*.xlsx"), ("All", "*.*")],
working_dir = '.',
head_label_width = config.head_label_width,
entry_width = config.entry_width,
button_width = config.button_width,
edit_button_width = 0,
shell_button_width = 0,
is_print = True, igridrow = 2)
# npz path frame
tktkinter.make_path_frame(app, cparams, page1_frame, path_grid_frame,
tkvars, varname = 'outresfile',
file_type = [("npz", "*.npz"), ("All", "*.*")],
working_dir = '.',
head_label_width = config.head_label_width,
entry_width = config.entry_width,
button_width = config.button_width,
edit_button_width = 0,
shell_button_width = 0,
is_print = True, igridrow = 3)
# Button
def analyze(app, cparams, tkvars):
copy_tkvars(app, cparams, tkvars)
print("")
print("Execute analysis")
c_engine.execute(app, cparams, wait_by_input = False)
def validate(app, cparams, tkvars):
copy_tkvars(app, cparams, tkvars)
print("")
print("Execute analysis")
c_engine.validate(app, cparams, wait_by_input = False)
def usage_cli(app, cparams, tkvars):
copy_tkvars(app, cparams, tkvars)
print("")
# cparams.infile = tkvars['infile'].get()
c_engine.usage(app)
button_frame = tkinter.Frame(page1_frame)
button1 = tktkinter.Button(app, button_frame, text = 'analyze', width = 8, font = ("", 16),
command = lambda: analyze(app, cparams, tkvars))
button1.pack(side = tkinter.LEFT)
button2 = tktkinter.Button(app, button_frame, text = 'validate', width = 8, font = ("", 16),
command = lambda: validate(app, cparams, tkvars))
button2.pack(side = tkinter.LEFT)
button3 = tktkinter.Button(app, button_frame, text = 'citation', width = 8, font = ("", 10),
command = lambda: c_engine.citation(app))
button3.pack(side = tkinter.RIGHT)
button4 = tktkinter.Button(app, button_frame, text = 'usage(cli)', width = 8, font = ("", 10),
command = lambda: usage_cli(app, cparams, tkvars))
button4.pack(side = tkinter.RIGHT)
button_frame.pack(side = tkinter.TOP, anchor = 'w', padx = 2, pady = 2, fill = tkinter.X, expand = True)
# Parameter block
vars_grid_frame = tkinter.Frame(page1_frame)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = 'nx_2D', vartype = 'int',
defval = [config, 11], from_ = 1, to = 101, increment = 10, box_width = 6,
reset_val = 11,
# help_text = 'ma_num_probes',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 0)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = 'ny_2D', vartype = 'int',
defval = [config, 11], from_ = 1, to = 100, increment = 10, box_width = 6,
reset_val = 11,
# help_text = 'ma_num_probes',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 1)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = 'max_num_probes', vartype = 'int',
defval = [config, 1], from_ = 1, to = 100, increment = 5, box_width = 6,
reset_val = 1,
# help_text = 'ma_num_probes',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 2)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = 'num_search_each', vartype = 'int',
defval = [config, 1], from_ = 1, to = 100, increment = 5, box_width = 6,
reset_val = 1,
# help_text = 'Number of probes at each iteration. Default: 0',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 3)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "num_rand_basis", vartype = 'int',
defval = [config, 200], from_ = 1, to = 5000, increment = 50, box_width = 6,
reset_val = 200,
# help_text = 'Number of random Gauss bases. Default: 200',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 4)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "interval", vartype = 'int',
defval = [config, 0], from_ = 1, to = 5000, increment = 10, box_width = 6,
reset_val = 0,
# help_text = 'Iterations to update hyper parameters. Default: 0',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 5)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "score_mode", vartype = 'str',
defval = [config, 'EI'], values = ['EI', 'PI', 'TS'], box_width = 6,
reset_val = 'EI',
# help_text = 'Type of aquisition function. Default: EI',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 6)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "random_seed", vartype = 'str',
defval = '',
reset_val = '',
# help_text = 'Seed for random numbers. Leave blank ("": null) to apply random seed. ' \
# + 'Specify an integer if you need reprodcible random numbers. Default: ""[null]',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 7)
frame = tktkinter.make_var_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "fraction_test", vartype = 'float',
defval = 0.0, from_ = 0.0, to = 1.0, increment = 0.1, box_width = 6,
reset_val = 0.0,
# help_text = 'Fraction or number of test data. < 1.0 specifies fraction >= 1 specifies the number. Default: 0.0',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
igridrow = 8)
frame = tktkinter.make_check_box(app, cparams, tkvars, page1_frame, vars_grid_frame,
varname = "standardize", label = 'standardize',
reset_val = 1,
# help_text = 'Number of random Gauss bases. Default: 200',
button1_args = {'text': 'default', "width": 6, 'font': ("", 10), 'command': 'set_default'},
button2_args = {'text': 'help', "width": 6, 'font': ("", 10), 'command': 'show_help'},
onvalue = 1, offvalue = 0,
igridrow = 9)
# Message text box
textframe = tktkinter.Frame(app, page1_frame, bg = 'dim gray')
message_box = tktkinter.Text(app, textframe,
width = config.get("message_box_width", 100), height = config.get("message_box_height", 5))
scrollbar = tkinter.Scrollbar(textframe, orient = tkinter.VERTICAL, command = message_box.yview)
message_box["yscrollcommand"] = scrollbar.set
message_box.grid(row = 0, column = 0)
scrollbar.grid(row = 0, column = 1, sticky = (tkinter.N, tkinter.S))
textframe.pack(side = tkinter.TOP, anchor = 'w', expand = True, padx = 2, pady = 2)
tkvars['message_box'] = message_box
return notebook_frame
[ドキュメント]
def create_canvas_tab(app, config, cparams, pane, title):
"""
キャンバスを表示するタブをペインに追加します。
概要:
新しいフレームを作成し、その中にTkinter Canvasウィジェットを配置して、指定されたペインにタブとして追加します。
詳細説明:
この関数は、描画や視覚化のためのキャンバスを提供するタブを作成するために使用されます。
現在、キャンバスは作成されるだけで、具体的な描画ロジックは含まれていません。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param pane: タブを追加する親ペインウィジェット。
:type pane: tkinter.ttk.Notebook or tkinter.PanedWindow
:param title: タブのタイトル文字列。
:type title: str
:returns: 作成されたタブのフレーム。
:rtype: tktkinter.Frame
"""
title = app.p(title)
frame = tktkinter.Frame(app, pane, bg='dim gray')
pane.add(frame, text = title)
app.canvas = tktkinter.Canvas(app, frame)
return frame
[ドキュメント]
def create_left_frame4(app, config, cparams, pane, title):
"""
Treeviewを含むテスト用ウィジェットタブをペインに追加します。
概要:
TkinterのTreeviewウィジェットを含むフレームを作成し、指定されたペインにタブとして追加します。
詳細説明:
このタブは、Treeviewウィジェットの機能テストやデモンストレーションのために用意されています。
階層的なデータ表示と複数列のデータ表示が可能なTreeviewが作成され、サンプルデータが挿入されます。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param pane: タブを追加する親ペインウィジェット。
:type pane: tkinter.ttk.Notebook or tkinter.PanedWindow
:param title: タブのタイトル文字列。
:type title: str
:returns: None
"""
title = app.p(title)
frame = tktkinter.Frame(app, pane, bg='dim gray')
pane.add(frame, text = title)
treeview = tkinter.ttk.Treeview(frame, columns=["colA", "colB", "colC"])
treeview.column("#0", width=100)
treeview.column("colA", width=80)
treeview.column("colB", width=80)
treeview.column("colC", width=80)
treeview.heading("#0", text="階層列")
treeview.heading("colA", text="データ列A")
treeview.heading("colB", text="データ列B")
treeview.heading("colC", text="データ列C")
itemAId = treeview.insert("", tkinter.END, text="itemA", open=True, values=("data1a", "data1b", "data1c"))
itemBId = treeview.insert(itemAId, tkinter.END, text="itemB", open=True, values=("data2a", "data2b", "data2c"))
itemCId = treeview.insert(itemBId, tkinter.END, text="itemC", values=("data3a", "data3b", "data3c"))
itemDId = treeview.insert("", tkinter.END, text="itemD", values=("data4a", "data4b", "data4c"))
treeview.pack()
[ドキュメント]
def create_left_frame3(app, config, cparams, pane, title):
"""
TextウィジェットとListboxを含むテスト用ウィジェットタブをペインに追加します。
概要:
垂直スクロールバー付きのTextウィジェットとListboxウィジェットを含むフレームを作成し、
指定されたペインにタブとして追加します。
詳細説明:
このタブは、TextおよびListboxウィジェットの機能テストやデモンストレーションのために用意されています。
Listboxには月の名前が挿入され、ユーザーが選択できる状態になります。
もう一つのTextウィジェットも出力表示用として用意されています。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param pane: タブを追加する親ペインウィジェット。
:type pane: tkinter.ttk.Notebook or tkinter.PanedWindow
:param title: タブのタイトル文字列。
:type title: str
:returns: None
"""
title = app.p(title)
frame = tktkinter.Frame(app, pane, bg='dim gray')
pane.add(frame, text = title)
textframe = tktkinter.Frame(app, frame, bg='dim gray')
textframe.pack()
text = tkinter.Text(textframe, height = 4, width = 20)
scrollbar = tkinter.Scrollbar(textframe, orient = tkinter.VERTICAL, command=text.yview)
text["yscrollcommand"] = scrollbar.set
text.grid(row=0, column=0)
scrollbar.grid(row=0, column=1, sticky=(tkinter.N, tkinter.S))
listbox = tkinter.Listbox(frame)
for month in ("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"):
listbox.insert(tkinter.END, month)
listbox.pack()
output_text = tktkinter.Text(app, frame,
width = 60,
height = 10)
output_text.pack(side = tkinter.TOP, anchor = 'w', expand = True, padx = 2, pady = 2)
# tkvars['outputtext'] = output_text
[ドキュメント]
def create_left_frame2(app, config, cparams, pane, title):
"""
各種Tkinterウィジェット(Menubutton, Scale, Dialog, Progressbar, Checkbutton, OptionMenu, Combobox, Radiobutton, Spinbox)を含むテスト用タブをペインに追加します。
概要:
多様なTkinterウィジェットを配置したフレームを作成し、指定されたペインにタブとして追加します。
詳細説明:
このタブは、Tkinterで利用可能な様々な標準ウィジェットの動作確認やデモンストレーションを目的としています。
カスタムダイアログの表示、スライダー、プログレスバー、チェックボックス、オプションメニュー、コンボボックス、
ラジオボタン、スピンボックスといった基本的なインタフェース要素が含まれています。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:param pane: タブを追加する親ペインウィジェット。
:type pane: tkinter.ttk.Notebook or tkinter.PanedWindow
:param title: タブのタイトル文字列。
:type title: str
:returns: 作成されたタブのフレーム。
:rtype: tktkinter.Frame
"""
title = app.p(title)
frame = tktkinter.Frame(app, pane, bg='dim gray')
pane.add(frame, text = title)
mb = tkinter.Menubutton(frame, text="menubutton:Select alphabet")
mb.pack()
menu = tkinter.Menu(mb)
menu.add_command(label="A")
menu.add_command(label="B")
mb["menu"] = menu
scale = tkinter.Scale(frame, width = 20, length = 300, label = 'title',
orient = tkinter.HORIZONTAL, showvalue = True,
from_ = 0, to = 100, tickinterval = 20)
scale.pack()
class CustomDialog(tkinter.simpledialog.Dialog):
def __init__(self, master, title=None) -> None:
super(CustomDialog, self).__init__(parent=master, title=title)
def body(self, master) -> None:
entry = tkinter.Entry(master)
entry.grid(column=0, row=0)
def buttonbox(self):
box = tkinter.Frame(self)
self.button1 = tkinter.Button(box, text="OK", width=10, command=self.ok, state=tkinter.DISABLED)
self.button1.pack(side=tkinter.LEFT, padx=5, pady=5)
self.button2 = tkinter.Button(box, text="Cancel", width=10, command=self.cancel)
self.button2.pack(side=tkinter.LEFT, padx=5, pady=5)
box.pack()
def switchButtonState(self):
if self.button1['state'] == tk.DISABLED:
self.button1['state'] = tk.NORMAL
def apply(self): # ダイアログボックスを閉じた後
pass
# print(self.var.get())
def display_dialog():
CustomDialog(pane)
# tkinter.simpledialog.Dialog(pane)
button = tktkinter.Button(app, frame, text = "dialog", command = display_dialog)
button.pack(side = 'top', anchor = 'w', padx = 5, pady = 5)
progressbar = tkinter.ttk.Progressbar(frame, value = 50)
progressbar.pack()
check_var = tkinter.BooleanVar(value = True)
# check_var.set(True)
# イベントハンドラーでget()しないと正常に初期化されない
def checked_button():
# print("checked", check_var.get())
check_var.get()
check = tkinter.Checkbutton(frame, variable = check_var, text = '選択しますか?',
onvalue = True, offvalue = False,
command = checked_button)
check.pack()
var = tkinter.StringVar()
var.set('aaa')
optionmenu = tkinter.OptionMenu(frame, var, 'aaa', 'bbb')
optionmenu.pack()
combobox = tkinter.ttk.Combobox(frame, values=('aaa', 'bbb', 'ccc'))
combobox.pack()
rdvar = tkinter.StringVar()
rdvar.set('B')
aButton = tkinter.Radiobutton(frame, variable = rdvar,
value = 'A', text = 'Option A') #, command = self.showValue)
aButton.pack()
bButton = tkinter.Radiobutton(frame, variable = rdvar,
value = 'B', text = 'Option B') #, command=self.showValue)
bButton.pack()
spinbox = tkinter.Spinbox(frame, cursor = 'clock',
from_ = 0, to = 100, increment = 3, format = '%12.6f')
spinbox.pack()
return frame
[ドキュメント]
def create_window(app, config, cparams):
"""
メインGUIウィンドウと内部のペイン、タブを作成します。
概要:
アプリケーションのルートウィンドウを初期化し、ツールバーと、複数のタブを持つノートブックペインを配置します。
詳細説明:
この関数は、GUIの視覚的なレイアウトを構築する役割を担います。
`tkApplication_GUI`の機能を利用してルートウィンドウを作成し、設定されたジオメトリと最小サイズを適用します。
次に、ツールバーを追加し、メインのコンテンツエリアとしてノートブックウィジェットを持つシングルペインレイアウトを作成します。
このノートブックには、「Analyze」(メイン設定)、「Graph」(グラフ設定)、「Development」(開発用)、
「Editor test」(エディタテスト)、およびいくつかの「Widget test」タブが追加されます。
最後に、アプリケーションのメインループを開始し、GUIイベントを処理します。
:param app: アプリケーションインスタンス。
:type app: tklib.tkgui.tkapplication_gui.tkApplication_GUI
:param config: アプリケーションの設定パラメータオブジェクト。
:type config: tklib.tkparams.tkParams
:param cparams: 計算エンジンのパラメータオブジェクト。
:type cparams: tklib.tkparams.tkParams
:returns: None
"""
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
root_window = app.create_window(title = sys.argv[0], geometry = config.geometry, minsize = config.minsize)
# menu_bar = create_menu(app, config, cparams, root_window)
tool_bar = create_toolbar(app, config, cparams, root_window)
# 2分割ウインドウを使う場合。いづれのpaneもnotebook型ウインドウが作られる
# panes = app.add_root_panes(root = root_window, type = "pane2", sashwidth = 2, left_pane_width = 600)
# main_pane, left_notebook, right_notebook = panes
# 1分割ウインドウを使う場合。paneはnotebook型ウインドウが作られる
panes = app.add_root_panes(type = "pane1", sashwidth = 2)
left_notebook = panes[0]
# 左ペインのnotebookにタブを追加
ltabframe1 = create_main_tab(app, config, cparams, left_notebook)
ltabframe2 = create_graph_tab(app, config, cparams, left_notebook)
ltabframe3 = app.create_development_tab(config, cparams, left_notebook, copy_tkvars = copy_tkvars)
ltabframe4 = app.create_editor_tab(config, cparams, left_notebook, title = 'Editor test',
entry_width = 35,
eval_button_args = { 'text': 'eval', 'width': 4, "command": None },
)
# ltabframe6 = create_canvas_tab(app, config, cparams, left_notebook, title = 'Canvas test')
ltabframe6 = create_left_frame2(app, config, cparams, left_notebook, title = 'Widget test1')
ltabframe7 = create_left_frame3(app, config, cparams, left_notebook, title = 'Widget test2')
ltabframe8 = create_left_frame4(app, config, cparams, left_notebook, title = 'Widget test3')
app.mainloop()
[ドキュメント]
def main():
"""
アプリケーションのエントリーポイント。GUIの初期化、設定読み込み、ウィンドウ作成、実行を行います。
概要:
本スクリプトの実行開始点であり、`tkApplication_GUI`インスタンスの生成から、
GUIウィンドウの作成、設定の保存、およびアプリケーションの終了処理までを制御します。
詳細説明:
1. `tkApplication_GUI`インスタンスを初期化し、グローバル変数とローカル変数を設定します。
2. `config`(アプリケーション設定)と`cparams`(計算エンジンパラメータ)のオブジェクトを取得します。
3. アプリケーションのバージョン情報と修正日時をコンソールに出力します。
4. `initialize`関数を呼び出して、アプリケーションの非設定および設定可能なパラメータを初期設定します。
5. 設定ファイル (`config.inifile`) から既存の設定を読み込みます。
6. コマンドライン引数があれば、`update_vars`を呼び出してパラメータを更新します(現在はコメントアウト)。
7. 現在の言語設定に基づいてリソースファイルを読み込み、フレーズを初期化します。
8. 設定に基づき作業ディレクトリを変更します。
9. `create_window`関数を呼び出してメインGUIウィンドウを作成し、Tkinterのイベントループを開始します。
10. GUIが閉じられた後、GUIウィジェットの現在の設定値を`cparams`と`config`にコピーします。
11. メインウィンドウのジオメトリを`config`に保存します。
12. 最新の設定を`config.inifile`に保存します。
13. 必要であれば、計算パラメータをパラメータファイル (`.prm`または`.ini`) に保存します。
14. アプリケーションを正常終了します。
:returns: None
"""
#==================================================================
# Initialize parameters
#==================================================================
app = tkApplication_GUI(usage_str = usage_str, globals = globals(), locals = locals(),
use_user_inifile = True,
inifile_dirs = ['../../user', 'user'], create_inidir = False)
app.env = os.environ
# 設定パラメータオブジェクト
config = app.configparams
cparams = app.get_params() # 計算エンジンのパラメータオブジェクト
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
mtime = time.localtime(os.path.getctime(app.script_path))
print("")
print( "################################################")
print(f"# {app.script_path} ver {version[0]}.{version[1]}.{version[2]}")
print(f"# Modified time: {mtime.tm_year}/{mtime.tm_mon}/{mtime.tm_mday} {mtime.tm_hour}:{mtime.tm_min}:{mtime.tm_sec}")
print( "################################################")
print(f"Initialize parameters")
initialize(app, config)
# 本GUIの設定パラメータオブジェクト
config = app.configparams
# GUIウィジェット変数オブジェクトと辞書型
ctkvars = app.tkvars
tkvars = ctkvars.get_param_dict()
print(f"Read configration from [{config.inifile}]")
config.read_parameters(path = config.inifile)
print(f"Update parameters by command-line arguments")
update_vars(app, cparams)
app.resource_path = os.path.join(app.resource_dir, f'resource_{app.config.lang}.resource')
app.phrases = app.read_resource(app.resource_path, app.config.lang) #, app.phrases)
work_dir = None
infile = config.get('infile', None)
if infile is not None:
work_dir, basename, filebody, ext = split_file_path(infile)
if work_dir is None:
work_dir = config.get('work_dir', None)
if work_dir is not None and work_dir != '':
if os.path.exists(work_dir):
os.chdir(work_dir)
create_window(app, config, cparams)
infile = config.get('infile', None)
if infile is not None:
work_dir, basename, filebody, ext = split_file_path(infile)
if work_dir is not None:
config.work_dir = work_dir
# ウィジェットの設定tkvarsをcparams,confgにコピー
copy_tkvars(app, cparams, tkvars)
copy_tkvars(app, config, tkvars)
# メインウインドウサイズをconfigにコピー
config.geometry = app.root_window_geometry
print("")
print(f"Save configuration to [{config.inifile}]")
config.save_parameters(path = config.inifile, section = 'Configure', sort_by_keys = True, IsPrint = False)
# 必要があれば、入力ファイルに対応するパラメータファイルを保存
if tkvars.get("prmpath", None) is not None:
cparams.prmpath = tkvars["prmpath"].get() #os.path.splitext(cparams.path)[0] + '.prm'
if cparams.prmpath != '':
print(f"Save parameters to [{cparams.prmpath}]")
ret = cparams.save_parameters(cparams.prmpath, section = 'Parameters',
sort_by_keys = True, IsPrint = False, update_commandline = False)
if not ret:
app.terminate(f"Error in main(): Cannot write to [{cparams.prmpath}]", usage = usage)
app.terminate()
if __name__ == "__main__":
main()