wxPythonとwxFormBuilderを使用して
⑫ 画面遷移の処理を定義(最終回)【python tkinter sqlite3で家計簿を作る】 – memopy
こちらのアプリを真似してみました。
wxFormBuilderはpythonコードを書き出して、子classでごにょごにょするのが普通なのかもしれませんが、扱いづらいのでXRCでデザインを書き出して使用するようにしました。
参考アプリと違うところは日付はデートピッカー、入力画面はダイアログになっています。
sqliteは先にコマンドで作っています。
バリデーション等、必要ですが、とりあえず動く程度です。
XRCの処理は
wxPython & XRC で Custom Frame を作る方法3種 | 穀風
こちらを参考にしています。
実行例
メイン画面
ダイアログ画面
wxFormBuilder
構成
メイン画面
入力用ダイアログ
メインコード(kakeibo.py)
import wx import wx.xrc import wx.grid import wx.adv from dbSqliteClass import db_sqlite __res = None DB_NAME = 'kakeibo.db' def get_resources(): global __res if __res is None: __init_resources() return __res def __init_resources(): global __res __res = wx.xrc.XmlResource() __res.Load('kakeibo/kakeibo.xrc') class MyFrame(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self) get_resources().LoadFrame(self, parent, 'MyFrame') self.Bind(wx.EVT_CLOSE, self.quit_button) self.btn1 = wx.xrc.XRCCTRL(self, 'btn1') self.btn1.Bind(wx.EVT_BUTTON, self.create_button) self.btn2 = wx.xrc.XRCCTRL(self, 'btn2') self.btn2.Bind(wx.EVT_BUTTON, self.quit_button) self.btn3 = wx.xrc.XRCCTRL(self, 'btn3') self.kikan1 = wx.xrc.XRCCTRL(self, 'kikan1') self.kikan2 = wx.xrc.XRCCTRL(self, 'kikan2') self.btn3.Bind(wx.EVT_BUTTON, self.select_sql) self.gridTable = wx.xrc.XRCCTRL(self, 'gridTable') self.gridTable.CreateGrid(5,3) # Set column labels. self.gridTable.SetColLabelValue(0, '日付') self.gridTable.SetColLabelValue(1, '内訳') self.gridTable.SetColLabelValue(2, '金額') self.tableShow() def tableShow(self): # Set cell values. c = db_sqlite(DB_NAME) sql = ( 'select acc_date, item_name, amount from' ' acc_data as a, item as i where' ' a.item_code = i.item_code order by acc_date' ) acc = c.db_execute(sql).fetchall() i = 0 for row in range(len(acc)): self.gridTable.SetCellValue(row, 0, str(acc[i]['acc_date'])) self.gridTable.SetCellValue(row, 1, str(acc[i]['item_name'])) am = f"{acc[i]['amount']:,}" self.gridTable.SetCellValue(row, 2, str(am)) i += 1 self.gridTable.AutoSize() def create_button(self, e): adid = AddItemDialog(self) adid.ShowModal() adid.Destroy() def quit_button( self, event ): self.Destroy() def select_sql( self, event ): kikan1_d = self.kikan1.GetValue() kikan1 = kikan1_d.Format("%Y-%m-%d") kikan2_d = self.kikan2.GetValue() kikan2 = kikan2_d.Format("%Y-%m-%d") # Set cell values. self.gridTable.ClearGrid() c = db_sqlite(DB_NAME) sql = ( 'select acc_date, item_name, amount from' ' acc_data as a, item as i where' ' a.acc_date between ? and ?' ' and a.item_code = i.item_code order by acc_date' ) acc = c.db_execute_place(sql, (kikan1, kikan2)).fetchall() i = 0 for row in range(len(acc)): self.gridTable.SetCellValue(row, 0, str(acc[i]['acc_date'])) self.gridTable.SetCellValue(row, 1, str(acc[i]['item_name'])) am = f"{acc[i]['amount']:,}" self.gridTable.SetCellValue(row, 2, str(am)) i += 1 self.gridTable.AutoSize() class AddItemDialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self) get_resources().LoadDialog(self, parent, 'MyDialog') self.SetSize((300, 250)) self.parent = parent c = db_sqlite(DB_NAME) self.dbtn1 = wx.xrc.XRCCTRL(self, 'dbtn1') self.dbtn1.Bind( wx.EVT_BUTTON, self.quit_button ) self.dbtn2 = wx.xrc.XRCCTRL(self, 'dbtn2') self.dbtn2.Bind( wx.EVT_BUTTON, self.create_sql ) self.in1 = wx.xrc.XRCCTRL(self, 'in1') self.in2 = wx.xrc.XRCCTRL(self, 'in2') self.in3 = wx.xrc.XRCCTRL(self, 'in3') in2Items = self.createitemname() self.in2.SetItems(in2Items) def quit_button(self, e): self.parent.tableShow() self.Destroy() def create_sql( self, event ): acc_d = self.in1.GetValue() acc_date = acc_d.Format("%Y-%m-%d") combo = self.in2.GetValue() amount = self.in3.GetValue() c = db_sqlite(DB_NAME) sql = 'select item_code from item where item_name=?' item_code = c.db_execute_place(sql, (combo,)).fetchone() sql = 'insert into acc_data(acc_date, item_code, amount) values (?, ?, ?)' c.db_execute_place(sql, (acc_date, item_code['item_code'], amount)) c.db_commit() def createitemname(self): li = [] c = db_sqlite(DB_NAME) sql = 'select item_name from item' items = c.db_execute(sql).fetchall() for r in items: li.append(r['item_name']) return tuple(li) def main(): app = wx.App() ex = MyFrame(None) ex.Show() app.MainLoop() if __name__ == '__main__': main()
dbSqliteClass.py
SQLite3のテーブル作成とPythonによるデータ操作 – Qiita
こちらのコードを使用しています。
# ----- # coding: utf-8 # https://qiita.com/ChibaDai/items/83e03aad49bb21b8bf12 # ----- import sqlite3 class db_sqlite(): def __init__(self, sqlite_db_path): self.db_path = sqlite_db_path self.conn = None self.cursor = None self.db_cursor() def db_connect(self): if self.conn is not None: self.db_close() self.conn = sqlite3.connect(self.db_path) self.conn.row_factory = self.dict_factory def db_cursor(self): if self.conn is None: self.db_connect() if self.cursor is None: self.cursor = self.conn.cursor() def db_commit(self): self.conn.commit() def db_execute(self, exec_sql): # Insert a row of data # sample sql source # c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") if self.cursor is None: self.db_cursor() return self.cursor.execute(exec_sql) def db_execute_place(self, exec_sql, data): if self.cursor is None: self.db_cursor() return self.cursor.execute(exec_sql, data) def db_execute_many(self, exec_sql, data): if self.cursor is None: self.db_cursor() return self.conn.executemany(exec_sql, data) def db_close(self): if self.conn is not None: self.conn.close() self.cursor = None self.conn = None def dict_factory(self, cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d
XRC(kakeibo.xrc)
wxFormBuilderで書き出したもの。
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1"> <object class="wxFrame" name="MyFrame"> <style>wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL</style> <size>350,350</size> <title>家計簿アプリ</title> <centered>1</centered> <aui_managed>0</aui_managed> <object class="wxPanel" name="mainPanel"> <style>wxTAB_TRAVERSAL</style> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxGridSizer"> <rows>0</rows> <cols>2</cols> <vgap>0</vgap> <hgap>0</hgap> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxButton" name="btn1"> <label>入力</label> <default>0</default> <markup>0</markup> <bitmap /> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_RIGHT</flag> <border>5</border> <object class="wxButton" name="btn2"> <label>終了</label> <default>0</default> <markup>0</markup> <bitmap /> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND | wxALL</flag> <border>5</border> <object class="wxStaticLine" name="line1"> <style>wxLI_HORIZONTAL</style> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxStaticText" name="st1"> <font> <size>15</size> <style>normal</style> <weight>normal</weight> <underlined>0</underlined> </font> <label>【表示画面】</label> <wrap>-1</wrap> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxHORIZONTAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_VERTICAL</flag> <border>5</border> <object class="wxStaticText" name="st2"> <label>期間</label> <wrap>-1</wrap> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxDatePickerCtrl" name="kikan1"> <style>wxDP_DROPDOWN</style> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_VERTICAL</flag> <border>5</border> <object class="wxStaticText" name="st3"> <label>~</label> <wrap>-1</wrap> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxDatePickerCtrl" name="kikan2"> <style>wxDP_DROPDOWN</style> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxButton" name="btn3"> <label>表示</label> <default>0</default> <markup>0</markup> <bitmap /> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>1</option> <flag>wxALL|wxEXPAND</flag> <border>5</border> <object class="wxGrid" name="gridTable" /> </object> </object> </object> </object> </object> </object> <object class="wxDialog" name="MyDialog"> <style>wxDEFAULT_DIALOG_STYLE</style> <size>300,250</size> <title>入力画面</title> <centered>1</centered> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>1</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxPanel" name="mainPanel"> <style>wxTAB_TRAVERSAL</style> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_RIGHT</flag> <border>5</border> <object class="wxButton" name="dbtn1"> <label>終了</label> <default>0</default> <markup>0</markup> <bitmap /> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxEXPAND</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxStaticText" name="st1"> <font> <size>14</size> <style>normal</style> <weight>normal</weight> <underlined>0</underlined> </font> <label>【入力画面】</label> <wrap>-1</wrap> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxFlexGridSizer"> <rows>0</rows> <cols>2</cols> <vgap>0</vgap> <hgap>0</hgap> <growablecols></growablecols> <growablerows></growablerows> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_VERTICAL</flag> <border>5</border> <object class="wxStaticText" name="st2"> <label>日付</label> <wrap>-1</wrap> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxDatePickerCtrl" name="in1"> <style>wxDP_DROPDOWN</style> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_VERTICAL</flag> <border>5</border> <object class="wxStaticText" name="st3"> <label>内訳</label> <wrap>-1</wrap> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxComboBox" name="in2"> <size>150,-1</size> <value></value> <content /> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL|wxALIGN_CENTER_VERTICAL</flag> <border>5</border> <object class="wxStaticText" name="st4"> <label>金額</label> <wrap>-1</wrap> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxTextCtrl" name="in3"> <size>150,-1</size> <value></value> </object> </object> </object> </object> <object class="sizeritem"> <option>0</option> <flag>wxALIGN_CENTER_HORIZONTAL</flag> <border>5</border> <object class="wxBoxSizer"> <orient>wxVERTICAL</orient> <object class="sizeritem"> <option>0</option> <flag>wxALL</flag> <border>5</border> <object class="wxButton" name="dbtn2"> <label>登録</label> <default>0</default> <markup>0</markup> <bitmap /> </object> </object> </object> </object> </object> </object> </object> </object> </object> </resource>
日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)