Python MainWindow class can't find attribute - python

I am building a GUI application and I've been trying to debug the code and test it but it keeps throwing me this error saying. I added a button function to the MainWindow class which is 'self.AddtoCart.clicked.connect(self.addCart)' but now it won't open.
'MainWindow' Object has no attribute 'addCart'.
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
self.Addtocart.clicked.connect(self.addCart)
def addcart(self):
style = self.comboBox_6.currentText()
name = self.lineEdit_10.text()
color = self.lineEdit_11.text()
size = self.comboBox_7.currentText()
text = "style: {style}, name: {name}, color: {color}, size: {size}".format(style=style, name=name, color=color, size=size)
self.plainTextEdit.appendPlainText(text)

In your code, addcart() is not in the scope of MainWindow, since it is at the same indentation level. Indent the functions with a tab and addCart() will become an attribute of the class.

Related

class same signal connected to multiple instances

If I define a disable_signal = QtCore.pyqtSignal() outside of the custom button class, the behaviour I am looking for (all instance are disabled when clicked upon).
class CustomButton(QtWidgets.QToolButton):
def __init__(self, parent, disable_signal):
super(CustomButton, self).__init__(parent)
self.disable_signal = disable_signal
self.disable_signal.connect(self.disable)
self.pressed.connect(self.buttonPressed)
def buttonPressed(self):
self.disable_signal.emit()
#QtCore.pyqtSlot()
def disable(self):
print("received")
self.setEnabled(False)
However, if I define the signal as a class attribute, each instance behave as if they each had their individual signal (pressing upon one, disable only that one):
class CustomButton(QtWidgets.QToolButton):
disable_signal = QtCore.pyqtSignal()
def __init__(self, parent):
super(CustomButton, self).__init__(parent)
self.disable_signal.connect(self.disable)
self.pressed.connect(self.buttonPressed)
def buttonPressed(self):
self.disable_signal.emit()
#QtCore.pyqtSlot()
def disable(self):
print("received")
self.setEnabled(False)
I don't understand why the signal is not shared? I tried to use instead of self.disable_signal.connect(self.disable), CustomButton.disable_signal.connect(self.disable) but I get the error: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'.

PyQt6 - Open QWidget by left clicking the SystemTrayIcon

I am new to PyQt6 and python. I created a class SystemTrayIcon where I am trying to open a QWidget win which was created outside the SystemTrayIcon-class, to show up when the SystemTrayIcon got left-clicked.
I got this error: "name 'win' is not defined"
How can I fix this, that the win-QWidget which was created outside the class SystemTrayIcon will open when the SystemTrayIcon got left-clicked?
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *
import sys
import ui_main
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self, icon, win, parent=None):
QSystemTrayIcon.__init__(self, icon, parent)
self.setToolTip("Test SystemTray")
menu = QMenu(parent)
exit_ = menu.addAction("Exit")
exit_.triggered.connect(lambda: sys.exit())
self.setContextMenu(menu)
self.activated.connect(self.trayiconclicked)
def trayiconclicked(self, reason):
if reason == self.ActivationReason.Trigger:
print("SysTrayIcon left clicked")
win.show() ###### -> ERROR: (<class 'NameError'>, NameError("name 'win' is not defined"), <traceback object at 0x000001B04F5C9580>)
def run():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
win = QWidget()
tray_icon = SystemTrayIcon(QIcon("images/logo.png"), win)
tray_icon.setVisible(True)
tray_icon.show()
ui = ui_main.Ui_Form()
ui.setupUi(win, tray_icon.geometry().right(), tray_icon.geometry().bottom(),
tray_icon.geometry().width(), tray_icon.geometry().height())
ui.btn_close.clicked.connect(lambda: win.close())
sys.exit(app.exec())
if __name__ == '__main__':
run()
It should work now you need to make win its attribute before you call it
class SystemTrayIcon(QSystemTrayIcon):
def __init__(self, icon, win, parent=None):
QSystemTrayIcon.__init__(self, icon, parent)
self.setToolTip("Test SystemTray")
self.win = win # <----- name it whatever you want ie self.abc will also work
menu = QMenu(parent)
exit_ = menu.addAction("Exit")
exit_.triggered.connect(lambda: sys.exit())
self.setContextMenu(menu)
self.activated.connect(self.trayiconclicked)
def trayiconclicked(self, reason):
if reason == self.ActivationReason.Trigger:
print("SysTrayIcon left clicked")
self.win.show() # <--- if you named you attribute self.abc call self.abc here instead of self.win
NOTE:
to make a variable a attribute of a class you need to define it with self eg, here I want to have age as a attribute
class Person:
def __init__(self, name, age):
# assigning attributes
self.age = age
def some_method(self):
# here calling self.name will give you error because you didn't assign it as a attribute
print(self.name)
def some_method_1(self):
# here this will not give error as you have assigned it earlier as a attribute
print(self.age)
p = Person("Bob", 16)
p.some_method_1()
p.some_method()

Call a function from another class by clicking a button PyQt4

I have a checkbox and a run button. When the checkbox is checked, I want to run some functions by clicking the button. The problem is that the function is in another class outside the button's class. My example codes are as below.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Tab1Widget1(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.Tab1Widget1initUI()
def Tab1Widget1initUI(self):
self.setLayout(QGridLayout())
self.T1W1checkBox1 = QCheckBox('a', self)
self.layout().addWidget(self.T1W1checkBox1, 1, 0)
def run(self):
if self.T1W1checkBox1.isChecked() == True:
pass
class Tab1Layout(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QGridLayout())
self.group1 = Tab1Widget1(self)
self.layout().addWidget(self.group1, 0, 0)
btn = QPushButton('Run', self)
self.layout().addWidget(btn, 1, 0)
btn.clicked.connect(Tab1Widget1().run()) ##the problem is in this line.
class Page1(QTabWidget):
def __init__(self, parent=None):
super(Page1, self).__init__(parent)
self.tab1 = Tab1Layout()
self.addTab(self.tab1, "Tab1")
self.tab2 = QWidget()
self.tab3 = QWidget()
self.addTab(self.tab2, "Tab2")
self.addTab(self.tab3, "Tab3")
self.tab2_initUI()
self.tab3_initUI()
def tab2_initUI(self):
grid = QGridLayout()
self.tab2.setLayout(grid)
def tab3_initUI(self):
grid = QGridLayout()
self.tab3.setLayout(grid)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setGeometry(300, 200, 600, 370)
self.startPage1()
def startPage1(self):
x = Page1(self)
self.setWindowTitle("Auto Benchmark")
self.setCentralWidget(x)
self.show()
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
As you can see, I want to run the "run" function in "Tab1Widget1" class. However, the button is in "Tab1Layout" class.
When I run the codes, it returns to me "TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'"
If anyone knows how to solve this, pls let me know. Appreciated!
There is no problem in connecting any callable to a button click regardless of what object it is in. But your code has two specific problems. You write
btn.clicked.connect(Tab1Widget1().run())
The first problem here is that Tab1Widget1() is creating a new Tab1Widget1 but presumably you don't want that. You want to call run on the Tab1Widget1 you have already created and stored in self.group.
The second problem is that when you connect a signal you need to connect it to a callable: the method you want to call. Instead here you are calling the run method at connect time and trying to connect to the result of that call (which is None). So you are trying to connect the signal to None which will of course fail. You need to refer to the method without calling it: just remove the calling brackets.
Putting it together:
btn.clicked.connect(self.group1.run)
That seems to work.

wrong constructor argument type, PySide

Well I can't figure out this issue, I am tryinf to fix something more complicated, and suddenly python came up with this:
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWidget,self).__init__(parent)
self.initUI()
...
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mainWidget = MainWidget(MainWindow)
and my IDE is saying that:
File "/home/maze/Develop/StartApp/startapp.py", line 47, in __init__
super(MainWidget,self).__init__(parent)
TypeError: 'PySide.QtGui.QWidget' called with wrong argument types:
PySide.QtGui.QWidget(Shiboken.ObjectType)
Supported signatures:
PySide.QtGui.QWidget(PySide.QtGui.QWidget = None, PySide.QtCore.Qt.WindowFlags = 0)
I think, before it was working that way...
Could You show me whats it about? Thanks for Your time.
You are calling the MainWidget constructor with an object type as parameter instead of an object instance in the constructor of MainWindow.
You should have:
self.mainWidget = MainWidget(self)
instead of:
self.mainWidget = MainWidget(MainWindow)

PySide multi-window, get QStackWidget to work

I need to create multi-window GUI, first I tried it with QWidgets, but finally I discover QStackWidget tool I need to use. So Im trying to, but Ive got some problems. Thanks for Your time.
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
self.mainWidget = MainWidget()
self.searchWidget = SearchWidget()
self.sWidget = QStackedWidget()
self.sWidget.addWidget(self.mainWidget)
self.sWidget.addWidget(self.searchWidget)
self.initUI()
and calling setCurrentWidget from the sub_widget class:
class MainWidget(QWidget):
def __init__(self, parent=MainWindow):
super(MainWidget,self).__init__()
self.initUI()
def initUI(self):
searchButton = QPushButton('searchButton',self)
optionButton = QPushButton('optionButton',self)
quitButton = QPushButton('quitButton',self)
listButton = QPushButton('listButton',self)
searchButton.clicked.connect(self.goSearch)
hbox = QHBoxLayout()
hbox.addWidget(listButton)
hbox.addWidget(quitButton)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addWidget(searchButton)
vbox.addWidget(optionButton)
vbox.addLayout(hbox)
self.setLayout(vbox)
def goSearch(self):
self.parent().sWidget.setCurrentWidget(self.parent().searchWidget)
Ive got this message from IDE:
self.parent().sWidget.setCurrentWidget(self.parent().searchWidget)
AttributeError: 'PySide.QtGui.QStackedWidget' object has no attribute 'sWidget'
What is the thing Im doing wrong?
I'm going to comment on the code you posted here: http://pastebin.com/fBfS1X5m
An important thing to know is that you can put widgets within widgets and so on. For example:
class Widget(QWidget):
def __init__(self, parent=None):
layout = QVBoxLayout(self)
childWidget = QWidget(parent=self)
layout.addWidget(childWidget)
Just a quick note: You don't need setLayout if you pass self to the main layout constructor - via the docs.
Anyways, what I'm trying to illustrate here is that the QStackedWidget and the SearchWidget really shouldn't be a part of the MainWindow, but should live inside their own relevant widget that will handle switching between the QStackedWidget pages.
For example the MainWindow.__init__ would only look like this:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.mainWidget = MainWidget(self)
self.setCentralWidget(self.mainWidget)
self.initUI()
Your MainWidget would then look something like:
class MainWidget(QtGui.QWidget):
...
def initUI(self):
...
self.stack = QtGui.QStackedWidget(parent=self)
self.searchWidget = SearchWidget(parent=self)
self.searchWidget.searchButton.clicked.connect(self.goSearch)
self.backWidget = BackWidget(parent=self)
self.backWidget.backButton.clicked.connect(self.goBack)
...
def goSearch(self):
self.stack.setCurrentWidget(self.backWidget)
def goBack(self):
self.stack.setCurrentWidget(self.searchWidget)
I've renamed some of the class names to make a little more sense (To me at least). SearchWidget was your old MainWidget. BackWidget was your old SearchWidget. Following those changes SearchWidget would look the same as your old MainWidget with one exception - we save a reference to the search button so we can access it in the MainWidget class as seen above (when we connect their signals to our slots). We do the same for the button in BackWidget.
The two renamed "child" widgets:
class SearchWidget(QtGui.QWidget):
...
def initUI(self):
self.searchButton = QtGui.QPushButton('searchButton', parent=self)
optionButton = QtGui.QPushButton('optionButton', parent=self)
quitButton = QtGui.QPushButton('quitButton', parent=self)
listButton = QtGui.QPushButton('listButton', parent=self)
vbox = QtGui.QVBoxLayout(self)
vbox.addStretch(1)
vbox.addWidget(self.searchButton)
vbox.addWidget(optionButton)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(listButton)
hbox.addWidget(quitButton)
vbox.addLayout(hbox)
class BackWidget(QtGui.QWidget):
...
def initUI(self):
self.backButton = QtGui.QPushButton('GoBack', parent=self)
So now we have something like:
MainWindow
|---MainWidget
|---QStackedWidget
|---SearchWidget
|---BackWidget
You can find the full working code here.
This line:
def __init__(self, parent=MainWindow):
sets the MainWindow class as a default argument, when you actually need an instance. But even if it was an instance, in the next line, you also fail to pass it on to the base-class:
super(MainWidget,self).__init__()
What you need to do instead is something like this:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
# pass an instance of MainWindow here
self.mainWidget = MainWidget(self)
...
class MainWidget(QWidget):
def __init__(self, parent):
# pass the parent to the base-class
super(MainWidget, self).__init__(parent)
...
UPDATE:
The stack-widget will re-parent any widgets added to it, so that it becomes the parent. There are ways of working around this, but I think the real problem with your code is that you have the structure backwards. The buttons that set the current widget should be controlled by the main-window, and the widgets in the stack should work completely independantly of that.

Categories