質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1664閲覧

TkinterでglobalにDataFrameを使用したいです

PeroNyago

総合スコア5

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/03/25 08:10

前提・実現したいこと

Tkinterを使ったGUIの作成しています。
子ウインドウに入力された数字を保存ボタンにて取得し次々に入力されるデータにてDataFrameを作成しglobalで保持したいです。
他の方の作られたものを参考にしております。buttonClickの挙動も分からないのでアドバイス頂けませんでしょうか?

発生している問題・エラーメッセージ

なし

該当のソースコード

python3

1import tkinter as tk 2import pandas as pd 3 4win = tk.Tk() 5 6class Application(tk.Frame): 7 def __init__(self,master): 8 super().__init__(master) 9 master.geometry("300x300") 10 master.title("title") 11 12 self.window = [] 13 self.user = [] 14 15 self.button = tk.Button(master,text='Button', height=5, width=20, command=self.buttonClick) 16 self.button.grid(row=0, column=1, padx=20, pady=60) 17 18 def buttonClick(self): 19 self.window.append(tk.Toplevel()) 20 self.user.append(User(self.window[len(self.window)-1],len(self.window))) 21 22class User(tk.Frame): 23 def __init__(self,master,num): 24 super().__init__(master) 25 master.geometry("300x300") 26 master.title(u"Button2") 27 28 def text_get(): 29 global id 30 id = self.id_entry.get() 31 print('bottonにより得られたのは'+id) 32 return id 33 34 self.id_text = tk.Label(master, text="ID") 35 self.id_text.place(x=20,y=20) 36 self.id_entry = tk.Entry(master, width=18) 37 self.id_entry.place(x=80,y=20) 38 39 self.button = tk.Button(master, text='保存', command=text_get, height=2, width=10) 40 self.button.place(x=200, y=200) 41 42#def MakeList(id): 43# df = pd.DataFrame(columns=['ID']) 44# pt_dat = pd.Series([id], index=list_df.columns) 45# df = df.append(pt_dat, ignore_index=True ) 46# print(df) 47 48 49def main(): 50 win = tk.Tk() 51 app = Application(win) 52 app.mainloop() 53 54 55if __name__ == '__main__': 56 main()

試したこと

  1. DataFrameを作成する関数MakeListを定義した。
  2. idをグローバル化して、mainで上記を使用してみた

idがmakeListに帰ってこないので、
3. text get下で定義したが、入力ごとにリセットされindexが0となる
そもそもDataFrameが思うように動かない →3
最終的にglobalで使用したいが引数をうけとれない →2

補足情報(FW/ツールのバージョンなど)

jupyterLab

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

python

1self.button = tk.Button(master, text='保存', command=MakeList, height=2, width=10)

として、MakeList関数からIDを参照する方法を、2通り紹介します。

A) トップレベルに置いた変数経由でアクセス

python

1win = tk.Tk() # <-- main()関数内ではなく、ファイル先頭の方 2id_var = tk.IntVar() 3 4 5# Entry の引数に textvariable を追加 6self.id_entry = tk.Entry(master, textvariable=id_var, width=18) 7 8 9# MakeList() 内 10def MakeList(): 11 id = id_var.get()

文字列の場合は同様に tk.StringVar があります。

B) 外部の関数から、クラス内部で作ったウィジェットにアクセス

Tk の提供するウィジェット検索関数 nametowidget() を使います。

python

1# Entry ウィジェットに name を付ける。 2self.id_entry = tk.Entry(master, name="id", width=18) 3 4# MakeList() 内 5# 1. ".!toplevel.id" の部分は、GUI部品の構成により変わります (親ウィジェットからのパス) 6# 2. Entry.get() は文字列を返すので、数値に変換する必要あり 7 8def MakeList(): 9 id = int(win.nametowidget(".!toplevel.id").get())

DateFrame に関しては未テストですが、
pd.Series([id], index=list_df.columns) の id が数値型になっているかを要確認。


組み込み関数に id という関数があるため、
Editor によっては組み込み関数としてハイライトされることがあります。

組み込み関数との名前被り自体は(気をつけていれば)問題ないのですが、
自分で定義したグローバル変数のid を参照したはずが、
組み込み関数idだった等ということを避けるためにも
別の名前にしたほうが無難です。

投稿2020/03/25 10:14

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PeroNyago

2020/03/26 23:49 編集

回答いただきましてありがとうございます。 Aの方法でグローバルにデータを取得することができましたが、buttonにより取得されたデータに対して毎回DataFrameを作成するため各データが蓄積されません。 解決方法やアドバイス等ご教授頂けませんでしょうか?    ID    ID|  ID      0 111 →0 222|0 111 ************ | 1 222 になるようにしたいです。
teamikl

2020/03/27 05:44

`list_df` がなかったので DataFrame の部分は実行できませんでした。 問題が再現できるようにコード編集お願いできますか。 (データベースから読み込んでいたり準備が大掛かりな場合等は、 仮で小さなデータに置き換えでも良いです。) 毎回作成するに関しては、 ボタンクリック時のイベント内で新しいDataFrameを作成しているからなので、 MakeList()の外で予め DataFrame を作っておくで解消できます。
PeroNyago

2020/03/31 08:14

連絡が遅くなり申し訳ございません。コメントアウトの部分のlist_dfはdfの間違いでした。 エラーの件は一度保留にさせてください。 初心者なもので、MakeList()の外で予めDataFrameを作る方法がうまくいきません。 df = pd.DataFrame(columns=['ID'])を先頭のほうに置き MakeList()からreturnでpt_datを返してみました。 df = df.append(pt_dat, ignore_index=True )をmainの中に定義すべきでしょうか? よろしくお願いいたします。
teamikl

2020/03/31 08:21

毎回作成してはいけないものを関数の外側にだせば良いです。 main()関数の中では、MakeList()関数から参照出来ないので、 この場合は、グローバルに置くことになります。 >MakeList()からreturnでpt_datを返してみました。 return するとしたら何処で値を受け取るのでしょう? これは、コードを見ないと解りませんが ボタンクリック時に実行される関数なので、 戻り値を受け取る方法がないと思います。
PeroNyago

2020/03/31 21:05

説明不足で、意図が伝わってなかったら申し訳ございません。 もう少し詳細なコードを作成しますので、また見ていただけませんでしょうか? しばらくお待ちください。
teamikl

2020/04/01 03:00

そうですね、現状のコードとの齟齬がありそうなので、コードを見たほうが確実です。 念の為確認、コード中の pt_dat を何処か(グローバル)に蓄積したいという事ですよね? >df = pd.DataFrame(columns=['ID'])を先頭のほうに置き ここまでは大丈夫です。 その後のMakeList()からreturn pt_datしたのを何処でどうしてるのか の部分が知りたい情報です。
PeroNyago

2020/04/07 20:12

もう少し詳しいコードと説明を載せました。よろしくお願いいたします。 ふと思ったのですが、ソフトウェア上でデータを持たせる時はcsv等に読書したほうが良いのでしょうか?
PeroNyago

2020/04/07 20:15

MakeList()からreturn pt_datしたのを何処でどうしてるのかの部分が知りたい情報です。 →この先はreturnして受け取るようにすべきかと思いましたが、書き方が分かりませんでした。
teamikl

2020/04/07 23:03 編集

ボタンのcommandに登録した関数は、 ライブラリ側からイベント処理時に呼び出される為、 ユーザ側のコードで直接戻り値を受け取ることはできません。 (受け取りたい場合は、別の関数を登録して、その中でMakeList()を呼びます) 追加に関しては、以下の一行だけで動くようになりました。 (コメントなのでインデントが消えてしまいますが、適切なインデントで) def MakeList(): global df # <- この行を追加 参照だけの場合は問題ありませんが 変数への代入の場合、グローバル宣言がないと ローカル変数扱いされてしまいます。 https://docs.python.org/ja/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
teamikl

2020/04/07 22:53 編集

---- 他の修正点 Series の "idnum", "name", "gen", "site" の引用符を外す。 ウィンドウが2枚開いてますが、 もし不要なら、`win = tk.Tk()` はどちらか一か所で良いです。 ---- > ソフトウェア上でデータを持たせる時はcsv等に読書したほうが良いのでしょうか? テストだけなら同じファイル内に書いてしまいますが、 実際の運用を想定で、入力を保存する必要があるなら、そうなりますね。 ファイルに記録するCSVでは データの一部分のみ変更したいといった場合でも、 ファイルを全部書き換える事になるので、不測のトラブルで(停電や強制終了) ファイルが壊れてしまわないようにケアが必要です。 用途次第ではデータベースの方が適切な事も有ります。 Pythonでは sqlite が手軽。(pandasからも使えます)
teamikl

2020/04/07 22:52

StringVar, IntVar の為に `win = tk.Tk()` としていたのですね。 main関数内の `win = tk.Tk()` が不要です。(2枚ウィンドウが開いてしまう)
PeroNyago

2020/04/08 19:31

お忙しい中詳細な回答、アドバイスまで頂きまして感謝しきれません。 sqlite等も勉強して、何とか形にします! 本当にありがとうございます。
guest

0

buttonClickの挙動も分からないのでアドバイス頂けませんでしょうか?

python

1def buttonClick1(self): 2 self.window.append(tk.Toplevel()) 3 self.user.append(User1(self.window[len(self.window)-1],len(self.window)))
  • self.window に新しいウィンドウを入れる。
  • self.window[len(self.window)-1] は末尾の要素、直近でappendしたものになります
  • self.window[-1] と同じ。

ほぼ同じ事をするコードで読みやすく書き換えるとこうなります。

python

1def buttonClick1(self): 2 top = tk.Toplevel() # 新しいウィンドウを開く 3 user = User1(top, len(self.user)) # フォームを配置 4 5 self.window.append(top) # リストに追加 6 self.user.append(user)

self.window が不要であれば、以下の様にもできます

python

1def buttonClick1(self): 2 user = User1(tk.Toplevel(), len(self.user)) 3 self.user.append(user)

気になった点: ウィンドウを閉じても self.window, self.user に蓄積されていく。
tkinter側のデータは解放されますが、Python側に無効なオブジェクトが残ります。
また、ウィンドウを同時に複数開けるのは問題ないのでしょうか。

現状のコードでは、未使用の変数のようですが、
User1 に引数 num が必要なら、数値のカウンターにした方が良いです。

# def __init__ 内で初期化 self.count = 0 def buttonClick1(self): self.count += 1 top = tk.Toplevel() user = User1(top, self.count)

num が不要なら、もっとコンパクトにできます。

# User1 の引数の num を取り除いて def buttonClick1(self): User1(tk.Toplevel())

投稿2020/04/07 23:28

編集2020/04/07 23:32
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

イメージ説明説明説明](51ca5dd8473ef84a27fab3b617877188.jpeg)](4f7fdc5aee61037a420dd515c9e5f119.jpeg)

python3

1import tkinter as tk 2import tkinter.ttk as ttk 3import pandas as pd 4import numpy as np 5 6win = tk.Tk() 7id_var = tk.StringVar() 8name_var = tk.StringVar() 9age_var = tk.IntVar() 10gen_var = tk.StringVar() 11hei_var = tk.IntVar() 12wei_var = tk.IntVar() 13site_var = tk.StringVar() 14x_var = tk.IntVar() 15y_var = tk.IntVar() 16z_var = tk.IntVar() 17 18#originalデータフレーム 19list_pt = [["0000001", "山田太郎", 50,"男性",170,70,"prostate",0.9,0.5,0.2], 20 ["0000001", "山田太郎", 50,"男性",170,70,"prostate",0.6,0.4,0.1], 21 ["1111111", "佐藤花子", 45,"女性",162,48,"breast",0.1,0.2,0.1]] 22columns = ["ID","名前","年齢","性別","身長 (cm)","体重 (kg)","部位","x","y","z"] 23df = pd.DataFrame(data=list_pt, columns=columns) 24df 25print(df) 26 27class Application(tk.Frame): 28 def __init__(self,master): 29 super().__init__(master) 30 master.geometry("650x380") 31 master.title("Daily Image Guidance Manager") 32 33 self.window = [] 34 self.user = [] 35 36 self.button = tk.Button(master,text='Daily IGRT', height=5, width=20, command=self.buttonClick1) 37 self.button.grid(row=0, column=0, padx=40, pady=60) 38 39 self.button = tk.Button(master,text='新規患者登録/修正', height=5, width=20, command=self.buttonClick2) 40 self.button.grid(row=0, column=1, padx=20, pady=60) 41 42 def buttonClick1(self): 43 self.window.append(tk.Toplevel()) 44 self.user.append(User1(self.window[len(self.window)-1],len(self.window))) 45 46 def buttonClick2(self): 47 self.window.append(tk.Toplevel()) 48 self.user.append(User2(self.window[len(self.window)-1],len(self.window))) 49 50 51class User1(tk.Frame): 52 def __init__(self,master,num): 53 super().__init__(master) 54 master.geometry("700x450") 55 master.title(u"Daily IGRT") 56 57 self.listbutton = tk.Button(master, text='治療中リスト', height=2, width=10) 58 self.listbutton.place(x=20, y=20) 59 60 self.regbutton = tk.Button(master, text='登録', height=2, width=10) 61 self.regbutton.place(x=20, y=80) 62 63 self.id_text = tk.Label(master, text="ID") 64 self.id_text.place(x=270,y=20) 65 self.id_entry = tk.Entry(master, width=15) 66 self.id_entry.place(x=310,y=20) 67 68 self.name_text = tk.Label(master, text="名前") 69 self.name_text.place(x=420,y=20) 70 self.name_entry = tk.Entry(master, width=15) 71 self.name_entry.place(x=460,y=20) 72 73 self.site_text = tk.Label(master, text="部位") 74 self.site_text.place(x=120,y=60) 75 self.site_entry = tk.Entry(master, textvariable=site_var, width=15) 76 self.site_entry.place(x=160,y=60) 77 78 self.x_text = tk.Label(master, text="x") 79 self.x_text.place(x=120,y=100) 80 self.x_entry = tk.Entry(master, textvariable=x_var, width=7) 81 self.x_entry.place(x=140,y=100) 82 83 self.y_text = tk.Label(master, text="y") 84 self.y_text.place(x=210,y=100) 85 self.y_entry = tk.Entry(master, textvariable=y_var, width=7) 86 self.y_entry.place(x=230,y=100) 87 88 self.z_text = tk.Label(master, text="z") 89 self.z_text.place(x=300,y=100) 90 self.z_entry = tk.Entry(master, textvariable=z_var, width=7) 91 self.z_entry.place(x=320,y=100) 92 93 94class User2(tk.Frame): 95 def __init__(self,master,num): 96 super().__init__(master) 97 master.geometry("670x520") 98 master.title(u"新規患者登録/修正") 99 100 self.id_text = tk.Label(master, text="ID") 101 self.id_text.place(x=20,y=20) 102 self.id_entry = tk.Entry(master, textvariable=id_var, width=18) 103 self.id_entry.place(x=80,y=20) 104 105 self.name_text = tk.Label(master, text="名前") 106 self.name_text.place(x=20,y=60) 107 self.name_entry = tk.Entry(master, textvariable=name_var, width=18) 108 self.name_entry.place(x=80,y=60) 109 110 self.age_text = tk.Label(master, text="年齢") 111 self.age_text.place(x=20,y=100) 112 self.age_entry = tk.Entry(master, textvariable=age_var, width=18) 113 self.age_entry.place(x=80,y=100) 114 115 self.gen_text = tk.Label(master, text="性別") 116 self.gen_text.place(x=20,y=140) 117 self.gen_entry = tk.Entry(master, textvariable=gen_var, width=18) 118 self.gen_entry.place(x=80,y=140) 119 120 self.hei_text = tk.Label(master, text="身長 (cm)") 121 self.hei_text.place(x=20,y=180) 122 self.hei_entry = tk.Entry(master, textvariable=hei_var, width=18) 123 self.hei_entry.place(x=80,y=180) 124 125 self.wei_text = tk.Label(master, text="体重 (kg)") 126 self.wei_text.place(x=20,y=220) 127 self.wei_entry = tk.Entry(master, textvariable=wei_var, width=18) 128 self.wei_entry.place(x=80,y=220) 129 130 self.button = tk.Button(master, text='保存', command=MakeList, height=2, width=10) 131 self.button.place(x=200, y=300) 132 133#originalデータフレームを新たに得られた値を追加し更新したい 134#pt_datを返してdfの更新を外で記述したほうが良いのか? 135#その際はどこに書くのかがわかりません 136def MakeList(): 137 idnum = id_var.get() 138 name = name_var.get() 139 age = age_var.get() 140 gen = gen_var.get() 141 hei = hei_var.get() 142 wei = wei_var.get() 143 site = site_var.get() 144 x = x_var.get() 145 y = y_var.get() 146 z = z_var.get() 147 pt_dat = pd.Series(["idnum","name", age, "gen", hei, wei, "site", x, y, z], index =["ID","名前","年齢","性別","身長 (cm)","体重 (kg)","部位","x","y","z"]) 148 df = df.append(pt_dat, ignore_index=True ) 149 print(df) 150 151def main(): 152 win = tk.Tk() 153 app = Application(win) 154 app.mainloop() 155 156 157if __name__ == '__main__': 158 main()

投稿2020/04/07 20:07

PeroNyago

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teamikl

2020/04/08 15:19

ソースの全体像を見て気づいた点があります。 これから作りこむところなのかもしれませんが。 - User1 と User2 の2つのウィンドウがあり - MakeList 関数では双方の 入力 を参照していますが、 片方が未入力になったり、前の値が残る状態になったりするので、 初日に登録するデータと、日々の蓄積するデータは別のテーブルに別けた方が良いでしょう。 「データベース 正規化」で調べると、データ構造(テーブル)の設計の仕方等の参考になると思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問