0

I'm trying to get all my filenames after I click on a button. I am getting the following error after I run app.py -

<lib.create_form_elements.CreateFormElements object at 0x000002286E0B9948> Traceback (most recent call last): File "\controller\addNewItemController.py", line 12, in update_filename self._model.fname = value File "\models\addNewItemModel.py", line 14, in fname self._flname.emit(value) AttributeError: 'bool' object has no attribute 'emit'.

what am I doing wrong?

app.py

import sys
from PyQt5.QtWidgets import QApplication
from models.addNewItemModel import ModelAddNewItem
from views.additem import AddNewItem
from controller.addNewItemController import AddNewItemController


class App(QApplication):
    def __init__(self, sys_argv):
        super(App, self).__init__(sys_argv)
        self.model = ModelAddNewItem()
        self.main_controller = AddNewItemController(self.model)
        self.main_view = AddNewItem(self.model, self.main_controller)
        self.main_view.show()


if __name__ == '__main__':
    app = App(sys.argv)
    sys.exit(app.exec_())

view:

from PyQt5 import QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QLineEdit, QPushButton
from lib.create_form_elements import CreateFormElements


# view
# Subclass QMainWindow to customise your application's main window
class AddNewItem(QMainWindow):

    def __init__(self, model, controller, *args, **kwargs):
        super(AddNewItem, self).__init__(*args, **kwargs)
        self._model = model
        self._controller = controller
        self.myWindow()

    def myWindow(self):
        self.setWindowTitle("Add New Item")
        sizeObject = QtWidgets.QDesktopWidget().screenGeometry(-1)
        print(" Screen size : " + str(sizeObject.height()) + "x" + str(sizeObject.width()))

        self.width = 600
        self.height = 480
        self.left = 0
        self.top = 0
        self.setGeometry(self.left, self.top, self.width, self.height)
        layout = QVBoxLayout()
        el_name = CreateFormElements("Object Name: ", QLineEdit())
        el_image = CreateFormElements("Add Images", None)
        el_image_1 = CreateFormElements("Image 1 ", QPushButton(), connectType='file', _fieldType='button')
        el_image_2 = CreateFormElements("Image 2 ", QPushButton(), connectType='file', _fieldType='button')
        el_image_3 = CreateFormElements("Image 1 ", QPushButton(), connectType='file', _fieldType='button')
        el_image_4 = CreateFormElements("Image 2 ", QPushButton(), connectType='file', _fieldType='button')
        el_save_button = QPushButton()
        el_save_button.setText('save')
        # this button is my save button
        el_save_button.clicked.connect(self._controller.get_file_name)
        self._model.fileName.connect(self.on_filename_changed)
        layout.addWidget(el_name)
        layout.addWidget(el_image)
        layout.addWidget(el_image_1)
        layout.addWidget(el_image_2)
        layout.addWidget(el_image_3)
        layout.addWidget(el_image_4)
        layout.addWidget(el_save_button)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

    @pyqtSlot(str)
    def on_filename_changed(self, value):
        print(value)

Model:

from PyQt5.QtCore import QObject, pyqtSignal


class ModelAddNewItem(QObject):
    fileName = pyqtSignal(str)

    @property
    def fname(self):
        return self._flname

    @fname.setter
    def fname(self, value):
        self._flname = value
        self._flname.emit(value)

    def __init__(self):
        super().__init__()

        self._flname = ''

controller

from PyQt5.QtCore import QObject, pyqtSlot, QFileInfo


class AddNewItemController(QObject):
    def __init__(self, model):
        super().__init__()

        self._model = model

    @pyqtSlot(str)
    def update_filename(self, value):
        self._model.fname = value

    def get_file_name(self):
        filePath = self.line_edit.text()
        fileName = QFileInfo(filePath).fileName()

the factory that create my form elements/ widgets:

from PyQt5 import QtWidgets
from PyQt5.QtCore import QFileInfo, pyqtSignal
from PyQt5.QtWidgets import QFormLayout, QLabel, QLineEdit, QHBoxLayout, QFileDialog


class CreateFormElements(QtWidgets.QWidget):
    filenameChanged = pyqtSignal(str)

    def __init__(self, label, fieldType, **kwargs):
        super(CreateFormElements, self)
        super().__init__()
        self.line_edit = QLineEdit()
        self.label = label
        self.fieldType = fieldType
        self.connectType = kwargs.get('connectType', None)
        self._fieldType = kwargs.get('_fieldType', None)
        self.create_form_row()

    def create_form_row(self):
        layout = QFormLayout()
        # if this is a button that should open up a file window, call the create_file_window() function to make a
        # file window.
        if self.connectType == 'file' and self._fieldType == 'button':
            self.fieldType.setText("Browse")
            self.fieldType.clicked.connect(self.create_file_window)
            hlayout = QHBoxLayout()
            hlayout.addWidget(self.line_edit)
            hlayout.addWidget(self.fieldType)
            layout.addRow(QLabel(self.label), hlayout)
            #self.line_edit.textChanged.connect(self.get_file_name)
        else:
            layout.addRow(QLabel(self.label), self.fieldType)

        self.setLayout(layout)

    def create_file_window(self):
        fileName, _ = QFileDialog.getOpenFileName(None, 'Select Image', '', 'Image Files (*.png *.jpg '
                                                                            '*.jpeg *.bmp)')
        self.line_edit.setText(fileName)
        self.filenameChanged.emit(fileName)

Samia Ruponti
  • 3,910
  • 12
  • 42
  • 62
  • change `self._flname.emit(value)` to `self.fileName.emit(value)` – eyllanesc Aug 18 '19 at 07:02
  • On the other hand, what I indicated in my previous code only solves the error you indicate but your error more thoroughly: Why do you use `el_save_button.clicked.connect(self._controller.update_filename)`? I don't understand why you connect the clicked signal to the update_filename slot – eyllanesc Aug 18 '19 at 07:05
  • Do you understand how the signals and slots work in Qt ?, it seems that no, I recommend you read some tutorial about its operation before going blindly, maybe a good starting point is https://doc.qt.io/qt-5/signalsandslots.html – eyllanesc Aug 18 '19 at 07:07
  • I was trying to get the filename on click of the save button, that's why I connected the button to the update_filename function. – Samia Ruponti Aug 18 '19 at 07:18
  • Do you think that magically the clicked signal of any button has the name of the file selected at the time of pressing the button? How will you get this information before the user scans and selects the file? – eyllanesc Aug 18 '19 at 07:20
  • now I am getting a type error `TypeError: decorated slot has no signature compatible with clicked(bool)` . I realize I am not going the right way, but I can't figure what I should be doing. I don't think it will magically appear - but that's why I am asking for help,to figure it out. – Samia Ruponti Aug 18 '19 at 07:22
  • If you realize the logic is: press the button, after a certain time a dialog opens where the user can take a lifetime to select the file but you want to get that name before the user selects it, and it is also in case the user does not select anything. – eyllanesc Aug 18 '19 at 07:23
  • Do you understand what `@pyqtSlot(bool)` means? – eyllanesc Aug 18 '19 at 07:24
  • the save button comes after all the files have been selected. this button does not open the dialog or the file dialog. – Samia Ruponti Aug 18 '19 at 07:29
  • Okay, but how does the save button get the name of the file? – eyllanesc Aug 18 '19 at 07:30
  • @SamiaRuponti Sorry, how to run your application to? – S. Nick Aug 18 '19 at 07:33
  • I'll give you the solution: 1) create a signal in CreateFormElements: `filenameChanged = pyqtSignal(str)`, 2) delete `self.line_edit.textChanged.connect(self.get_file_name)` 3) change `el_save_button.clicked.connect(self._controller.update_filename)` to `el_save_button.clicked.connect(self._controller.get_file_name)` – eyllanesc Aug 18 '19 at 07:34
  • @S.Nick I'll post the `app.py` too @eyllanesc I was trying to return the filename through `get_file_name` in the `CreateFormElements` object. – Samia Ruponti Aug 18 '19 at 07:35
  • 4) change `return fileName` to `self.filenameChanged.emit(fileName)` 5) change `@pyqtSlot(bool)` to `@pyqtSlot(str)` – eyllanesc Aug 18 '19 at 07:35
  • @eyllanesc I have updated my code, please take a look. the current error is `AttributeError: 'AddNewItemController' object has no attribute 'line_edit'` in the controller. I think I have to get the filename from the factory to view to model but I don't know how I can do that. thanks for your help. – Samia Ruponti Aug 18 '19 at 10:18
  • @SamiaRuponti I don't know why you moved the get_file_name function, I didn't tell you that. – eyllanesc Aug 18 '19 at 10:19
  • `el_save_button.clicked.connect(self._controller.get_file_name)` gets the function from the controller. the function was written in the factory. that's why I moved it. – Samia Ruponti Aug 18 '19 at 10:20
  • I already gave you the detailed solution if you don't follow it then I won't be able to help you, so I'll continue on my way, bye. – eyllanesc Aug 18 '19 at 10:21
  • It seems that you do not know how to design classes, I recommend you learn to model UML, take a class course, etc. For example according to your current logic: `class AddNewItemController(QObject): .... def get_file_name(self): filePath = self.line_edit.text() ...` AddNewItemController has `line_edit` as an attribute and clearly that is **FALSE** – eyllanesc Aug 18 '19 at 10:25
  • 1
    if you don't want to help, that's fine. but please do follow the conversation. I have already admitted I don't know how to transfer the value from the factory to view. I know it is false, I asked for help to know how to correct that. – Samia Ruponti Aug 18 '19 at 10:29

0 Answers0