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

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

ただいまの
回答率

88.58%

チェックボックスが全部選択されてしまう

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 878

yep

score 45

csvのcolumnsを動的に取得できたら便利だなと思い書いたのですが、
チェックボタンの選択で一個、一個が独立してチェックできるのではなく
一回押したら全部の欄にチェックがついていしまい困っています。

import os,sys
from tkinter import *
import tkinter
from tkinter import filedialog
from fir_win import sub_window3
import codecs
import pandas as pd

def func():
    sub_window3.func()


def file_search():
    root = tkinter.Tk()
    root.withdraw()
    fTyp = [("","*.csv")]
    iDir = os.path.abspath(os.path.dirname(__file__))
    filepath = filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)
    sub_win = Toplevel()
    with codecs.open(filepath, "r", "cp932", "ignore") as file:
        df = pd.read_table(file, delimiter=",", skipinitialspace=True)
        columns = df.columns.values
        col_var = tkinter.IntVar()
        for i in range(len(columns)):
            col = tkinter.Checkbutton(sub_win, variable=col_var, text=columns[i])<--全部チェックがついてしまいます。
            col.place(x=50, y=30 + (i * 24))
            num = col_var.get()
    label0 = tkinter.Label(sub_win,text=u'Data cleaning[.csv]')
    label0.place(x=5, y=5)
    sub_win.geometry("385x400")
    button2 = tkinter.Button(sub_win, text='Start!', command=func)
    button2.place(x=5, y=250)


もしご存知の方がいらっしゃれば、ご教授頂きたく存じます。

def do_something():
    sub_win = Toplevel()
    col_var = tkinter.IntVar()
    if col_vars[0].get():
        col_var = []
        for i, cn in enumerate(columns):
            col_var = tkinter.IntVar()
            col_vars.append(col_var)
            col = tkinter.Checkbutton(sub_win, variable=col_var, text=cn)
            col.place(x=50, y=30 + (i * 24))
    if col_vars[1].get():#繰り返し


KSwordOfHasteさんに教えていただいた情報を基に作成したインスタント部分です。
col_vars.append(col_var)
の部分でName is not definedになってしまいます。

追記:

from tkinter import *
import tkinter.ttk as ttk
import tkinter
import tkinter.filedialog as filedialog
import pandas as pd
import os,codecs

class FiledialogApp(ttk.Frame):

    def __init__(self, app):
        super().__init__(app)
        self.pack()

        self.filename = StringVar()

        label = ttk.Label(self,text="File>>")
        label.pack(side="left")
        filenameEntry = ttk.Entry(self,text="",textvariable= self.filename)
        filenameEntry.pack(side="left")

        button = ttk.Button(self,text="Select",command = self.openFileDialog)
        button.pack(side="left")

        button_c = ttk.Button(self, text="Close",command = quit)
        button_c.pack(side="left")

    def openFileDialog(self):
        # ファイルダイアログにより処理対象のファイルパスを選ばせる
        filepath  = filedialog.askopenfilename(filetypes=[(".csv","*.csv")]);
        self.filename.set(filepath)
        # ファイルを読み込む
        with codecs.open(filepath, "r", "cp932", "ignore") as file:
            df = pd.read_table(file, delimiter=",", skipinitialspace=True)
        columns = df.columns.values
        # データフレーム上の列数分だけ Checkbotton を生成すると仮定
        col_vars = []
        for i, column in enumerate(columns):
            col_var = tkinter.IntVar()
            col_vars.append(col_var)
            cb = ttk.Checkbutton(variable=col_var, text=column)
            cb.place(x=50, y=30 + (i * 24))

        # ボタンのハンドラー関数
        def on_start_button():
            for i, column in enumerate(columns):
                checked = 'checked' if col_vars[i].get() else 'is not checked'
                print(f"{column} column {checked}")
            # 必要に応じて何かする

        button_1 = ttk.Button(text='Start!', command=on_start_button)
        button_1.place(x=5, y=250)



if __name__ == '__main__':
    app  = Tk()
    app.geometry("400x300")
    app.title("Select your file[.csv]")
    frame = FiledialogApp(app)
    app.mainloop()


教えていただいたコードでgui画面を作ってみました。
正常に動きました。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

同一のIntVarインスタンスを全てのCheckbuttonで共有しているのが問題の原因です。個々のCheckbuttonそれぞれに別々のIntValueインスタンスを指定してください。またチェックボタンを配置したばかりで利用者がボタンを操作してもいない時点で
num = col_var.get()
とするのは意味がないと思います。チェックボタンの状態が必要になる時点で参照してください。

import tkinter as tk

...

def file_search():
    ...

    def do_something():
        if col_vars[0].get():
            # 最初のCheckbuttonがチェックされていた
            ...
        if col_vars[1].get()
            # 2番目のCheckbuttonがチェックされていた
            ...
        # 等々

    run_button = tk.Button(sub_win, text="run",
                           command=do_something)
    ...

    col_vars = []
    for i, cn in enumerate(columns):
        col_var = tk.IntVar()
        col_vars.append(col_var)
        col = tk.Checkbutton(sub_win, variable=col_var, text=cn)
        col.place(x=50, y=30 + (i * 24))
    ...

追記:

質問文にコードを追記していただいたのですが・・・自分の回答は質問者さんによく伝わらなかったようです。また、ボタンを押したときに呼び出されるハンドラー関数からどの範囲の変数が見えるか、ファイルダイアログを開いたりDataFrameをロードしたり、GUIの初期化をしたりといったもろもろの制御の流れをどう記述したらよいか等々についてはっきりとイメージできていないような印象でしたので、「何が問題でどうしたらよいか」という説明をするかわりに、単純な例を書いてみることにしました。下記を動かし動作を確認した上で個々のコードがどういうふうに動くのかを考えてみてはいかがでしょう?

スミマセンが、自分が不自然に感じた細々とした点は断りなしに変更させていただいています。

import os
import tkinter as tk
import tkinter.filedialog
import codecs
import pandas as pd


def main():
    root = tk.Tk()
    root.withdraw()

    # ファイルダイアログにより処理対象のファイルパスを選ばせる

    filetypes = [("", "*.csv")]
    initialdir = os.path.abspath(os.path.dirname(__file__))
    filepath = tk.filedialog.askopenfilename(filetypes=filetypes,initialdir=initialdir)

    # ファイルを読み込む
    with codecs.open(filepath, "r", "cp932", "ignore") as file:
        df = pd.read_table(file, delimiter=",", skipinitialspace=True)
    columns = df.columns.values

    # ウィンドウの初期化
    sub_win = tk.Toplevel()
    sub_win.geometry("385x400")

    # データフレーム上の列数分だけ Checkbotton を生成すると仮定
    col_vars = []
    for i, column in enumerate(columns):
        col_var = tk.IntVar()
        col_vars.append(col_var)
        cb = tk.Checkbutton(sub_win, variable=col_var, text=column)
        cb.place(x=50, y=30 + (i * 24))
        label0 = tk.Label(sub_win, text=u'Data cleaning[.csv]')
        label0.place(x=5, y=5)

    # ボタンのハンドラー関数
    def on_start_button():
        for i, column in enumerate(columns):
            checked = 'checked' if col_vars[i].get() else 'is not checked'
            print(f"{column} column {checked}")
        # 必要に応じて何かする

    button2 = tk.Button(sub_win, text='Start!', command=on_start_button)
    button2.place(x=5, y=250)
    root.mainloop()


if __name__ == '__main__':
    main()

もう少し追記:

最初の回答に書いたdo_somethingという関数名はわかりにくかったようなのでon_start_buttonという関数名に変えました。この関数の定義場所に注意してください。注意すべきはon_start_button関数を

(A)main関数の中で定義すること
(B)button2の生成より前に定義すること

です。(A)の理由はmain関数のローカル変数col_varsをon_start_buttonからアクセスするため。(B)の理由はButton生成のcommand引数には「その時点で関数が定義済みでないといけないから」です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/26 22:24

    すみません。直してみましたが分かりませんでした。

    キャンセル

  • 2019/04/27 00:13

    do_something関数だけ書いても質問者さんが自分の回答を咀嚼できているかどうか確認できません。多分咀嚼できていないような印象ですがはっきりしません。またfir_winモジュールなど「閲覧者に中身がわからないコードを前提としたプログラム」を提示するのは控えてください。問題の本質に無関係なところは削除し、提示したコードだけで動作する「完全なプログラム」を提示しましょう。そうするためには元のコードをより短い単純なものに変更する必要があります。質問者さんにとって面倒かも知れませんが、そういう配慮が「質問側へ確実にコードの意図を伝える」コツです。

    キャンセル

  • 2019/04/27 01:11

    とはいってみたものの、逆にコード例を私の方から提示してみることにしました。回答への追記部分のコードをご覧ください。こういう感じの「コピペすればそのまま試すことができる、完全なコード」を質問文に書いてほしかったのです。

    キャンセル

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

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る