I have created 2 new widgets/windows in pyqt, from my my main window. Now I would like to access my methods in mainwindow class to my new widgets. How can I do this?
Here is my code:
from UI_NewProject import Ui_widget
from UI_OpenNew import Ui_Form
# Main Class
class MainClass(QtGui.QMainWindow, UI_Main.Ui_MainWindow):
def __init__(self, parent=None):
super(MainClass, self).__init__(parent)
self.setupUi(self)
self.openFile.triggered.connect(self.on_pushButton_clicked)
def on_pushButton_clicked(self):
connectClass = openNew(self)
connectClass.show()
def funcfromMain(self):
filters = ('Data Files (*.csv *.txt *.xls *.xml *.xlsx *.xlsm)',)
path, filter = QtGui.QFileDialog.getOpenFileNameAndFilter(
self, 'Open File', '', ';;'.join(filters))
self.nameFile = os.path.basename(path)
if (".csv" or ".txt") in path:
with open(path, 'rb') as drate:
self.Datas = pd.read_csv(drate, index_col=0)
if (".xls" or ".xml" or ".xlsx" or ".xlsm") in path:
with open(path, 'rb') as drate:
self.Datas = pd.read_excel(drate, index_col=0)
#New Widget/Window class 1
class openNew(QtGui.QMainWindow, Ui_Form):
#from UI_OpenNew import Ui_Form
def __init__(self, parent = None):
super(openNew, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setupUi(self)
# Create New Project
self.pushButton_2.clicked.connect(self.on_Button_clicked)
self.pushButton.clicked.connect(MainClass.funcfromMain) #this is funtion in MainClass and I want to access it Here
def on_Button_clicked(self):
Win = NewProject(self)
Win.show()
#New Widget/Window class 2
class NewProject(QtGui.QMainWindow, Ui_widget):
#from UI_NewProject import Ui_widget
def __init__(self, parent = None):
super(NewProject, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setupUi(self)
self.pushButton_2 and self.pushButton are from the corresponding UI files.
Now I want to connect buttons like these in the New UI files to methods in MainClass, So any Ideas on how I can achieve this?
Error: (with parent.func)
TypeError: QFileDialog.getOpenFileNameAndFilter(QWidget parent=None, str caption='', str directory='', str filter='', str initialFilter='', QFileDialog.Options options=0) -> (str, str): argument 1 has unexpected type 'bool'
Update 1:
I tried using Mixin Class but my main file is so big and I want like 6-7 methods of main in the new widgets so, any ideas of how I can approach this?
In MainClass you must make the connection: connectClass.pushButton.clicked.connect(self.funcfromMain)
from PyQt4 import QtGui
from UI_NewProject import Ui_widget
from UI_OpenNew import Ui_Form
# New Widget/Window class 2
class NewProject(QtGui.QMainWindow, Ui_widget):
# from UI_NewProject import Ui_widget
def __init__(self, parent=None):
super(NewProject, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setupUi(self)
# New Widget/Window class 1
class openNew(QtGui.QMainWindow, Ui_Form):
# from UI_OpenNew import Ui_Form
def __init__(self, parent=None):
super(openNew, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setupUi(self)
# Create New Project
self.pushButton_2.clicked.connect(self.on_Button_clicked)
def on_Button_clicked(self):
Win = NewProject(self)
Win.show()
# Main Class
class MainClass(QtGui.QMainWindow, UI_Main.Ui_MainWindow):
def __init__(self, parent=None):
super(MainClass, self).__init__(parent)
self.setupUi(self)
self.openFile.triggered.connect(self.on_pushButton_clicked)
def on_pushButton_clicked(self):
connectClass = openNew(self)
connectClass.pushButton.clicked.connect(self.funcfromMain)
connectClass.show()
def funcfromMain(self):
pass
Related
I am just trying to send a signal from the class A to class B but it does not work, I don't see the print.
I am certainly doing something wrong but I did know what. Here is a quick code to show you the problem, thank you.
from PyQt5 import QtWidgets, QtCore
import sys
class B(object):
def __init__(self, parent=None):
super(B, self).__init__(parent)
self._initSlot()
def _initSlot(self):
a = A()
a.assetSelectionChanged.connect(self._doSomething)
#QtCore.pyqtSlot()
def _doSomething(self):
print('do something')
class A(QtWidgets.QWidget):
assetSelectionChanged = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(A, self).__init__(parent)
self._initUI()
def _initUI(self):
self.treeWidgetAssets = QtWidgets.QTreeWidget()
for i in range(1, 11, 1):
QtWidgets.QTreeWidgetItem(self.treeWidgetAssets, [str(i)])
self.mainLayout = QtWidgets.QVBoxLayout()
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.treeWidgetAssets)
self.treeWidgetAssets.itemSelectionChanged.connect(self.onAssetSelectionChanged)
def onAssetSelectionChanged(self):
self.assetSelectionChanged.emit()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dlg = A()
dlg.show()
sys.exit(app.exec_())
There are various problems with that code:
No instance of B is ever created
direct object subclasses don't require calling super().__init__(), and even if you do that you should certainly not add arbitrary arguments, as they won't be accepted, resulting in a crash
B should inherit from QObject
No new instance should be declared in _initSlot: there already exists one, and the one you're creating there will be immediately garbage collected because its reference is local and will be deleted immediately after _initSlot returns
class B(QtCore.QObject):
def __init__(self, parent=None):
super(B, self).__init__(parent)
self._initSlot()
def _initSlot(self):
if self.parent():
self.parent().assetSelectionChanged.connect(self._doSomething)
#QtCore.pyqtSlot()
def _doSomething(self):
print('do something')
class A(QtWidgets.QWidget):
assetSelectionChanged = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(A, self).__init__(parent)
self._initUI()
self.b = B(self)
# ...
As an variant. I've marked the lines that I changed for you.
import sys
from PyQt5 import QtWidgets, QtCore
class B(QtCore.QObject):
def __init__(self, parent=None):
super(B, self).__init__(parent)
# self._initSlot()
# def _initSlot(self):
# a = A()
# a.assetSelectionChanged.connect(self._doSomething)
#QtCore.pyqtSlot(str)
def _doSomething(self, text):
print(f'do something: clicked -> {text}')
class A(QtWidgets.QWidget):
assetSelectionChanged = QtCore.pyqtSignal(str) # 1. + str
def __init__(self, parent=None):
super(A, self).__init__(parent)
self._initUI()
self.b = B(self) # !!!
self.assetSelectionChanged[str].connect(self.b._doSomething) # 3. + str
def _initUI(self):
self.treeWidgetAssets = QtWidgets.QTreeWidget()
for i in range(1, 11, 1):
QtWidgets.QTreeWidgetItem(self.treeWidgetAssets, [str(i)])
self.mainLayout = QtWidgets.QVBoxLayout()
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.treeWidgetAssets)
self.treeWidgetAssets.itemSelectionChanged.connect(self.onAssetSelectionChanged)
def onAssetSelectionChanged(self):
text = self.treeWidgetAssets.selectedItems()[0].text(0)
self.assetSelectionChanged.emit(text) # 2. + text
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dlg = A()
dlg.show()
sys.exit(app.exec_())
I have a menubar in the mainwindow class which I want to use to select a file directory. Once the file directory is selected it should call a function in the ui class to load the filenames into the list box. The filepath is being sent to the other function but the list doesn't load any items. My code is below thanks in advance.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
import sys
import os
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui_widget = ui(parent=self)
self.setCentralWidget(self.ui_widget)
# filling up a menu bar
bar = self.menuBar()
# File menu
file_menu = bar.addMenu('File')
# adding actions to file menu
images_dir = QtWidgets.QAction('Set Images Dir', self)
close_action = QtWidgets.QAction('Close', self)
file_menu.addAction(images_dir)
# use `connect` method to bind signals to desired behavior
close_action.triggered.connect(self.close)
images_dir.triggered.connect(self.set_images_dir)
def set_images_dir(self):
filepath = QFileDialog.getExistingDirectory(self,"Select Directory")
if filepath:
filepath=filepath+'/'
ui().image_dir_select(filepath)
self.image_dir=filepath
return
class ui(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
QWidget.__init__(self)
layout = QGridLayout()
self.setLayout(layout)
self.listwidget = QListWidget()
layout.addWidget(self.listwidget)
def image_dir_select(self, image_dir):
filelist=os.listdir(image_dir)
self.listwidget.clear()
filelist=list(set(filelist))
filelist.sort()
self.listwidget.addItems(filelist)
app = QApplication(sys.argv)
screen = MainWindow()
screen.show()
sys.exit(app.exec_())
You have to call the image_dir_select of the existing ui_widget, but you're doing it against a new instance.
Change this:
ui().image_dir_select(filepath)
To this:
self.ui_widget.image_dir_select(filepath)
I must say it is a very beginner's question. I have read and tried a lot, but still don't understand how Slot+Signal work.
In my following code I want to transfer three variables from MyApp Class into Worker Class, when the button is clicked.
The code does not work.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Worker(QObject):
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
#pyqtSlot(str, str, int)
def onJob(self, strA, strB, int1):
print(strA, strB, int1)
for i in range(40):
print(i)
class MyApp(QWidget):
def __init__(self, parent= None):
super(MyApp, self).__init__(parent)
self.initUI()
def initUI(self):
self.btn = QPushButton("start", self)
self.btn.clicked.connect(self.start)
self.show()
def start(self):
otherClass = Worker()
self.signal = pyqtSignal(str, str, int)
self.signal.emit("foo", "baz", 10)
self.signal.connect(otherClass.onJob)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
Your code has the following errors:
A signal must not be declared in any method of the class, it must be on the same level as the methods.
If I send a signal before connecting it to any slot then nobody will listen to the information so the data will be lost, that is, the transmission of data is almost instantaneous.
In the following code I have implemented the necessary modifications to make it work:
class MyApp(QWidget):
signal = pyqtSignal(str, str, int)
def __init__(self, parent= None):
super(MyApp, self).__init__(parent)
self.initUI()
def initUI(self):
self.btn = QPushButton("start", self)
self.btn.clicked.connect(self.start)
self.show()
def start(self):
otherClass = Worker()
self.signal.connect(otherClass.onJob)
self.signal.emit("foo", "baz", 10)
I am trying to create a toolbar that can be modified to change actions on the fly.
However signals are not being sent when I add actions from outside the class that creates the toolbar.
In the example below the new action is never triggered. Any idea on how this can be done?
import sys
from PyQt4 import QtGui
from toolbarmodifier import ToolbarModifier
class FluidToolbar(QtGui.QMainWindow):
def __init__(self):
super(FluidToolbar, self).__init__()
self.initUI()
def initUI(self):
createAction = QtGui.QAction( 'create Action', self)
createAction.triggered.connect(self.createActions)
self.toolbar = self.addToolBar('create Action')
self.toolbar.addAction(createAction)
self.setGeometry(300, 300, 300, 200)
self.show()
def createActions(self):
print(">>createActions()")
toolbarModifier = ToolbarModifier()
toolbarModifier.addAction(self)
def main():
app = QtGui.QApplication(sys.argv)
ex = FluidToolbar()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
toolbarmodifier.py
from PyQt4 import QtGui
from PyQt4.QtGui import QWidget
class ToolbarModifier(QWidget):
def __init__(self):
super(ToolbarModifier, self).__init__()
def newActionTriggered(self):
print(">>newActionTriggered()")
def addAction(self, gui):
triggerAction = QtGui.QAction( 'New action', gui)
triggerAction.triggered.connect(self.newActionTriggered)
gui.toolbar.addAction(triggerAction)
print("<<addAction()")
Not having a link back to parent was the issue. In FluidToobar modify code in createActions method to include self in call:
toolbarModifier = ToolbarModifier(self)
In ToolbarModifier change first few lines to:
class ToolbarModifier(QtCore.QObject):
def __init__(self, parent=None):
super(ToolbarModifier, self).__init__(parent)
I wrote a few customized widget classes by subclassing QWidget. I created a few customized widgets using them and added them to a QToolBox.
class BaseWidget(QtGui.QWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
pass
class AWidget(BaseWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
print "A"
class BWidget(BaseWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
print "B"
Now I want to loop over all the widgets added to the QToolBox and call a method of these customized widgets:
class toolboxWidget(QtGui.QToolBox):
def __init__(self, parent=None):
super(toolboxWidget, self).__init__(parent=parent)
a = AWidget(self)
b = BWidget(self)
self.addItem(a, "A")
self.addItem(b, "B")
def printMethod(self):
for i in range(self.count()):
self.widget(i).mymethod()
However, since widget() method of QToolBox only returns objects of QWidget type, when calling printMethod() of toolboxWidget object, it gives the following error:
AttributeError: 'QWidget' object has no attribute 'mymethod'.
Is there a way I can convert the QWidget returned by widget() to BaseWidget objects? Thanks.
After fixing all the obvious errors and omissions in your example code, I was able to get it working without any problems.
If the QToolBox.widget method didn't return an instance of one of your BaseWidget subclasses, it would be a bug in PyQt (or sip).
Here is a script that works for me using sip 4.15.4 and PyQt 4.10.3:
from PyQt4 import QtCore, QtGui
class BaseWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
def mymethod(self):
pass
class AWidget(BaseWidget):
def __init__(self, parent=None):
BaseWidget.__init__(self, parent)
def mymethod(self):
print "A"
class BWidget(BaseWidget):
def __init__(self, parent=None):
BaseWidget.__init__(self, parent)
def mymethod(self):
print "B"
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.toolbox = QtGui.QToolBox(self)
a = AWidget(self.toolbox)
b = BWidget(self.toolbox)
self.toolbox.addItem(a, "A")
self.toolbox.addItem(b, "B")
self.button = QtGui.QPushButton('Test', self)
self.button.clicked.connect(self.printMethod)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.toolbox)
layout.addWidget(self.button)
def printMethod(self):
for i in range(self.toolbox.count()):
self.toolbox.widget(i).mymethod()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 300)
window.show()
sys.exit(app.exec_())