7

I designed a basic UI in the QtDesigner. Now i am trying to pop a simple file dialog on click of a button, below given is my GUI Code :

from PySide2 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
 def setupUi(self, MainWindow):
.....
.....

  self.input_Image_GraphicsView = QtWidgets.QGraphicsView(self.centralwidget)
  self.input_Image_GraphicsView.setGeometry(QtCore.QRect(730, 110, 480, 320))
  self.input_Image_GraphicsView.setObjectName("input_Image_GraphicsView")
......
  self.output_Image_GraphicsView = QtWidgets.QGraphicsView(self.centralwidget)
  self.output_Image_GraphicsView.setGeometry(QtCore.QRect(730, 480, 480, 320))
  self.output_Image_GraphicsView.setObjectName("output_Image_GraphicsView")
......
  self.file_Select_Btn = QtWidgets.QPushButton(self.centralwidget)
  self.file_Select_Btn.setGeometry(QtCore.QRect(1082, 80, 121, 28))
  self.file_Select_Btn.setObjectName("file_Select_Btn")
  self.file_Select_Btn.clicked.connect(self.selectFile)
.....
.....
 def selectFile():
  self.path_To_File = QtWidgets.QFileDialog.getOpenFileName(self, QtCore.QObject.tr("Load Image"), QtCore.QObject.tr("~/Desktop/"), QtCore.QObject.tr("Images (*.jpg)"))
  print(self.path_To_File)
.....
.....

if __name__ == "__main__":
 import sys
 app = QtWidgets.QApplication(sys.argv)
 MainWindow = QtWidgets.QMainWindow()
 ui = Ui_MainWindow()
 ui.setupUi(MainWindow)
 MainWindow.show()
 sys.exit(app.exec_()) 

This is the error that i get :

TypeError: descriptor 'tr' requires a 'PySide2.QtCore.QObject' object but received a 'str'

When i wasnt using the 'tr', I was getting :

TypeError: 'PySide2.QtWidgets.QFileDialog.getOpenFileName' called with wrong 
argument types:
PySide2.QtWidgets.QFileDialog.getOpenFileName(Ui_MainWindow, str, str, str)
Supported signatures:
PySide2.QtWidgets.QFileDialog.getOpenFileName(PySide2.QtWidgets.QWidget = None, str = '', str = '', str = '', str = '', PySide2.QtWidgets.QFileDialog.Options = Default(QFileDialog.Options))

I have read the python documentation for Qt ver 5.12 given here : https://doc.qt.io/qtforpython/PySide2/QtWidgets/QFileDialog.html

That didnt help either. Where did i go wrong??

Basically i want to :

  1. Get a FileDialog -> Select an JPG File
  2. Get the path of the file in python code -> Populate a GraphicsView with the image on the GUI

I am currently struggling with both the aspects

Any help will be appreciated..

Dravidian
  • 9,945
  • 3
  • 34
  • 74

1 Answers1

8

You should not mix your program logic with the generated UI files, instead, create a QMainWindow class wrapper and inherit from both QMainWindow and the UI class.

As per your actual problem, you were just missing a reference to an object (for example, self) before passing the text to translate, I added a small helper method to handle that in the following example:

import sys
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import QObject, QRectF, Qt
from PySide2.QtWidgets import QMainWindow, QFileDialog, QWidget, QVBoxLayout, QGraphicsScene, QGraphicsView
from PySide2.QtGui import QPixmap


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
        self.file_Select_Btn = QtWidgets.QPushButton(self.centralWidget)
        self.file_Select_Btn.setGeometry(QtCore.QRect(1082, 80, 121, 28))
        self.file_Select_Btn.setObjectName("file_Select_Btn")
        self.file_Select_Btn.setText("Load Image")
        self.gridLayout.addWidget(self.file_Select_Btn)
        MainWindow.setCentralWidget(self.centralWidget)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        Ui_MainWindow.__init__(self)
        QMainWindow.__init__(self)

        # Initialize UI
        self.setupUi(self)
        self.file_Select_Btn.clicked.connect(self.showImage)

    def tr(self, text):
        return QObject.tr(self, text)

    def showImage(self):
        path_to_file, _ = QFileDialog.getOpenFileName(self, self.tr("Load Image"), self.tr("~/Desktop/"), self.tr("Images (*.jpg)"))

        self.image_viewer = ImageViewer(path_to_file)
        self.image_viewer.show()


class ImageViewer(QWidget):
    def __init__(self, image_path):
        super().__init__()

        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        layout = QVBoxLayout()
        layout.addWidget(self.view)
        self.setLayout(layout)

        self.load_image(image_path)

    def load_image(self, image_path):
        pixmap = QPixmap(image_path)
        self.scene.addPixmap(pixmap)
        self.view.fitInView(QRectF(0, 0, pixmap.width(), pixmap.height()), Qt.KeepAspectRatio)
        self.scene.update()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())
Isma
  • 14,604
  • 5
  • 37
  • 51
  • Thanks for your reply. I will try and replicate your efforts in my code, and will get back to you. In the mean time, could you please elaborate if there is any specific reason to your suggestion *You should not mix your program logic with the generated UI files*. Thanks. – Dravidian Mar 25 '19 at 09:58
  • 1
    Because the UI files can be overwritten by the generator and then you will lose all your specific code, also, it makes the program easier to read and maintain because you can split the look and feel from the logic, another reason I can think of right now is that it allows you to reuse the same UI files for different implementations (or even different applications). – Isma Mar 25 '19 at 10:05
  • +1 Thanks your solution works perfectly for the 1st part of my problem. Could you help me out with the 2nd part as well?? Thanks – Dravidian Mar 25 '19 at 10:19
  • Sorry to trouble you further, but i have two GraphicsView in the UI window(Code updated in the qustion), and i would like to have a common class which could load an image in either one of them. Thanks – Dravidian Mar 25 '19 at 11:22
  • 1
    You also need to add a scene and then simply implement the method load_image inside your MainWindow class and use the corresponding GraphicsView – Isma Mar 25 '19 at 12:56