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

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

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

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

Python

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

Q&A

解決済

1回答

2348閲覧

チェックボックスの判定が取得できない

asibarai

総合スコア6

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/09/05 09:08

前提・実現したいこと

tkinterを用いて、任意のwordファイルから出力する要素(文字、画像、表)を選択してGUI_extra_out.docxというファイルに出力するプログラムの作成をしており、追加機能として文字要素を出力する際に出力する段落も選択できるようにしようと思っています。
しかし、段落ごとのチェックボックスの判定を受け取ろうとした所、判定を受け取ることができず、チェックを入れても”False”のままになってしまいます。

質問で聞くにはやや長めのコードにはなってしまいますが、どうかご助力いただきたいです。

実行結果

<docx.document.Document object at 0x000002AA3C0C1E00>
sub_element
all_text: ['あいうえお', 'かきくけこ']
checkbox_element 2
bln_text: {0: <tkinter.BooleanVar object at 0x000002AA3B0DF790>, 1: <tkinter.BooleanVar object at 0x000002AA3B0DFEB0>}
OKクリック
text_select
bln_text: 2
all_text: ['あいうえお', 'かきくけこ']
bln_text [0] : False
bln_text [1] : False

該当のソースコード

python

1import tkinter 2import os 3from tkinter import ttk 4from tkinter import filedialog 5from tkinter import messagebox 6from docx import Document 7import docx 8from tika import parser 9import io 10import re 11import tabula 12from docx.shared import Cm 13import zipfile 14from pathlib import Path 15from io import FileIO 16import numpy as np 17import pandas as pd 18import docx2txt 19import sys 20 21# ファイル読み込み 22doc = docx.Document() 23doc_n = docx.Document() # 出力用に新ファイル生成 24 25all_text = [] 26def txt_file(): 27 ad = str(file_box.get()) #tkinterの型から只の文字列に変換 28 doc=docx.Document(ad) #パスセット 29 #all_text = [] 30 for para in doc.paragraphs: 31 all_text.append(para.text) 32 tuple(all_text) 33 print("all_text:",all_text) 34 35 36def ask_file(): 37 root = tkinter.Tk() # ウィンドウ生成 38 root.withdraw() # rootを非表示 39 fTyp = [("", "*.docx")] # [("ファイル","*.拡張子")] 40 iDir = os.path.abspath(os.path.dirname(__file__)) # 絶対パスを返す 41 # ファイルダイアログ表示後、ファイル選択⇒wordファイルの絶対パス(iDir)を指定 42 file = tkinter.filedialog.askopenfilename(filetypes=fTyp, initialdir=iDir) 43 file_box.delete(0, tkinter.END) # テキスト初期化 44 file_box.insert(tkinter.END, file) # テキスト追加 45 path = file_box.get() 46 doc = Document(path) 47 print(doc) 48 49 50def text_extration(t): # テキスト抽出 51 global text_ex 52 file_data = parser.from_file(file_box.get()) 53 text_ex = file_data["content"] 54 text_ex = text_ex.strip() 55 pattern = r"\n" 56 matchOB = re.match(pattern, text_ex) 57 58 txt_file(text_ex) 59 60 return text_ex 61 62 63def image_extration(i): # 画像抽出 64 docx_path = Path(file_box.get()) 65 # docxをZIP形式のファイルとして開く 66 docx_zip = zipfile.ZipFile(docx_path) 67 # docxの中にあるファイル一覧を取得 68 zipped_files = docx_zip.namelist() 69 # 保存するフォルダー 70 img_dir = Path("doc_images") 71 img_dir.mkdir(exist_ok=True) 72 # ファイルを1つずつ表示 73 for file in zipped_files: 74 # 画像ファイルだけ選別 75 if file.startswith("word/media/"): 76 print(file) 77 img_file = docx_zip.open(file) 78 img_bytes = img_file.read() 79 # 画像ファイルの先頭に「docxファイル名を先頭につける」 80 img_path = img_dir / (docx_path.stem + "_" + Path(file).name) 81 # 画像ファイルの保存 82 with img_path.open(mode="wb") as f: 83 f.write(img_bytes) 84 return img_file 85 86 87def table_extration(): # 表抽出 88 i = 0 89 tbl_path = Document(file_box.get()) 90 print(file_box.get()) # 91 tbl = tbl_path.tables[0] # 1つ目の表要素を抽出 92 table1 = doc_n.add_table(rows=len(tbl.rows), cols=len(tbl.columns)) # 表の作成 93 for row in tbl.rows: # rowsでテーブルの行を取得し、rowに格納し(row={1行目、2行目、3行目、...})、行の数だけ繰り返し 94 values = [] 95 for cell in row.cells: # 例)row[0]であれば、row[0](1行目)の各セル要素を取得し、その行のセルの数(列数)だけ繰り返し 96 values.append(cell.text) # 取得したセルの文字列を追加 97 r = table1.rows[i] # 行にアクセス 98 i += 1 99 for a in range(len(tbl.columns)): 100 r.cells[a].text = values[a] # 現在の行の各セルに要素を挿入 101 print(values) # 出力 102 103 104def extration(): # 各要素抽出,抽出ボタンクリック時 105 106 print("extration") 107 if (bln1.get() == True): # bln1=="text"checkbox 108 print(len(bln_text)) 109 text = txt_file() # テキスト抽出 110 for a in range(len(all_text)):#all_text=段落 111 doc_n.add_paragraph(all_text[a])#段落追加 112 # --------------------------- 113 if (bln2.get() == True): # bln2=="image"checkbox 114 img_file = image_extration(1) # 画像抽出 115 doc_n.add_picture(img_file) 116 # --------------------------- 117 if (bln3.get() == True): # bln3=="table"checkbox 118 table_extration() # 表抽出 119 doc_n.save("GUI_extra_out.docx") 120 print("抽出完了") 121 122 main_win.quit() 123 124 125 126 127def text_select():#OKボタンクリック時 128 print("OKクリック") 129 print("text_select") 130 print("bln_text:",len(bln_text)) 131 print("all_text:",all_text) 132 for a in range(len(all_text)): 133 print("bln_text",[a],":",bln_text[a].get())#チェックボックス状態確認 134 if bln_text[a].get() == True: 135 doc_n.add_paragraph(all_text[a]) # 段落追加 136 doc_n.save("GUI_extra_out.docx") 137 138bln_text = {}#判定 139 140def sub_element(): 141 print("sub_element") 142 143 #=====ウィンドウ準備=== 144 sub_win=tkinter.Tk() 145 sub_win.title("テキスト要素選択") 146 sub_win.geometry("600x200") 147 sub_frm=ttk.Frame(sub_win) 148 sub_frm.grid(column=0, row=0, sticky=tkinter.NSEW, padx=5, pady=10) 149 #=========== 150 151 txt_file()#段落要素抽出 152 checkbox_element = [] # チェックボックス 153 154 for e in range(len(all_text)):#段落の数だけ~~ 155 checkbox_element.append(all_text[e]) # ~チェックボックス生成 156 bln_text[e] = tkinter.BooleanVar() # チェックボックス判定 157 if all_text[e]=="":#その段落が何もないならcontinue 158 continue 159 160 checkbox_element[e] = tkinter.Checkbutton\ 161 (sub_frm, variable=bln_text[e],text=all_text[e]) 162 163 checkbox_element[e].grid(column=0, row=e) 164 165 print("checkbox_element", len(checkbox_element)) 166 167 # OKボタン作成(extrationに飛ぶ) 168 OK_btn = ttk.Button(sub_frm, text="OK", command=text_select) 169 OK_btn.grid(column=0, row=e+1, sticky=tkinter.NSEW, padx=5, pady=10) 170 171 print("bln_text:",bln_text) 172 173 sub_win.columnconfigure(0, weight=1) # (ウィンドウの拡大に合わせて変化するか、weight) 174 sub_win.rowconfigure(0, weight=1) 175 sub_frm.columnconfigure(1, weight=1) 176 sub_win.mainloop() 177 178def main(): 179 global main_win, file_box, bln1, bln2, bln3 180 # メインウィンドウ 181 main_win = tkinter.Tk() 182 main_win.title("原稿") 183 main_win.geometry("600x200") 184 # メインフレーム 185 main_frm = ttk.Frame(main_win) 186 main_frm.grid(column=0, row=0, sticky=tkinter.NSEW, padx=5, pady=10) # padx=左右の余白,pady=上下の余白 187 # ウィジェット作成(ファイルパス) 188 folder_label = ttk.Label(main_frm, text="ファイル指定") 189 file_box = ttk.Entry(main_frm) 190 file_btn = ttk.Button(main_frm, text="参照", command=ask_file) 191 # ウィジェット作成(抽出ボタン) 192 app_btn = ttk.Button(main_frm, text="抽出", command=extration) 193 194 ####============== 195 text_select_btn = ttk.Button(main_frm, text="段落選択", command=sub_element) 196 ####=================== 197 198 # チェック有無変数 199 bln1 = tkinter.BooleanVar() 200 bln2 = tkinter.BooleanVar() 201 bln3 = tkinter.BooleanVar() 202 # value=0のチェックボックスにチェックを入れる 203 bln1.set(1) 204 bln2.set(1) 205 bln3.set(1) 206 # ラベル 207 lb1 = tkinter.Label(text="要素抽出") 208 # チェックボックス作成 209 check1 = tkinter.Checkbutton(main_frm, variable=bln1, text='text ') 210 check2 = tkinter.Checkbutton(main_frm, variable=bln2, text='image ') 211 check3 = tkinter.Checkbutton(main_frm, variable=bln3, text='table ') 212 # ウィジェットの配置 213 folder_label.grid(column=0, row=0, pady=10) 214 file_box.grid(column=1, row=0, sticky=tkinter.EW, padx=5) 215 file_btn.grid(column=2, row=0) 216 check1.grid(column=0, row=3) 217 check2.grid(column=0, row=4) 218 check3.grid(column=0, row=5) 219 app_btn.grid(column=1, row=6) 220 221 text_select_btn.grid(column=2,row=6) 222 # 配置設定 223 main_win.columnconfigure(0, weight=1) # (ウィンドウの拡大に合わせて変化するか、weight) 224 main_win.rowconfigure(0, weight=1) 225 main_frm.columnconfigure(1, weight=1) 226 main_win.mainloop() 227 228 229main() 230 231

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

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

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

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

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

guest

回答1

0

ベストアンサー

問題を再現する最小限のコードを作成できますか?
チェックボックスのみを使い、問題を再現するコードは出来るでしょうか。

個人的には、長いコード掲載で問題ないのですが、(変に省略されるよりは良いです)
ある程度の規模になると コードの実行に必要な「依存ライブラリのインストール」や
「実行に使うデータの作成」が手間になるので、まずは問題の範囲を絞り込むべきだと思います。


一応、原因に心当たりはあるので、問題を再現するコード
(提示されたコードの実行は出来てないので、他の部分の問題は解りません。チェックボックス関連のみ)

python

1#!/usr/bin/env python3.8 2 3 4import tkinter as tk 5 6 7bln_var = {} 8 9def main(): 10 root = tk.Tk() # <--- 問題点 11 12 bln_var[1] = tk.BooleanVar() # <-- tk.BooleanVar(master=root) 13 14 def onclick(): 15 print(bln_var[1].get()) 16 17 checkbox = tk.Checkbutton(root, text="var", variable=bln_var[1]) 18 checkbox.pack() 19 button = tk.Button(root, text="Check", command=onclick) 20 button.pack() 21 22 root.mainloop() 23 24if __name__ == '__main__': 25 # このコードは、main() を直接呼び出すと問題ありませんが、 26 # 以下の様に入れ子のような状況で Tk() を複数回呼び出すと発生します。 27 28 root = tk.Tk() 29 tk.Button(root, text="Open", command=main).pack() 30 root.mainloop()

暫定的な回避策:

  • tk.BooleanVar(root) とする事でも、期待する結果は得られます

 が根本的な解決にはなりません。同様の問題が起こる可能性があります。

解決策:

  • Tk() の作成と mainloop() は、原則としてプログラム内で一度とします。
  • サブウィンドウの作成には、tkinter.Toplevel を使います。

 サブウィンドウでは mainloop() の代わりに、wait_window()
詳しくはダイアログの作成方法を調べて下さい。

詳細
tkinter.BooleanVar() と呼び出したときに、デフォルトの root オブジェクトが使われるのですが、
これが、tkinter内のグローバル変数となっていて、tkinter.Tk を複数回呼び出すと、
この関係が壊れてしまうために起こります。

なので、tk.BooleanVar(master=root) というように明示的に指定することで、
問題回避は出来るのですが、この問題は全てのtkinterのウィジェットで起こり得ます。
複数のウィンドウ(ダイアログ)が必要な場合は、TkとToplevelを使い分ける方法をお勧めします。

投稿2020/09/05 10:58

teamikl

総合スコア8664

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

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

asibarai

2020/09/05 16:18

丸投げのような質問をしてしまったにも関わらず丁寧にご回答いただきありがとうございます。 ウィンドウの作成にもメインやサブのような位置付けがされるのですね。 回答いただいたように、サブウィンドウ作成にToplevelを使うことで解決できました。 プログラムのコードに関しても、今後質問投稿をする際には最低限のコードの掲載にするように心がけます。 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問