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

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

ただいまの
回答率

88.93%

【Python】wxPythonで入力したテキストをファイルに保存させたい。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,507

Python.R

score 28

現在自分の使っている各種プログラミング言語の文法をまとめて確認できるツールを作っています。
見た目は下記の通りです。
ツールのレイアウト
タブごとに言語が並んでおり、最後のタブにテキストエリアを設けています。
テキスト入力エリア
そして画面下に入力したテキストを保存するボタンを配置しました。

ここからが問題でした。ボタンを配置したは良いが、Bindメソッドを使いどのように、イベントとテキスト情報を取得し、関数で処理をさせるか?
詳しい方いましたら、ぜひ知恵を貸していただきたいです。

ちなみに、私はまだクラスを用いた複雑な設計は理解できないことが多く、まだ難しいです。

以下が書いたコードになります。できるだけ、コードをするなくしようと努力しましたが、現時点で200行以上あります。

コード

import wx
import os
import glob
from mutagen.mp3 import MP3 as mp3
import pygame

class Prog_lgs():
    def python_button_func(event): # Python用の関数を宣言
        pygame.mixer.init()
        pygame.mixer.music.load('md\\nc106374.wav')
        pygame.mixer.music.play(1)
        if event.GetId() == 3:
            os.system('data\\py\\3_list_and_loop.txt')
        elif event.GetId() == 4:
            os.system('data\\py\\4_function_and_module.txt')
        elif event.GetId() == 1:
            os.system('data\\py\\1_variable.txt')
        elif event.GetId() == 2:
            os.system('data\\py\\2_input_and_if.txt')
        elif event.GetId() == 5:
            os.system('data\\py\\5_file_control.txt')
        elif event.GetId() == 6:
            os.system('data\\py\\6_text_control.txt')
        elif event.GetId() == 7:
            os.system('data\\py\\7_recall_function.txt')
        elif event.GetId() == 8:
            os.system('data\\py\\8_COM_Sapi.txt')
        elif event.GetId() == 9:
            os.system('data\\py\\9_CSV_database_control.txt')
        elif event.GetId() == 10:
            os.system('data\\py\\10_time_method.txt')
        elif event.GetId() == 11:
            os.system('data\\py\\11_key_event.txt')
        elif event.GetId() == 12:
            os.system('data\\py\\12_sort_algorithm.txt')
    def c_button_func(event):  # C言語用の関数を宣言
        if event.GetId() == 200:
            os.system('data\\c\\1_variable.txt')
        elif event.GetId() == 201:
            os.system('data\\c\\2_list_and_loop.txt')
        elif event.GetId() == 202:
            os.system('data\\c\\3_input_and_if.txt')
        elif event.GetId() == 203:
            os.system('data\\c\\4_file_control.txt')
        elif event.GetId() == 204:
            os.system('data\\c\\5_pointer_and_function.txt')
    def java_button_func(event):  # Java用の関数を宣言
        if event.GetId() == 400:
            os.system('data\\java\\1_kihon.txt')
        elif event.GetId() == 401:
            os.system('data\\java\\2_input.txt')
        elif event.GetId() == 402:
            os.system('data\\java\\3_if.txt')
        elif event.GetId() == 403:
            os.system('data\\java\\4_loop.txt')
        elif event.GetId() == 404:
            os.system('data\\java\\5_list.txt')
        elif event.GetId() == 405:
            os.system('data\\java\\6_sqpow.txt')

#プロンプトで表示するように作った関数です
def save_text(tmp):
    print(tmp)

def run_music():
    pygame.mixer.init()
    pygame.mixer.music.load('md\\mens-ou1.mp3') #音源を読み込み
    #再生開始。1の部分を変えるとn回再生(その場合は次の行の秒数も×nすること)
    pygame.mixer.music.play(1)

application = wx.App()
frame = wx.Frame(None, wx.ID_ANY, 'プログラミング言語文法確認ツール', size=(700, 450))
run_music()
frame.CreateStatusBar()
#image = wx.Image('img\\background.jpg')
#bitmap = image.ConvertToBitmap()
icon = wx.Icon('img\\tool_logo.ico',wx.BITMAP_TYPE_ICO)
frame.SetIcon(icon)

notebook = wx.Notebook(frame, wx.ID_ANY)

#それぞれのパネルにnotebook(タブ)の属性を付与する
panel_1 = wx.Panel(notebook, wx.ID_ANY)
panel_2 = wx.Panel(notebook, wx.ID_ANY)
panel_3 = wx.Panel(notebook, wx.ID_ANY)
panel_4 = wx.Panel(notebook, wx.ID_ANY)
panel_5 = wx.Panel(notebook, wx.ID_ANY)

#タブパネルごとのバックグラウンドカラーを指定
panel_1.SetBackgroundColour('#BCF5F1')
panel_2.SetBackgroundColour('#F2C0BC')
panel_3.SetBackgroundColour('#F3ECAF')
panel_4.SetBackgroundColour('#ADEDB2')
panel_5.SetBackgroundColour('#B1BDF6')

#タブメニュー文字列の表示を指定
notebook.InsertPage(0, panel_1, 'Python')
notebook.InsertPage(1, panel_2, 'C言語')
notebook.InsertPage(2, panel_3, 'Java')
notebook.InsertPage(3, panel_4, 'VBS')
notebook.InsertPage(4, panel_5, 'メモエリア')

# それぞれのタブにアイコンを設定する
image_list = wx.ImageList(30, 30)
image_list_bata = sorted(glob.glob(".\\img\\tab_icon\\*.ico"))
for i in range(len(image_list_bata)):
    icon = wx.Icon(image_list_bata[i], wx.BITMAP_TYPE_ICO)
    image_list.Add(icon)
notebook.AssignImageList(image_list)
for i in range(len(image_list_bata)):
    notebook.SetPageImage(i, i)

# パネル5のテキストボックス
text_main = wx.TextCtrl(panel_5, wx.ID_ANY, style = wx.TE_MULTILINE)
text_main.SetBackgroundColour('#0D0D0D')
text_main.SetForegroundColour('#FFFFFF')

#####################################
#   ボタンの戻り値と表示文字列の指定
#####################################
# Pythonタブ用
button_1_py = wx.Button(panel_1, 1, '変数')
button_2_py = wx.Button(panel_1, 2, '入力と\n条件分岐')
button_3_py = wx.Button(panel_1, 3, 'リストとループ')
button_4_py = wx.Button(panel_1, 4, '関数と\nモジュール')
button_5_py = wx.Button(panel_1, 5, 'ファイル操作')
button_6_py = wx.Button(panel_1, 6, 'テキスト処理\n(乱数・正規表現)')
button_7_py = wx.Button(panel_1, 7, '再起呼出\n(2進数計算)')
button_8_py = wx.Button(panel_1, 8, 'COM(Sapi)')
button_9_py = wx.Button(panel_1, 9, 'CSVメソッド\nデータベース処理')
button_10_py = wx.Button(panel_1, 10, 'timeメソッド\n(時間制御)')
button_11_py = wx.Button(panel_1, 11, 'getchメソッド\n(キー操作)')
button_12_py = wx.Button(panel_1, 12, 'ソート\nアルゴリズム')
python_button = [button_1_py, button_2_py, button_3_py, button_4_py, button_5_py, 
button_6_py, button_7_py, button_8_py, button_9_py, button_10_py, button_11_py, 
button_12_py]
# C言語タブ用
button_1_c = wx.Button(panel_2, 200, '変数\n(基礎文法)')
button_2_c = wx.Button(panel_2, 201, 'リストとループ')
button_3_c = wx.Button(panel_2, 202, '入力と\n条件分岐')
button_4_c = wx.Button(panel_2, 203, 'ファイル操作')
button_5_c = wx.Button(panel_2, 204, 'ポインタと関数')
c_button = [button_1_c, button_2_c, button_3_c, button_4_c, button_5_c]
# Javaタブ用
button_1_java = wx.Button(panel_3, 400, '基本文法')
button_2_java = wx.Button(panel_3, 401, '入力')
button_3_java = wx.Button(panel_3, 402, '条件分岐')
button_4_java = wx.Button(panel_3, 403, 'ループ処理')
button_5_java = wx.Button(panel_3, 404, 'リスト・配列')
button_6_java = wx.Button(panel_3, 405, '平方根・累乗')
java_button = [button_1_java, button_2_java, button_3_java, button_4_java, 
button_5_java, button_6_java]

#保存ボタンを生成
test_button = wx.Button(panel_5, wx.ID_ANY, '保存', size = (0, 50))

#################################
#     フォントサイズの指定
#################################
font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
for i in range(len(python_button)):
    python_button[i].SetFont(font)
for i in range(len(c_button)):
    c_button[i].SetFont(font)
for i in range(len(java_button)):
    java_button[i].SetFont(font)
notebook.SetFont(font) # タブ全体のフォントサイズ指定
text_main.SetFont(font)

################################$
#   ボタンクリック時の動作を指定
#################################
for i in range(len(python_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.python_button_func, python_button[i])
for i in range(len(c_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.c_button_func, c_button[i])
for i in range(len(java_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.java_button_func, java_button[i])

#入力したテキストを取得したかった。
tmp = text_main.GetValue()
test_button.Bind(wx.EVT_BUTTON, save_text(tmp))

#################################
#   ボタン配置のレイアウトを指定
#################################
layout_py = wx.GridSizer(rows=5, cols=3, gap=(0, 0))
for i in range(len(python_button)):
    layout_py.Add(python_button[i], 0, wx.GROW)
layout_c = wx.GridSizer(rows=5, cols=3, gap=(0, 0))
for i in range(len(c_button)):
    layout_c.Add(c_button[i], 0, wx.GROW)
layout_java = wx.GridSizer(rows=5, cols=3, gap=(0, 0))
for i in range(len(java_button)):
    layout_java.Add(java_button[i], 0, wx.GROW)
layout_textbox = wx.BoxSizer(wx.VERTICAL)
layout_textbox.Add(text_main, 1, wx.EXPAND|wx.ALL)
layout_textbox.Add(test_button, 0, wx.EXPAND|wx.ALL)
panel_1.SetSizer(layout_py)
panel_2.SetSizer(layout_c)
panel_3.SetSizer(layout_java)
panel_5.SetSizer(layout_textbox)

frame.Centre()
frame.Show()
# wx.StaticBitmap(panel_1, 1, bitmap, pos=(0, 0), size=panel_1.GetSize())
application.MainLoop()

やったこと

まずパネル5でテキストボックスを生成

# パネル5のテキストボックス
text_main = wx.TextCtrl(panel_5, wx.ID_ANY, style = wx.TE_MULTILINE)
text_main.SetBackgroundColour('#0D0D0D')
text_main.SetForegroundColour('#FFFFFF')


そしてボタンを生成

#保存ボタンを生成
test_button = wx.Button(panel_5, wx.ID_ANY, '保存', size = (0, 50))


それとレイアウトは、コード後半で行っています。

とりあえずここまではできたのですが、ボタンクリック時の動作を関数でそう処理すればようかわかりません。

試したこと

試したことといっても、

#プロンプトで表示するように作った関数です
def save_text(tmp):
    print(tmp)

・・・・中略・・・・

#入力したテキストを取得したかった。
tmp = text_main.GetValue()
test_button.Bind(wx.EVT_BUTTON, save_text(tmp))


これでまず入力したテキストを確認しようとしたが、ボタンを押しても反応なし。

解決したいこと

冒頭で書いたとおり、入力したテキストをファイルに保存するところまでいきたいです。

また、ファイルに保存するコードは以前作ったものを組み込もうと思います。

app = wx.App()
        frame_b = wx.Frame(None, wx.ID_ANY, 'ファイル参照', size=(700, 450))
        panel_b = wx.Panel(frame_b, wx.ID_ANY)
        folder = wx.DirDialog(panel_b,style=wx.DD_CHANGE_DIR,message="保存先フォルダ")
        if folder.ShowModal() == wx.ID_OK:
            folder = folder.GetPath()
            with codecs.open(f'{folder}\\test.txt', 'w', encoding = "shift_jis") as f:
                f.write('test')
                f.close()
app.MainLoop()

非常に長くなってしまし、申し訳ないです。現役の方も含め、お力添えしていただけると幸いです。

補足

・一時ファイル
イメージ説明
・完成
イメージ説明

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

質問者さんが造りたいものを実現するまでもう少しだと思いましたので、回答としてはボタンを押したときのイベントハンドラーの使い方を簡単に説明させていただくことにとどめます。

test_button.Bind(wx.EVT_BUTTON, save_text(tmp))で惜しいのですが、この場合、save_text関数に渡される引数の内容はあらかじめ決まっていて、その引数の内容は実際にクリックされた時に決まります。wxPython - Events and Event Handling

ではどうしたらいいのかと言うと、ボタンであるtest_buttonボタンがクリックされたときに呼び出されるようsave_text関数をBind(結び付け)した訳ですから、savet_text関数の中で改めてtext_mainを操作し、入力されたテキストを取得するようにしなければなりません。具体的なコードは以下のようになります。質問者さんのコードを流用し、必要なところを抜粋(一部修正)したものを全部掲載しますので見てみてください。

import wx

# パネル5のテキストボックスをグローバルで
text_main = None

#プロンプトで表示するように作った関数です
#def save_text(tmp):
#    print(tmp)

# イベントハンドラーを定義
# ※このイベントハンドラーに渡される引数はあらかじめ決まっている
def save_text(event):
    content = ''
    #入力したテキストを取得
    if text_main is not None:
        # (安全の為)作成済みであればTextControlの値を取得
        content = text_main.GetValue()

    print('save_textが呼ばれた!!')
    print(content)
    # ここで好きにファイルへ保存すればよい


application = wx.App()
frame = wx.Frame(None, wx.ID_ANY, 'プログラミング言語文法確認ツール')

panel_5 = wx.Panel(frame, wx.ID_ANY)

text_main = wx.TextCtrl(panel_5, wx.ID_ANY, style = wx.TE_MULTILINE)

#保存ボタンを生成
test_button = wx.Button(panel_5, wx.ID_ANY, '保存')

#入力したテキストを取得したかった。
#ここではダメ tmp = text_main.GetValue()
#これではダメ test_button.Bind(wx.EVT_BUTTON, save_text(tmp))
test_button.Bind(wx.EVT_BUTTON, save_text)

layout_textbox = wx.BoxSizer(wx.VERTICAL)
layout_textbox.Add(text_main, 1, wx.GROW)
layout_textbox.Add(test_button, 0, wx.GROW)
panel_5.SetSizer(layout_textbox)

frame.Show()

application.MainLoop()

実際に動作させた例です。linuxであるUbuntu 16.04 上(python3.5.2 + wxPython 4.0.0.b1)ですが、windows環境でも同じなはずです。

Ubuntu16.04上での動作例

ファイルに保存する方法はほぼ目処がついておられるようですのでここでは述べないことにします。もう少しだと思うので、ぜひ頑張ってください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/12/30 00:14

    無事完成しました。ヒントをくださり、ありがとうございます。
    完成したコードは下記の通りです。
    すみません、文字数オーバーなので、一部削除。
    大幅に処理形態を改良しました。
    ```Python

    ・・・・上記コード省略・・・・

    # テキストをリアルタイムで取得し、一時ファイルへ格納
    def save_text(event):
    obj = event.GetEventObject()
    obj = obj.GetValue()
    frame.SetStatusText('文字カウント:'+ str(len(obj)) +" 字 | Made by RYUKI.Y")
    with open('.\\tmp\\tmp.txt', 'w') as f:
    f.write(obj)
    f.close()

    # 一時ファイルからテキストファイル新規作成した後、一時ファイル初期化
    def save_text_file(event):
    add_text = []
    with open('.\\tmp\\tmp.txt', 'r') as f:
    for read_text in f:
    add_text.append(read_text)
    f.close()
    app = wx.App()
    frame_b = wx.Frame(None, wx.ID_ANY, 'ファイル参照', size=(700, 450))
    panel_b = wx.Panel(frame_b, wx.ID_ANY)
    panel_b_a = wx.Panel(frame_b, wx.ID_ANY)
    panel_b_b = wx.Panel(frame_b, wx.ID_ANY)
    folder = wx.DirDialog(panel_b,style = wx.DD_CHANGE_DIR,message="保存先のディレクトリー(パス)")
    if folder.ShowModal() == wx.ID_OK:
    dirs = folder.GetPath()
    folder.Destroy()
    dlg = wx.TextEntryDialog(panel_b_a, 'ファイル名を拡張子含めて入力してください。','ファイル名の入力')
    dlg.SetValue("ファイル名を入力")
    if dlg.ShowModal() == wx.ID_OK:
    filename = dlg.GetValue()
    with open(dirs + "\\" + filename, 'w') as f:
    for line in add_text:
    f.write(line)
    f.close()
    dlg = wx.MessageDialog(panel_b_b, "ファイルを作成しました。",
    "確認のメッセージ")
    dlg.ShowModal()
    dlg.Destroy()
    with open('.\\tmp\\tmp.txt', 'w') as f:
    f.close()
    app.MainLoop()


    def run_music():
    pygame.mixer.init()
    pygame.mixer.music.load('md\\mens-ou1.mp3') #音源を読み込み
    #再生開始。1の部分を変えるとn回再生(その場合は次の行の秒数も×nすること)
    pygame.mixer.music.play(1)

    ・・・中略・・・

    # パネル5のテキストボックス
    text_main = wx.TextCtrl(panel_5, wx.ID_ANY, "ここに入力", style = wx.TE_MULTILINE)
    text_main.SetBackgroundColour('#0D0D0D')
    text_main.SetForegroundColour('#FFFFFF')

    ・・・・中略・・・・・

    # パネル5のテキストエリアにおける内容の保存
    text_button = wx.Button(panel_5, 3000, 'ファイルに保存', size = (0, 40))

    ・・・中略・・・・

    ################################$
    # ボタンクリック時の動作を指定
    #################################
    for i in range(len(python_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.python_button_func, python_button[i])
    for i in range(len(c_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.c_button_func, c_button[i])
    for i in range(len(java_button)):
    frame.Bind(wx.EVT_BUTTON, Prog_lgs.java_button_func, java_button[i])
    text_button.Bind(wx.EVT_BUTTON, save_text_file)

    ######################################
    # テキストエリアでの入力時の動作
    ######################################
    text_main.Bind(wx.EVT_TEXT, save_text)

    ・・・以下省略・・・・

    ```
    テキストを入力するとまず、一時ファイル「tmp」にリアルタイムで格納され、
    ![一時ファイル](baf3f134a711bd2a4d66b370af109fd9.png)
    ツールの「ファイルを保存」ボタンを押すと、ファルダー参照画面とファイル名入力ダイアログを立ち上げるようにしました。ファイルの保存は成功です。
    ![完成](f9650c86ba1ab4a591e4277625f9448d.png)
    今回リアルタイム処理をしたのは、文字数をステータスバーに表示したかったからです。
    少し回りくどいことをしているように見えると思いますが、許してください。

    キャンセル

  • 2018/12/30 00:18

    すみません、画像は本文に補足しました。

    キャンセル

  • 2018/12/30 00:33

    その後の修正内容も示してくださり、ありがとうございます。
    自分の思い通りに作れると楽しいですよね。完成おめでとうございます。

    キャンセル

  • 2018/12/30 08:22

    そうですね!ありがとうございます。
    どんどんしたいことが増えていきそうです(!
    徐々にwxPythonについても理解してきたので、これからどんどん使い込んで行きたいです。

    それと、pyinstallerを使い、これから実行形式に変換しようと思います。

    キャンセル

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

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

関連した質問

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