"""
GUI for bayes_gp_plain.py
概要:
ガウス過程を用いたベイズ最適化のGUIアプリケーション。
詳細説明:
このスクリプトは、`bayes_gp_plain2.py` の計算エンジンを操作するための
グラフィカルユーザーインターフェース(GUI)を提供します。
ファイルパスの指定、ベイズ最適化のパラメータ設定、グラフ表示、
およびアプリケーションの一般的な設定変更が可能です。
Tkinterライブラリを使用して構築されています。
関連リンク:
:doc:`bayes_gp_gui_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 as c_engine
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: tkApplication_GUI):
"""
概要:
アプリケーションの使用方法をコマンドラインに出力します。
詳細説明:
`app` オブジェクトに格納されている `usage_str` を解析し、
各行を標準出力に表示します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
"""
# 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: tkApplication_GUI, config: tkIniFile):
"""
概要:
アプリケーションの初期設定とデフォルト値を定義します。
詳細説明:
ファイルタイプ、リソースディレクトリ、および設定可能なパラメータ
(言語、デバッグモード、ウィンドウサイズなど)のデフォルト値を設定します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
"""
#================================
# 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: tkApplication_GUI, cparams: tkParams):
"""
概要:
コマンドライン引数に基づいて計算パラメータを更新します。
詳細説明:
現在のコードでは特にコマンドライン引数を処理していませんが、
`getarg` のコメントアウトから、将来的に引数を処理する可能性を示唆しています。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
"""
argv = app.argv
# if len(argv) <= 1:
# app.terminate(usage = usage)
# cparams.infile = getarg(1, cparams.infile)
[ドキュメント]
def copy_tkvars(app: tkApplication_GUI, cparams: tkParams, tkvars: dict):
"""
概要:
GUIウィジェットの変数(tkvars)の値を計算パラメータオブジェクトと設定パラメータオブジェクトにコピーします。
詳細説明:
特定のキーに対応するTkinter変数の値を取得し、`cparams` (計算パラメータ)
および `config` (アプリケーション設定) の対応する属性に設定します。
グラフのサイズも処理します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param tkvars: dict: Tkinterウィジェット変数を格納する辞書。
"""
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: tkApplication_GUI, cparams: tkParams, config: tkIniFile):
"""
概要:
アプリケーション設定パラメータを計算パラメータにコピーします。
詳細説明:
`config` オブジェクトのキーが `cparams` オブジェクトにも存在する場合、
その値を `cparams` にコピーします。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
"""
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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, parent_notebook: tkinter.ttk.Notebook) -> tkinter.Frame:
"""
概要:
グラフ設定用のタブページを作成します。
詳細説明:
グラフの幅、高さ、フォントサイズ、凡例のフォントサイズを設定するための
ウィジェットを配置します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param parent_notebook: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
戻り値 (Returns):
:returns: tkinter.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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, parent_notebook: tkinter.ttk.Notebook) -> tkinter.Frame:
"""
概要:
メインの分析タブページを作成します。
詳細説明:
入力ファイル、出力ファイル、結果ファイル(npz)のパス設定、
分析・検証・引用・使用方法(CLI)ボタン、および各種計算パラメータ
(グリッドサイズ、プローブ数、乱数シードなど)の入力ウィジェットを配置します。
メッセージボックスも含まれます。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param parent_notebook: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
戻り値 (Returns):
:returns: tkinter.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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, pane: tkinter.ttk.Notebook, title: str) -> tkinter.Frame:
"""
概要:
Canvasウィジェットを含むタブページを作成します。
詳細説明:
指定されたペイン内に新しいフレームを作成し、その中にTkinterのCanvasウィジェットを配置します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param pane: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
:param title: str: タブページのタイトル。
戻り値 (Returns):
:returns: tkinter.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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, pane: tkinter.ttk.Notebook, title: str):
"""
概要:
Treeviewウィジェットを含むタブページ(左ペインのフレーム)を作成します。
詳細説明:
指定されたペイン内に新しいフレームを作成し、その中に階層的なデータを
表示するためのTreeviewウィジェットを配置します。
いくつかのサンプルデータが挿入されます。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param pane: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
:param title: str: タブページのタイトル。
"""
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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, pane: tkinter.ttk.Notebook, title: str):
"""
概要:
TextウィジェットとListboxウィジェットを含むタブページ(左ペインのフレーム)を作成します。
詳細説明:
指定されたペイン内に新しいフレームを作成し、その中に複数行テキスト入力用の
Textウィジェットと項目選択用のListboxウィジェットを配置します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param pane: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
:param title: str: タブページのタイトル。
"""
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: tkApplication_GUI, config: tkIniFile, cparams: tkParams, pane: tkinter.ttk.Notebook, title: str) -> tkinter.Frame:
"""
概要:
多様なTkinterウィジェットを含むタブページ(左ペインのフレーム)を作成します。
詳細説明:
Menubutton、Scale、カスタムダイアログを起動するボタン、Progressbar、
Checkbutton、OptionMenu、Combobox、Radiobutton、Spinboxなど、
様々なTkinterウィジェットを配置します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
:param pane: tkinter.ttk.Notebook: 親となるノートブックウィジェット。
:param title: str: タブページのタイトル。
戻り値 (Returns):
:returns: tkinter.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):
"""
概要:
カスタムダイアログボックスを実装するクラス。
詳細説明:
`tkinter.simpledialog.Dialog` を継承し、独自のボディとボタンボックスを定義します。
引数 (Parameters):
:param master: tkinter.Widget: 親ウィジェット。
:param title: str or None: ダイアログのタイトル。
"""
def __init__(self, master: tkinter.Widget, title: str = None) -> None:
"""
概要:
CustomDialogクラスのコンストラクタ。
詳細説明:
親クラスのコンストラクタを呼び出し、ダイアログを初期化します。
引数 (Parameters):
:param master: tkinter.Widget: 親ウィジェット。
:param title: str or None: ダイアログのタイトル。
"""
super(CustomDialog, self).__init__(parent=master, title=title)
def body(self, master: tkinter.Frame) -> None:
"""
概要:
ダイアログのメインコンテンツ領域を作成します。
詳細説明:
エントリウィジェットを配置します。
引数 (Parameters):
:param master: tkinter.Frame: ダイアログのボディフレーム。
"""
entry = tkinter.Entry(master)
entry.grid(column=0, row=0)
def buttonbox(self):
"""
概要:
ダイアログの下部にあるボタン領域を作成します。
詳細説明:
「OK」ボタンと「Cancel」ボタンを配置し、それぞれのコマンドを割り当てます。
「OK」ボタンは初期状態で無効化されています。
"""
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):
"""
概要:
「OK」ボタンの状態を切り替えます。
詳細説明:
現在「OK」ボタンの状態が `DISABLED` であれば `NORMAL` に変更します。
注意: ここでは `tk.DISABLED` が使用されていますが、
このスコープでは `tk` は未定義の可能性があります。
"""
if self.button1['state'] == tk.DISABLED: # Bug: tk is not defined. Should be tkinter.DISABLED
self.button1['state'] = tk.NORMAL
def apply(self): # ダイアログボックスを閉じた後
"""
概要:
ダイアログが閉じられた後に実行される処理を定義します。
詳細説明:
このメソッドは、ダイアログがOKボタンで閉じられた際に自動的に呼び出されますが、
現在はこのメソッドで具体的な処理は定義されていません。
"""
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: tkApplication_GUI, config: tkIniFile, cparams: tkParams):
"""
概要:
GUIアプリケーションのメインウィンドウとタブページを作成します。
詳細説明:
メインウィンドウを初期化し、ツールバーと、メイン分析、グラフ設定、開発、
エディタ、様々なウィジェットのテスト用のタブページを含むノートブックペインを配置します。
引数 (Parameters):
:param app: tkApplication_GUI: GUIアプリケーションのメインインスタンス。
:param config: tkIniFile: 設定パラメータを管理するオブジェクト。
:param cparams: tkParams: 計算エンジン用パラメータを管理するオブジェクト。
"""
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():
"""
概要:
アプリケーションのエントリーポイント。
詳細説明:
`tkApplication_GUI` のインスタンスを初期化し、設定ファイルからパラメータを読み込み、
コマンドライン引数で更新し、GUIウィンドウを作成して表示します。
終了時には設定をiniファイルに保存します。
"""
#==================================================================
# 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) # <-- この行は `copy_tkvars(app, config, tkvars)` と解釈される。
# 第一引数がapp、第二引数がcparamsまたはconfig、第三引数がtkvarsと期待されるため、
# 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()