How to Import Pyqt5 Widget In Another File - python

First File first.py
import pyqt5py
ret=pyqt5py.confirm()
print(ret)
Second File Having PYQT5 name: pyqt5py.py
import sys
from PyQt5 import QtWidgets, uic
class Ui(QtWidgets.QDialog):
def __init__(self,button1='Ok',button2='Cancel',text='Are You Sure?'):
super(Ui, self).__init__() # Call the inherited classes __init__ method
uic.loadUi('dialog.ui', self) # Load the .ui file
# Show the GUI
self.pushButton1.clicked.connect(lambda: self.click(1))
self.pushButton2.clicked.connect(lambda: self.click(2))
self.label.setText(text)
self.pushButton1.setText(button1)
self.pushButton2.setText(button2)
self.show()
def click(self,args):
print(self)
return self.sender().text()
app = QtWidgets.QApplication(sys.argv) # Create an instance of QtWidgets.QApplication
def confirm():
def pressed():
return 'clicked'
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?') # Create an instance of our class
print(window)
window.pushButton1.clicked.connect(pressed)
app.exec_() # Start the application
but i dont know what changes should i do make my first.py to work,i have correctly made the pyqt5 file but i dont know how to add def to call it for confirm
#######################
I Updated My Second File

As suggested by bfris you should rewrite the last lines of pyqt5py.py as follows:
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?')
app.exec_()
That way you can run this file directly for debbugging purposes, but also import it elsewhere.
To use your widget in first.py you need to create an instance of it there.
first.py:
from pyqt5py.py import UI
app = QtWidgets.QApplication(sys.argv)
window = Ui(button1='Ok',button2='Cancel',text='Are You Sure?')
app.exec_()
Usually I use a QDialog within a Qt environment where it is opened from a QMainWindow and also returning which button was clicked to the QMainWindow.
However as I understand you would like to run another program and in between open your UI? I am not experienced doing that but it seems to me that its exec method does exactly that though you should read this discussion about a bug related to it.
Alternatively in first.py you connect the pushbutton's clicked signal to a slot, a function there.

Related

How to access components from another module with PyQt6?

I made a minimum working environment for this question.
First I have this UI file (GDrive Link),which I'll later load in my UI.py., which I'll later load in my
The UI.py goes thus:
import sys
from PyQt6.QtWidgets import QMainWindow, QApplication, QPlainTextEdit
from PyQt6 import uic
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.ui = uic.loadUi(r"C:\Documents\Qt Designer\mwe.ui") # Change it to yoour own .ui
self.txtBox = self.findChild(QPlainTextEdit, 'plainTextEdit')
self.ui.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
import main
sys.exit(app.exec())
Essentially, what I want to do is to access this PlainTextEditor in main.py, becuase that's where I'll write the functions.
import UI
UI.Window.txtBox.insertPlainText('foo')
But when I try to run UI.py, I get this error:
Traceback (most recent call last):
File "C:\Users\Me\PycharmProjects\dynamic_ui_foo\UI.py", line 18, in <module>
import main
File "C:\Users\Me\PycharmProjects\dynamic_ui_foo\main.py", line 3, in <module>
UI.Window.txtBox.insertPlainText('foo')
AttributeError: type object 'Window' has no attribute 'txtBox'
It says Window doesn't have this attribute. How do I access the components from another module? And am I going in the right way by separating UI codes and function codes (I know the cross-importing looks terrible).
To illustrate your error message, consider the following example:
class bla:
def __init__(self):
self.foo = 'test'
print(bla.foo) # <-- results in your error
b = bla()
print(b.foo) # <-- this is what you would like to access
Right now you are trying to access txtBox of the class Window, but you need to access txtBox from your instance window.
However, I have doubts about it working in the way you do your imports.
I would suggest to move
if __name__ == "__main__":
app = QApplication(sys.argv)
window = UI.Window()
sys.exit(app.exec())
to main.py. Use UI.py to only define the layout. Changing the text txtBox can be implemented either as a method of Window:
class Window(QMainWindow):
# init code
def change_content(self, content):
self.txtBox.insertPlainText(content)
Then in main you call that:
if __name__ == "__main__":
app = QApplication(sys.argv)
window = UI.Window()
window.change_content()
sys.exit(app.exec())
Of course you can use a more direct approach:
if __name__ == "__main__":
app = QApplication(sys.argv)
window = UI.Window()
window.txtBox.insertPlainText(content)
sys.exit(app.exec())
The last example seems to be easier. But that way, if you change txtBox to something else you need to keep in mind to also do changes in main.py. With the first example you only have to do changes in UI.py.
Edit:
Added missing argument self. Thanks to musicamante for pointing that out.

How do I draw a plot using pyqtgraph on PyQt4 widget created in QT Designer?

I'm just starting with pyqtgraph. I have a graphicsView widget that I promoted with QT designer per the documentation. I would like to try a plot to see if it works. When I tried pg.plot(x,y) the program created a plot in a separate window rather than in the graphicsView widget. I'm using Windows 10, PyQt4, and Python 2.7. What am I doing wrong?
from PyQt4 import QtGui
from PyQt4 import QtCore
import ui_test #Gui File
import sys
import pyqtgraph as pg
class Gui(QtGui.QMainWindow, ui_test.Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self) # This is defined in ui_pumptest.py file automatically
self.plot()
def plot(self):
vb = pg.ViewBox()
self.graphicsView.setCentralItem(vb)
def main():
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = Gui() # We set the form to be our ExampleApp (design)
form.show() # Show the form
app.exec_() # and execute the. app
if __name__ == '__main__': # if we're running file directly and not importing it
main() # run the main function
Can you share the ui_pumptest.py file source? Otherwise it's hard to tell what your intentions are. If not, at least detail what construct you used to place in the QGraphicsView promotion process in QtDesigner (assuming you followed http://www.pyqtgraph.org/documentation/how_to_use.html#embedding-widgets-inside-pyqt-applications).
pg.plot creates it's own plotwindow->plotwidget structure, so that's why you're getting a separate window if calling that. The item you call plot on should be the container object name that was promoted in your Qt Ui file.

PySide \ PyQt: How to return value to UI after button click?

I am trying to return a path from a browse folder dialog box.
I have tried passing the instance object or even attribute to the call and setting it there:
self.browseBtn.clicked.connect(myExporter.browseFolder(self))
or
self.browseBtn.clicked.connect(myExporter.browseFolder(self.path))
But this doesn't work. It causes the browser dialog to pop open immediately upon load and then once you choose a folder it errors out with : Failed to connect signal clicked().
I have tried to set the clicked call to a return, with no luck:
result = self.browseBtn.clicked.connect(myExporter.browseFolder)
Can someone lead me in the right direction as far as how to return a value, when you are dealing with separate classes handling the UI and logic? Also... is it bad practice to be separating them like this? I know I could probably easily solve this if I threw everything into just one python file, but I figured that is not proper.
Here is my ui file (ui.py):
from PySide import QtCore, QtGui
class Ui_Dialog(object):
def __init__(self):
self.path =""
def setupUi(self, Dialog, myExporter):
Dialog.setObjectName("Dialog")
Dialog.resize(382, 589)
...
.......
.............
.................
self.retranslateUi(Dialog)
self.tabWidget.setCurrentIndex(1)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.browseBtn.clicked.connect(myExporter.browseFolder)
Here is my exporter file (exporter.py):
class Exporter(object):
def __init__(self):
...
......
def browseFolder(self):
...
.......
do something
...........
return path
Here is my load/test file (loadExporter.py):
import ui as interface
import exporter as exporter
from PySide import QtCore, QtGui
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
myExporter = exporter.Exporter()
myUI = interface.Ui_Dialog()
myUI.setupUi(Dialog, myExporter)
Dialog.show()
app.exec_()
It's not necessarily bad to have them in separate files. Having a separate file for certain widgets is a good thing especially if those widgets can be reused.
I would have my main file have a QMainWindow class.
class MyWindow(QtGui.QMainWindow):
pass
if __name__ == "__main__":
QtGui.QApplication([])
mywindow = MyWindow()
mywindow.show()
sys.exit(QtGui.qApp.exec_())
Wrapping the app functionality in if __name__ == "__main__" prevents this code from being run when another file tries to import this file.
A signal (self.browserBtn.clicked) calls a callback method. Everything is an object in python.
def my_func():
pass
new_func_name = my_func # my_func can be reassigned like any variable
my_func is an object. self.browseBtn.clicked.connect(my_func) passes my_func as a variable to be called later.
When self.browserBtn.clicked.emit() happens (on user click) it is the same as calling the connected functions my_func(). Other signals may pass values to callback functions self.lineEdit.textChanged.connect(my_func) calls 'my_func(new_text)'
You want your function to call everything for you.
def open_file(filename=None):
"""Open a file."""
# If a filename isn't given ask the user for a file
if filename is None:
filename, ext = QtGUi.QFileDialog.getOpenFileName(None, "Open File", ".../My Documents/")
# You may have to use the ext to make a proper filename
# Open the file
with open(filename, "r") as file:
file.read()
self.browserBtn.clicked.connect(open_file)
Structure
...
import mywidget
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super().__init__()
...
self.show_file = QtGui.QLineEdit()
self.setCentralWidget(self.show_file)
self.exporter = mywidget.Exporter()
self.browserBtn.clicked.connect(self.open_file)
def open_file(self, filename=None):
"""Open a file."""
path = self.exporter.browseFolder()
# Do something with the path
self.show_file.setText(path)
if __name__ == "__main__":
QtGui.QApplication([])
mywindow = MyWindow()
mywindow.show()
sys.exit(QtGui.qApp.exec_())
I don't think I fully understand what you're trying to achieve, but may I suggest the following solution.
exporter.py
# implementation
dialog.py (Main UI)
import PyQt4.QtGui as qg
from exporter import Exporter
class Dialog(qg.QDialog):
def __init__(self):
super().__init__()
self.path = None
self.setup_widgets()
def setup_widgets(self):
self.browse.clicked.connect(self.on_browse_clicked)
def on_browse_clicked(self):
self.path = Exporter().browse_folder()
main.py
import sys
import PyQt4.QtGui as qg
from dialog import Dialog
if __name__ == '__main__':
app = qg.QApplication(sys.argv)
dialog = Dialog()
dialog.show()
sys.exit(app.exec_())
This way you still have three files, but dialog.py imports exporter.py instead of main.py importing both of them.
As for returning values from signals, I don't know; I think signals are voids (do not return values).
Signals pass arguments to slots via their formal parameters. Usually slots have the same or fewer parameters than their signal counterparts'. It's slots that return values.

PyQt4 app button not working

I'm trying to set up an app in Linux using PyQt4 designer and I'm struggling to connect signals and slots to it. Right now all I want it to do is connect a button clicked signal to a custom slot, saveEnergyScheme which simply prints 'energy list' to the terminal.
I've translated the .ui code for my app to a python class with pyuic4 -w sumcorr.ui > sumcorr_ui.py. This created a class in the sumcorr_ui.py module called SumCorr_ui:
class SumCorr_ui(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QMainWindow.__init__(self, parent, f)
self.setupUi(self)
I then made my app as a custom widget and tried to add a simple signal-slot connection to a button to show it works:
from PyQt4 import QtGui, QtCore
from sumcorr_ui import SumCorr_ui
class SumCorr(SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = QtGui.QMainWindow()
ui = SumCorr()
ui.setupUi(mySumCorr)
mySumCorr.show()
sys.exit(app.exec_())
I expect to get the line 'energy list' when I click the button named save_energies_button, but nothing happens. Could this be because I haven't built the UI as a widget, but as a main window? Why doesn't it print out??
Try to add ui.show() and you'll see that your code is creating two different windows, one should have the signal connected and one doesn't. That's because you are showing only the mySumCorr window, but you call only setupUi on it, which does not connect the signal.
When you create the SumCorr instance, you are creating a window and setting it up, then, by no reason, you do ui.setupUi(mySumCorr), which setups the mySumCorr instance without connecting the signal, and you show this last window.
I believe your code should be like this:
class SumCorr(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.setupUi(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = SumCorr()
mySumCorr.show()
sys.exit(app.exec_())
Note that it doesn't make any sense to have a SumCorr_ui class, that's because Qt is a UI library so you are just introducing a worthless level of abstraction. The designer file already gives you an abstraction over the ui layout.

How to call multiple Dialogs in PyQt?

I have a main dialog and on that dialog there is a button. When the button is clicked, I want to open an another dialog.
Main Dialog code (Function which is called when the button is clicked in the main dialog):
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
default function:
if __name__ == "__main__":
import sys
global app
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
Secondary dialog (add_host.py) code snapshot:
def main(self):
app1 = QtGui.QApplication(sys.argv)
Dialog1 = QtGui.QDialog()
ui1 = Ui_Dialog1()
ui1.setupUi1(Dialog1)
Dialog1.show()
sys.exit(app.exec_())
So when I run the code, it opens the secondary dialog but when I close it, it just freezes, and I get this error message:
File "testbot.py", line 175, in add_host
x.main()
File "/home/ppp/ppp/add_host.py", line 74, in main
sys.exit(app.exec_())
NameError: global name 'app' is not defined
Which does make sense, but I have no idea how to resolve it. I try several combinations without success, including adding and deleting app.exec_().
You cannot create multiple QApplications inside of the same script and thread. You are only supposed to have one...
This should be more like:
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
No global app. Although you should be doing your setupUI from within the class of your dialog.
Then when you want to show another dialog from with your app...say main(), you just create it and call show()
Here is a really basic example:
class Dialog(QDialog)
def __init__(self, parent):
super(Dialog, self).__init__(parent)
self.otherDialog = QDialog(parent=self)
self.otherDialog.show()
if __name__ == "__main__":
app = QApplication([])
dialog = Dialog()
dialog.show()
app.exec_()
You create a single QApplication and start its event loop by calling exec_(). From that point on, your main application is free to create more QWidgets. You never create another QApplication again at this point.
Also, I dont understand this part of your code:
def add_host(self):
x=add_host.Ui_Dialog1()
x.main()
The fact that you are calling a main() method on your UI object makes me think you are modifying the UI file and adding functionality to it, which you should not be doing. That ui file is subject to be overwritten every time you make changes in QT Designer and save out a new one. You should only be importing it and using its setupUI() method to apply it to your own custom classes.
A note about organization of your modules
When you are designing a PyQT application, you will always have a single entry point that will be called to start your app. This is the single and only location that should be creating your QApp and starting the event loop, and is usually done with in a if __name__ == "__main__" block to ensure its only done when its the main script. It should not be done within methods of your objects. For all your other modules where you define other Dialog, Widgets, etc, these should simply be classes that you import. As long as you have a running QApp, you are free to create and show these widgets.
Your code sample is a bit confusing - I don't understand why you have two mains, etc - anyway, maybe it's just a typo in add_host.py (app1.exec_() instead of app.exec_())
def main(self):
app1 = QtGui.QApplication(sys.argv)
...
sys.exit(app1.exec_())

Categories