wrong constructor argument type, PySide - python

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)

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'.

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.

Python MainWindow class can't find attribute

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.

Hover Event for a QGraphicsItem (PyQt4)

I want some small text to pop up when I have my curser over a QGraphicsItem in my QGraphicsScene. I have a class that inherits from QGraphicsItem, and this represents my graphical items in the scene.
I tried using the QGraphicsItem.hoverEnterEvent and I also set the setAcceptHoverEvents(True), but I still can't enable that hover event. I also came across an event filter method but I'm not sure where to implement it.
Should I install the event filter in the QGraphicsItem class, or the scene? I tried both and I'm still not getting the desired result. I want to be able to hover over all the items in the scene.
UPDATE:
So I tried doing this but the hover event still isn't being detected.
class graphics_Object(QtGui.QGraphicsPixmapItem):
def __init__(self, parent=None):
super(graphics_Object, self).__init__(parent)
pixmap = QtGui.QPixmap("item.png")
self.graphics_pixItem = QtGui.QGraphicsPixmapItem(pixmap.scaled(40, 40, QtCore.Qt.KeepAspectRatio))
self.graphics_pixItem.setFlag(QtGui.QGraphicsPixmapItem.ItemIsSelectable)
self.graphics_pixItem.setFlag(QtGui.QGraphicsPixmapItem.ItemIsMovable)
self.graphics_pixItem.setAcceptHoverEvents(True)
def hoverEnterEvent(self, event):
print 'hello'
class graphicsScene(QtGui.QGraphicsScene):
def __init__(self, parent=None):
super(graphicsScene, self).__init__(parent)
def mousePressEvent(self, event):
self.graphics_item = graphics_Object()
def mouseReleaseEvent(self, event)
self.addItem(self.graphics_item.graphics_pixItem)
self.graphics_item.graphics_pixItem.setPos(event.scenePos())
class Form(QtGui.QMainWindow):
def __init__(self):
super(Form, self).__init__()
self.ui = uic.loadUi('form.ui')
self.scene = graphicsScene()
self.ui.view.setScene(self.scene)
self.setMouseTracking(True)
You are making another pixmapItem inside you graphics_Object class, graphics_Object is already a subclass of graphicsPixmapItem so I don't see a purpose for this.
Then you only add that nested pixmapItem to the scene and your hoverEnterEvent is on the graphics_Object which is never added to the scene. That is why you are not receiving hover events.
One of many solutions would be to just add your graphics object to the scene instead of the nested graphicsPixmapItem and use setPixmap() in the init of graphics_Object
class graphics_Object(QtGui.QGraphicsPixmapItem):
def __init__(self, parent=None):
super(graphics_Object, self).__init__(parent)
pixmap = QtGui.QPixmap("item.png")
self.setPixmap(pixmap.scaled(40, 40, QtCore.Qt.KeepAspectRatio))
self.setFlag(QtGui.QGraphicsPixmapItem.ItemIsSelectable)
self.setFlag(QtGui.QGraphicsPixmapItem.ItemIsMovable)
self.setAcceptHoverEvents(True)
def hoverEnterEvent(self, event):
print('hello')
class graphicsScene(QtGui.QGraphicsScene):
def __init__(self, parent=None):
super(graphicsScene, self).__init__(parent)
def mousePressEvent(self, event):
self.graphics_item = graphics_Object()
def mouseReleaseEvent(self, event):
print('adding to scene')
self.addItem(self.graphics_item)
self.graphics_item.setPos(event.scenePos())
When you inherit (subclass) from a pyqt class or any class in python, think of the new class as a "copy" of the inherited class. It will behave the exact same way as the base class until you overwrite a method, in this case, we override the "init" and "hoverEnterEvent" methods to do our custom stuff. Everything else about a QGraphicsPixmapItem stays the same

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