Развертывание PyQT5 с использованием FBS с базой данных SQLITE - PullRequest
0 голосов
/ 19 апреля 2020

Я использую следующие «обязательные» версии:

  • Python 3.6.4
  • PyQt5 5.9.2

Запуск «fbs» «

У меня нет абсолютно никаких проблем с тем, чтобы заставить мое приложение работать через« fbs run »… приложение работает отлично

Я завершаю свой« fbs freeze »… без проблем, но после того, как я запускаю« fbs » установщик », и я запускаю файл .dmg (я нахожусь на macOS - Catalina - 10.15.2) и перетаскиваю его в папку с приложениями. Кажется, все работает, но когда я пытаюсь запустить уже установленное приложение… он начинает запускать значок и док, а затем просто выключается.

Когда я закомментирую код, связанный с БД, все работает отлично. То есть я могу полностью запустить свое приложение

Сначала как я настроил свое приложение.

В main.py:

appctxt.get_resource("../resources/plants.db”)

И я помещаю файл базы данных в: "src / main / resources"

когда я работаю так, я получаю поведение, описанное выше (приложение пытается unch и закрывается сразу)

Второй способ настройки приложения. Я начал ковыряться, чтобы посмотреть, смогу ли я решить проблему. Таким образом, я обнаружил каталог «resources» в целевом каталоге, и я пытаюсь запустить свое приложение через исполняемый файл в каталоге: target / testPlants.app / Contents /, когда я это делаю, появляется окно ma c CMD, и я вижу что он говорит мне, он не может найти мою БД по пути, указанному мной в методе «get_resource».

Поэтому я нахожу каталог ресурсов в каталоге цели в UPPERCASE, например:

target / testPlants.app / Contents / Resources, и я вижу, что моя БД, как и ожидалось, хранится в каталоге «Ресурсы». поэтому я изменил свой оператор appctxt.get_resource в main.py на:

appctxt.get_resource("../Resources/plants.db”)

, и фактически я больше не получаю ошибку при попытке запустить его через .exe в: target / testPlants. app / Contents / directory и мое приложение запускается ... (я не получаю свои значки, но оно запускается!)

так что я думаю, я где-то получаю.

Итак, я go вперед и попробуйте запустить мое приложение, дважды щелкнув значок приложения после запуска установщика с этим изменением пути (используя «Ресурсы» в верхнем регистре), и теперь я получаю новую ошибку

Could not open database file: out of memory

(см. ниже ) Снимок экрана 2020-04-19 в 2.46.11 PM.png

enter image description here

Воспроизводимый образец С кодом как есть. .. когда я проверяю каталог ресурсов в целевом каталоге, который создается в результате замораживания fbs, в нем нет базы данных, поэтому приложение пытается запустить (после того, как я запустил установщик) и просто закрывается. Если я вручную помещу в него базу данных, это выдаст мне ошибку «недостаточно памяти». Спасибо за просмотр

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)

ОБНОВЛЕНИЕ - Я считаю, что я исправил проблему с БД со следующими изменениями в коде и конфигурации, но я все еще не могу увидеть свои изображения после запуска "fbs freeze"

Вот изменения, которые я сделал в отношении БД:

  1. Первая БД для меня должна была жить в подкаталоге к "ресурсам", как в отличие от ресурсов напрямую, поэтому для меня это так:

src / main / resources / base

Далее, я предположил, что путь в моем main.py будет имитировать c этот путь выше (другими словами, где я разместил базу данных (src / main / resources / base)). Вместо этого, это то, что, кажется, работает для меня:

appctxt.get_resource("plants.db")

Теперь я не получаю ошибку о невозможности найти БД, однако, когда я запускаю Исполняемый файл, ни одно из моих изображений / значков не отображается, что для меня, включить навигацию приложения и БД.

При чтении документации выясняется, что изображения следуют тому же логу c, что и файлы данных / база данных, но это, похоже, не работает для меня. Он работает, когда я запускаю «fbs run», но не после «fbs freeze», когда я запускаю исполняемый файл приложения. Приложение запускается без ошибок, но без картинок.

Моя конфигурация для изображений такая же, как и для БД:

  1. Я загрузил их в подкаталог для «ресурсов» под названием «base», например

src / main / resources / base

А что касается утверждений в файле "main.py", у меня есть следующее:
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")

Кому-нибудь повезло с изображениями? Есть ли другой способ их настройки? Спасибо

ДОПОЛНИТЕЛЬНОЕ ОБНОВЛЕНИЕ

Поскольку я продолжаю пытаться выяснить это, после 'fbs freeze' я могу подтвердить, что fbs передает базу данных и изображения в : каталог 'target // Contents / Resources', но я не думаю, что он действительно видит какой-либо из них.

Более того, не имеет значения, включаю ли я:

# appctxt.get_resource("add.png")
# appctxt.get_resource("carrots.jpg")

в main.py

Полагаю, я не до конца понимаю, при каких условиях мне нужно включить методы .get_resource () и как именно его настроить. Я видел пример здесь , но не уверен, как заставить это работать с моей базой данных или если мне даже нужно. Логично, что я делаю. Я продолжу копать, но если у кого-то есть понимание, я буду признателен за любые советы.

ОБНОВЛЕНИЕ - ИСПРАВЛЕНО!

Я наконец понял это, и я надеюсь, что это помогает кому-то еще.

  1. Я правильно понял эту часть, файлы данных, изображения и база данных находятся здесь:

src / main / resources / base

Вот как я получил код для базы данных, чтобы он был распознан:
 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)

Мне нужно было поместить метод get_resource () в метод setDatabaseName () из PyQt QSqlDatabase класс.

Для изображений мне нужно было сделать что-то вроде этого:

   ros = appctxt.get_resource("Rosce.png")
        pixmap = qtg.QPixmap(ros)

ИЛИ, если использовать метод setStyle, например:

seed = appctxt.get_resource("seed.png")
self.btnSeed.setStyleSheet("image: url(" + seed + ");")
...