[Tutor] Python WX module program issues.
mhysnm1964 at gmail.com
mhysnm1964 at gmail.com
Thu Mar 23 05:14:47 EDT 2023
All,
I have created a simple Python 3.10 app using WX module. There is a main
frame and two horizontal panels. Panel1 has an edit object in it. Panel2 has
a list box. The issues I cannot resolve:
1. I cannot add any new content to the status bar from the class EditPanel.
2. The RecordListPanel does not show any content and the database is
populated.
3. F6 is meant to switch between the two panels and set the keyboard focus
to the next panel.
There is some issues with the saveDb method in the EditPanel Class which I
am still working on. If record key publisher has no values, it receives
"None". The Publisher table has unique records set to prevent duplication.
The same applies to authors, genre, narrator.
Can someone look at this code an let me know why point 1 to 3 isn't working?
import wx, os, codecs, chardet
from books_db import Book, Author, Narrator, Series, Publisher, Genre,
Session
from sqlalchemy.exc import IntegrityError
from books_db import Book, Author, Narrator, Series, Publisher, Genre,
Session
class RecordListPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.list_ctrl = wx.ListCtrl(self, style=wx.LC_REPORT)
self.list_ctrl.InsertColumn(0, 'Title', width=200)
self.list_ctrl.InsertColumn(1, 'Author', width=200)
self.list_ctrl.InsertColumn(2, 'Genre', width=200)
self.list_ctrl.InsertColumn(3, 'Narrator', width=200)
self.list_ctrl.InsertColumn(4, 'Publisher', width=200)
self.list_ctrl.InsertColumn(5, 'Series', width=200)
self.list_ctrl.InsertColumn(6, 'Series No.', width=100)
self.populate_list_ctrl()
#sizer = wx.BoxSizer(wx.VERTICAL)
#sizer.Add(self.list_ctrl, 1, wx.EXPAND)
#self.SetSizer(sizer)
def populate_list_ctrl(self):
session = Session()
books = session.query(Book).all()
for book in books:
row = [book.title]
# authors
authors = ', '.join([author.author for author in book.authors])
row.append(authors)
# genres
genres = ', '.join([genre.genre for genre in book.genres])
row.append(genres)
# narrators
narrators = ', '.join([narrator.narrator for narrator in
book.narrators])
row.append(narrators)
row.append(book.publisher.publisher)
row.append(book.series.series)
row.append(str(book.series_no))
self.list_ctrl.Append(row)
session.close()
class EditPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
# Initialize variables
self.books = []
self.current_book_index = 0
self.record = {}
# Create controls
self.edit = wx.TextCtrl(self,
style=wx.TE_MULTILINE|wx.SUNKEN_BORDER)
# Load the books
self.load_books_paths()
# Load the first book into the edit field
self.load_book()
#sizer = wx.BoxSizer(wx.VERTICAL)
#sizer.Add(self.edit, 1, wx.EXPAND)
#self.SetSizer(sizer)
def load_books_paths(self):
for root, dirs, files in os.walk("c:\\books"):
for filename in files:
if filename.endswith(".txt"):
filepath = os.path.join(root, filename)
self.books.append(filepath)
print("loaded file paths ")
def load_book(self):
# Get the current book file path
current_book = self.books[self.current_book_index]
self.record['path'] = current_book
with open(current_book, 'rb') as f:
contents = f.read()
encoding = chardet.detect(contents)['encoding']
try:
with codecs.open(current_book, "r", encoding=encoding) as f:
contents = f.read()
except UnicodeDecodeError:
content = "Unknown file type for " + current_book
# Load the contents of the file into the text box
self.edit.SetValue(contents)
def priorBook(self, event):
self.record.clear() # initialize record.
# Move to the prior book and load it
self.current_book_index -= 1
if self.current_book_index < 0: # cannot pass 0.
dlg = wx.MessageDialog(self, "Beginning of book path",
caption="Record Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
dlg.ShowModal()
return
self.load_book()
prior_file = self.books[self.current_book_index]
self.GetTopWindow().SetStatusText(f"Prior file: {prior_file}")
def nextBook(self, event=None):
self.record.clear() # initialize record.
# Move to the next book and load it
self.current_book_index += 1
if self.current_book_index >= len(self.books):
dlg = wx.MessageDialog(self, "end of book path",
caption="Record Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
dlg.ShowModal()
return
self.load_book()
# Update status bar with path of next file
next_file = self.books[self.current_book_index]
self.GetTopWindow().SetStatusText(f"Next file: {next_file}")
def titleSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['title'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"title: {selected_text}")
def authorSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'author' not in self.record:
self.record['author'] = []
self.record['author'].append(selected_text.strip())
self.GetTopWindow().SetStatusText(f"Author: {selected_text}")
def aboutAuthorSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'about_author' not in self.record:
self.record['about_author'] = selected_text.strip()
else:
self.record['about_author'] = self.record['about_author'] + '\n'
+ selected_text.strip()
self.GetTopWindow().SetStatusText("About Author saved")
def descriptionSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'description' not in self.record:
self.record['description'] = selected_text.strip()
else:
self.record['description'] = self.record['description'] + "\n" +
selected_text.strip()
self.GetTopWindow().SetStatusText("Description saved")
def seriesSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['series'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"Series: {selected_text}")
def seriesNoSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['series_no'] = int(selected_text.strip())
self.GetTopWindow().SetStatusText(f"Series Number: {selected_text}")
def narratorSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'narrator' not in self.record:
self.record['narrator'] = []
self.record['narrator'].append(selected_text.strip())
self.GetTopWindow().SetStatusText(f"Narrator: {selected_text}")
def miscSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'misc' not in self.record:
self.record['misc'] = selected_text.strip()
else:
self.record['misc'] = self.record['misc'] + "\n" +
selected_text.strip()
self.GetTopWindow().SetStatusText("Misc saved")
def genreSave(self, event):
selected_text = self.edit.GetStringSelection()
if 'genre' not in self.record:
self.record['genre'] = []
self.record['genre'].append(selected_text.strip())
self.GetTopWindow().SetStatusText(f"Genre: {selected_text}")
def publisherSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['publisher'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"Publisher: {selected_text}")
def durationSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['duration'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"Duration saved:
{selected_text}")
def releaseSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['release'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"Release: {selected_text}")
def copyrightSave(self, event):
selected_text = self.edit.GetStringSelection()
self.record['copyright'] = selected_text.strip()
self.GetTopWindow().SetStatusText(f"Copyright: {selected_text}")
def reviewDb(self, event):
# review the dict
print (self.record)
msgString = ""
for key, value in self.record.items():
if isinstance(value, int):
value = str(value)
elif isinstance(value, list) and value:
for v in value:
v += "\n"
msgString += " ".join([key, value]) + "\n"
dlg = wx.MessageDialog(self, msgString, caption="Record Content",
style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
dlg.ShowModal()
def saveDb(self, event):
if self.record.get('title') is None or self.record.get('author') is
None or self.record.get('description') is None:
dlg = wx.MessageDialog(self, "Cannot save update database. Not
all required fields have been defined.", caption="Record Warning",
style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
dlg.ShowModal()
return
elif self.record.get('genre') is None:
self.record.get['genre'] = "None"
elif self.record.get('narrator') is None:
self.record['narrator'] = []
self.record['narrator'].append("None")
elif self.record.get('publisher') is None:
self.record['publisher'] = "None"
elif self.record.get('title') == '' or
self.record.get('description') == '':
dlg = wx.MessageDialog(self, "Title and description are
required before record can be saved to the database. ", caption="Record
Warning", style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
dlg.ShowModal()
return
# establish session with database.
session = Session()
try:
# create objects
publisher =
session.query(publisher).filter_by(publisher=self.record.get('publisher')).f
irst()
if publisher is None:
publisher = Publisher(publisher=self.record.get('publisher',
''))
# check if author exists
authors = []
for author_name in self.record.get('author', []):
author =
session.query(Author).filter_by(author=author_name).first()
if author is None:
author = Author(author=author_name,
about_author=self.record.get('about_author', ''))
authors.append(author)
# check if genre exists
genres = []
for genre_name in self.record.get('genre', []):
genre =
session.query(Genre).filter_by(genre=genre_name).first()
if genre is None:
genre = Genre(genre=genre_name)
genres.append(genre)
# check if narrator exists
narrators = []
for narrator_name in self.record.get('narrator', []):
narrator =
session.query(Narrator).filter_by(narrator=narrator_name).first()
if narrator is None:
narrator = Narrator(narrator=narrator_name)
narrators.append(narrator)
series = Series(series=self.record.get('series', ''))
book = Book(title=self.record.get('title', ''),
path=self.record.get('path', ''),
release=self.record.get('release', ''),
duration=self.record.get('duration', ''),
copyright=self.record.get('copyright', ''),
description=self.record.get('description', ''),
misc=self.record.get('misc', ''),
series_no=self.record.get('series_no', 0))
book.publisher = publisher
book.authors = authors
book.narrators = narrators
book.genres = genres
book.series = series
# add objects to session
session.add_all([book, publisher, series] + authors + narrators
+ genres)
# commit changes
session.commit()
self.GetTopWindow().SetStatusText("Record saved successfully")
except Exception as e:
session.rollback()
print(f"Error occurred: {e}")
self.GetTopWindow().SetStatusText("Record did not saved
successfully")
finally:
session.close()
def clearRecord(self, event):
self.record.clear()
self.GetTopWindow().SetStatusText("Record in memory cleared
successfully")
class MyApp(wx.App):
def OnInit(self):
# Create the main frame
self.frame = wx.Frame(None, title="Library", size=(1920, 1080 ))
self.frame.Maximize()
sizer_main = wx.BoxSizer(wx.VERTICAL)
# Create the two panels
self.panel1 = EditPanel(self.frame)
self.panel2 = RecordListPanel(self.frame)
# Create the horizontal box sizers for the panels
sizer_panel1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_panel2 = wx.BoxSizer(wx.HORIZONTAL)
# Create the menubar
menubar = wx.MenuBar()
# Create the "Options" menu
options_menu = wx.Menu()
save_record_item = options_menu.Append(wx.ID_ANY, "Save
Record\tCtrl+S", "Save to database")
self.Bind(wx.EVT_MENU,self.panel1.saveDb, save_record_item)
next_file_item = options_menu.Append(wx.ID_ANY, "Next file\tCtrl+N",
"Load next file")
prior_file_item = options_menu.Append(wx.ID_ANY, "Prior
file\tCtrl+P", "Load prior file")
review_record_item = options_menu.Append(wx.ID_ANY, "Review
Record\tCtrl+r", "Review record")
self.Bind(wx.EVT_MENU,self.panel1.reviewDb, review_record_item)
self.Bind(wx.EVT_MENU,self.panel1.nextBook, next_file_item)
self.Bind(wx.EVT_MENU,self.panel1.priorBook, prior_file_item)
clear_record_item = options_menu.Append(wx.ID_ANY, "Clear
Record\Alt+I", "Clear record in memory")
self.Bind(wx.EVT_MENU,self.panel1.clearRecord, clear_record_item)
options_menu.Append(wx.ID_EXIT, "Exit", "Exit the program")
menubar.Append(options_menu, "&Options")
# Create the "Save to record" menu
save_menu = wx.Menu()
title_item = save_menu.Append(wx.ID_ANY, "Title\tAlt+T", "Save book
title")
self.Bind(wx.EVT_MENU,self.panel1.titleSave, title_item)
author_item = save_menu.Append(wx.ID_ANY, "Author\tAlt+A", "Save
book author")
self.Bind(wx.EVT_MENU,self.panel1.authorSave, author_item)
series_item = save_menu.Append(wx.ID_ANY, "Series\tAlt+S", "Save
book Series")
self.Bind(wx.EVT_MENU,self.panel1.seriesSave, series_item)
seriesNo_item = save_menu.Append(wx.ID_ANY, "SeriesNo\tCtrl+3",
"Save Series No")
self.Bind(wx.EVT_MENU,self.panel1.seriesNoSave, seriesNo_item)
genre_item = save_menu.Append(wx.ID_ANY, "Genre\tAlt+G", "Save book
genre")
self.Bind(wx.EVT_MENU,self.panel1.genreSave, genre_item)
description_item = save_menu.Append(wx.ID_ANY, "Description\tAlt+D",
"Save book description")
self.Bind(wx.EVT_MENU,self.panel1.descriptionSave, description_item)
aboutAuthor_item = save_menu.Append(wx.ID_ANY, "About
Author\tAlt+B", "Save about author")
self.Bind(wx.EVT_MENU,self.panel1.aboutAuthorSave, aboutAuthor_item)
narrator_item = save_menu.Append(wx.ID_ANY, "Narrator\tAlt+N", "Save
book narrator")
self.Bind(wx.EVT_MENU,self.panel1.narratorSave, narrator_item)
release_item = save_menu.Append(wx.ID_ANY, "Release Date\tAlt+R",
"Save book release date")
self.Bind(wx.EVT_MENU,self.panel1.releaseSave, release_item)
duration_item = save_menu.Append(wx.ID_ANY, "Duration\tCtrl+D",
"Save book duration")
self.Bind(wx.EVT_MENU,self.panel1.durationSave, duration_item)
copyright_item = save_menu.Append(wx.ID_ANY, "Copyright\tAlt+C",
"Save book copyright")
self.Bind(wx.EVT_MENU,self.panel1.copyrightSave, copyright_item)
publisher_item = save_menu.Append(wx.ID_ANY, "Publisher\tAlt+P",
"Save book publisher")
self.Bind(wx.EVT_MENU,self.panel1.publisherSave, publisher_item)
misc_item = save_menu.Append(wx.ID_ANY, "Misc\tAlt+M", "Save book
misc")
self.Bind(wx.EVT_MENU,self.panel1.miscSave, misc_item)
menubar.Append(save_menu, "Sa&ve to record")
self.frame.SetMenuBar(menubar)
# Create the status bar
self.frame.CreateStatusBar()
#self.statusbar.SetFieldsCount(3)
#self.statusbar.SetStatusWidths([-2, -1, -1])
# Set up the panel switching
self.currentPanel = self.panel1
self.panel1.SetFocus()
self.frame.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
def onKeyDown(self, event):
if event.GetKeyCode() == wx.WXK_F6:
if self.currentPanel == self.panel1:
self.currentPanel = self.panel2
self.panel2.SetFocus()
else:
self.currentPanel = self.panel1
self.panel1.SetFocus()
else:
event.Skip()
# set focus to the current panel.
self.currentPanel.SetFocus()
if __name__ == '__main__':
# Create the wx
app = MyApp()
# Start the main event loop
app.MainLoop()
More information about the Tutor
mailing list