I am using these 'required' versions of:
- Python 3.6.4
- PyQt5 5.9.2
Running “fbs"
I have absolutely no problem getting my application to work through “fbs run”… the application runs perfectly
I complete my “fbs freeze”… no problem but after I run the “fbs installer” and I execute the .dmg file (I am on macOS - Catalina - 10.15.2) and drag it into my applications folder Everything appears to work, but when I try and launch the now installed application… it starts to launch the icon and the dock and then just shuts down.
When I comment out the DB-related code. it all works perfectly. That is I am able to fully launch my application
First way I configured my application.
In main.py:
appctxt.get_resource("../resources/plants.db”)
And I place my database file in: "src/main/resources"
when I operate like this, I get the behavior I described above (app tries to launch and closes right down)
Second way I configured my application. I started to poke around to see if I could fix the issue. So I found a "resources" directory in the target directory I try to launch my application through the executable in the: target/testPlants.app/Contents/ directory when I do that, the mac CMD window comes up and I see that it tells me, it can not find my DB at the path I specified in the “get_resource” method.
So I find the resources directory in the target’s directory is in UPPERCASE, like this:
target/testPlants.app/Contents/Resources and I see that as expected my DB is stored in the “Resources”directory. so I changed my appctxt.get_resource statement in main.py to:
appctxt.get_resource("../Resources/plants.db”)
and in fact, I no longer get the error when I try to launch it through the .exe in the: target/testPlants.app/Contents/ directory and my application launches… (I don’t get my icons, but it launches!)
so I am thinking, I am getting somewhere.
So I go ahead and try and launch my application through double-clicking the application icon after running the installer with this path change (using “Resources” in uppercase) and I now get a new error
Could not open database file: out of memory
(see below) Screen Shot 2020-04-19 at 2.46.11 PM.png
Reproducible Sample With the code as is... when I examine the resources directory in the target directory, that gets created as a result of the fbs freeze, there is no db in it, so the app tries to launch (after I run the installer)and just closes down. If I manually place the db in it, it gives me the "out of memory" error. Thanks for taking a look
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from fbs_runtime.application_context import cached_property
import sys, csv
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
from PyQt5 import QtSql as qts
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog
from PyQt5.Qt import QFileInfo
import sqlite3
from datetime import date
from PyQt5.QtGui import QPixmap
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
self.gridLayout = qtw.QGridLayout()
self.mainW = qtw.QWidget()
self.mainW.setLayout(self.gridLayout)
self.setCentralWidget(self.mainW)
# Connect to the database
db = qts.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('plants.db')
if not db.open():
qtw.QMessageBox.critical(
None, 'DB Connection Error',
'Could not open database file: '
f'{db.lastError().text()}')
sys.exit(1)
#CREATE MODELS FOR EACH SQL TABLE
self.zone_model = qts.QSqlTableModel()
self.zone_model.setTable('zones')
self.loc_model = qts.QSqlTableModel()
self.loc_model.setTable('loc_rec')
self.indoor_seed_model = qts.QSqlTableModel()
self.indoor_seed_model.setTable('indoor_seed')
self.soil_rec_model = qts.QSqlTableModel()
self.soil_rec_model.setTable('soil_rec')
self.plant_type_model = qts.QSqlTableModel()
self.plant_type_model.setTable('plant_type')
self.nick_name_model = qts.QSqlTableModel()
self.plant_type_model.setTable('nick_name')
self.plants_model = qts.QSqlRelationalTableModel()
self.plants_model.setTable('plant_list')
self.plants_model.setRelation(
self.plants_model.fieldIndex('nickname_id'),
qts.QSqlRelation('nick_name', 'id', 'veggies')
)
self.plants_model.setRelation(
self.plants_model.fieldIndex('ans_id'),
qts.QSqlRelation('indoor_seed', 'id', 'ans')
)
self.plants_model.setRelation(
self.plants_model.fieldIndex('zone_id'),
qts.QSqlRelation('zones', 'id', 'code')
)
self.plants_model.setRelation(
self.plants_model.fieldIndex('soil_id'),
qts.QSqlRelation('soil_rec', 'id', 'soil_type')
)
self.plants_model.setRelation(
self.plants_model.fieldIndex('p_type_id'),
qts.QSqlRelation('plant_type', 'id', 'p_type')
)
self.plants_model.setRelation(
self.plants_model.fieldIndex('location_id'),
qts.QSqlRelation('loc_rec', 'id', 'loc')
)
self.UIComps() # call the UI components method
def UIComps(self):
# set headers for main table
fieldnames = ['ID', "Year Planted", "Real Name", "Nick Name", "Description",
"Seed Plant Rec","Garden Plant Rec", "Plant Notes", "Comments",
"Days to Germ", "Days to Harv","Reco Spring Frost","Actual Spring Frost", "Seed Plant Rec", "Garden Plant Rec",
"Actual Seed Plant", "Actual Garden Plant", "Harvest Date Plan", "Actual Harvest Date",
"Photo", "Location", "Zone", "Seed Indoor?", "Soil Type", "Plant Type" ]
c = 0
for f in fieldnames:
self.plants_model.setHeaderData(c, qtc.Qt.Horizontal, (fieldnames[c]))
c += 1
self.plants_model.setEditStrategy(qts.QSqlTableModel.OnFieldChange)
# self.plants_model.dataChanged.connect(print)
lbl2 = qtw.QLabel("View/Edit Plants", self)
lbl2.setFont(qtg.QFont("Helvetica", 25, 12))
self.gridLayout.layout().addWidget(lbl2, 6, 0,1,3, alignment=qtc.Qt.AlignCenter)
#PLANT LIST TABLE
self.plant_list = qtw.QTableView()
self.plant_list.setSelectionMode(qtw.QAbstractItemView.ExtendedSelection)
self.plant_list.setDragEnabled(True)
self.plant_list.setAcceptDrops(True)
self.plant_list.setDropIndicatorShown(True)
self.plant_list.setDragDropMode(qtw.QAbstractItemView.InternalMove)
self.plant_list.setModel(self.plants_model)
self.gridLayout.layout().addWidget(self.plant_list, 7, 0, 2, 3)
self.plant_list.horizontalHeader().setSectionsClickable(True)
self.plant_list.horizontalHeader().setSortIndicatorShown(True)
self.plant_list.setSortingEnabled(True) # this makes table sortable
self.plants_model.setEditStrategy(qts.QSqlTableModel.OnFieldChange)
self.plants_model.dataChanged.connect(print)
self.plants_model.select()
self.plant_list.setItemDelegate(qts.QSqlRelationalDelegate())
#adding toolbars
self.toolbar = self.addToolBar('Controls')
deleteCoffee = qtw.QAction(qtg.QIcon("close.png"), "Delete Record", self)
deleteCoffee.triggered.connect(self.delete_plant) #removes from table
self.toolbar.addAction(deleteCoffee )
addPlant = qtw.QAction(qtg.QIcon("add.png"), "Add A Plant", self)
addPlant.triggered.connect(self.add_plant)
self.toolbar.addAction(addPlant)
# SLOTS for Toolbar buttons
def delete_plant(self):
selected = self.plant_list.selectedIndexes()
for index in selected or []:
self.plants_model.removeRow(index.row())
self.plants_model.select()
def add_plant(self):
self.gridLayout.layout().addWidget(self.plant_list, 7, 0, 2, 3)
self.plants_model.insertRows(0, 1)
appctxt = ApplicationContext()
appctxt.get_resource("../resources/plants.db")
appctxt.get_resource("../resources/add.png")
mw = MainWindow()
mw.setGeometry(10, 10, 900, 650)
mw.show()
exit_code = appctxt.app.exec_()
sys.exit(exit_code)
UPDATE - I believe I fixed the DB problem, with the following changes to the code and configuration, but I am still not able to see my images after running "fbs freeze"
Here are the changes I made with respect to the DB:
- First DB for me had to live in a sub-directory to "resources" as opposed to resources directly, so for me it is this:
src/main/resources/base
- Next, I assumed the path in my 'main.py' would mimic that path above (in other words, where I placed the database (src/main/resources/base)). Instead, this is what appears to be working for me:
appctxt.get_resource("plants.db")
I now get no error about not being able to locate the DB, However, when I run the executable, none of my images/icons are showing up, which for me, enable navigation of the application and the DB.
In reading the documentation it appears that images follow the same logic as the data files/database, but that does not appear to be working for me. It works when I execute an "fbs run", but not after the "fbs freeze" when I launch the applications' executable. The application launches without error, but no images.
My configuration for the images is the same as for the DB:
- I have loaded them into a sub-directory to "resources" called "base", like this
src/main/resources/base
- And as for the statements in the "main.py" file, I have the following:
appctxt.get_resource("carrots.jpg")
appctxt.get_resource("csv.png")
appctxt.get_resource("csv2.png")
appctxt.get_resource("leeks.jpg")
appctxt.get_resource("list.png")
appctxt.get_resource("close.png")
appctxt.get_resource("mushrooms.jpg")
appctxt.get_resource("pdf.png")
appctxt.get_resource("potato.jpg")
appctxt.get_resource("Rosce.png")
appctxt.get_resource("seed.png")
appctxt.get_resource("tomato.jpg")
appctxt.get_resource("veggies.png")
appctxt.get_resource("year.png")
Anyone have luck with images? Is there a different way to configure them? Thanks
FURTHER UPDATE
As I continue to try to figure this out, after 'fbs freeze', I can confirm that fbs transfers the database and the images to the: 'target//Contents/Resources' directory, but I don't think it is really seeing any of them.
Further, it does not seem to make a difference whether or not I include:
# appctxt.get_resource("add.png")
# appctxt.get_resource("carrots.jpg")
in main.py
I guess I don't fully understand under what conditions I would need to include the .get_resource() methods and exactly how to configure it. I have seen the example here, but not sure how to get that to work with my database or if I even need to. It seem logically that I do. I'll keep digging, but if anyone was has insight, I would appreciate any tips.
UPDATE - FIXED!
I finally figured it out and I hope this helps someone else.
- I had this part right, the data files, images and database goes here:
src/main/resources/base
- Here is how I got the code for the database to get it to be recognized:
db = qts.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(appctxt.get_resource("plants.db"))
if not db.open():
qtw.QMessageBox.critical(
None, 'DB Connection Error',
'Could not open database file: '
f'{db.lastError().text()}')
sys.exit(1)
I needed to place the get_resource() method inside the setDatabaseName() method from PyQt's QSqlDatabase class.
For the images I needed to do something like this:
ros = appctxt.get_resource("Rosce.png")
pixmap = qtg.QPixmap(ros)
OR if using the setStyle method, like this:
seed = appctxt.get_resource("seed.png")
self.btnSeed.setStyleSheet("image: url(" + seed + ");")