When I try to show a message box from another class, it doesn't react anything.
On the other hand, I could succeed to show the box with the internal function.
I can print a message in console through another method of the class.
It seems just not working without any error.. I'm reading some articles but doesn't help.. Could you let me know which part I missed?
[Main.py]
class WinViewer(QWidget):
def __init__(self):
super().__init__()
def initUI(self):
self.setWindowTitle('Autolin')
self.move(300, 300)
self.resize(400, 200)
crw = Crawler.Crawler()
runBtn = QPushButton('Run', self)
runBtn.move(150, 50)
runBtn.clicked.connect(crw.putWebData)
tstBtn = QPushButton('Tst', self)
tstBtn.move(150, 100)
tstBtn.clicked.connect(self.tstmsg)
crw.testFunc()
self.show()
def tstmsg(self):
QMessageBox.about(self, "Tst", "Tst works.")
if __name__ == '__main__':
q_app = QApplication(sys.argv)
gui = WinViewer()
gui.initUI()
sys.exit(q_app.exec_())
[Sub.py]
class Crawler():
def putWebData(self):
QMessageBox.about(self, "Run", "Run works.")
def testFunc(self):
print('Hello')
try using this
Main.py
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from Sub import Crawler
class WinViewer(QWidget):
def __init__(self, *args):
super(WinViewer, self).__init__(*args)
def initUI(self):
self.setWindowTitle('Autolin')
self.move(300, 300)
self.resize(400, 200)
crw = Crawler(self)
runBtn = QPushButton('Run', self)
runBtn.move(150, 50)
runBtn.clicked.connect(crw.putWebData)
tstBtn = QPushButton('Tst', self)
tstBtn.move(150, 100)
tstBtn.clicked.connect(self.tstmsg)
crw.testFunc()
self.show()
def tstmsg(self):
QMessageBox.about(self, "Tst", "Tst works.")
if __name__ == '__main__':
q_app = QApplication(sys.argv)
gui = WinViewer()
gui.initUI()
sys.exit(q_app.exec_())
Sub.py
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Crawler(QMessageBox):
def __init__(self, *args):
super(Crawler, self).__init__(*args)
def putWebData(self):
self.about(self, "Run", "Run works.")
def testFunc(self):
print('Hello')
[EDIT]
I went to do something which gave me no time to add the explanation.
What you missed is the super().__init__() is a must when you are inheriting a class from Qt Classes and it works like this super({CLASS_NAME}, self) self represents the inherited class and after it .__init__(*args, **kwargs) it should have both args and kwargs so you can get the full functionality of the inhereted class. *args, **kwargs should be assigned as attributes inside def __init__(self, *args, **kwargs)
Related
This is my third project using PySide and I came across an unusual error when trying to use custom Signals and Slots. Below is a variation of what I am working on that is giving me the AttributeError. I have used a similar syntax for other projects with no issues, so any help is appreciated. I do understand per the error that I am trying to connect a function to a slot, however if I use the #Signal decorator I receive a separate error basically saying that I cannot use it.
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys
class TestSignal(QObject):
signal = Signal(float)
def __init__(self):
QObject.__init__(self)
def changed(self, test_value: float):
self.signal.emit(test_value)
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.signal = TestSignal()
self.signal.changed.connect(self.test_slot) # this is where the error occurs
self.central_widget = QWidget()
self.go_button = QPushButton("Emit")
self.go_button.clicked.connect(self.emit_signal)
self.change_label = QLabel("Push Button")
self.test_layout = QVBoxLayout()
self.test_layout.addWidget(self.change_label)
self.test_layout.addWidget(self.go_button)
self.setCentralWidget(self.central_widget)
self.central_widget.setLayout(self.test_layout)
self.show()
#Slot(float)
def test_slot(self, test_value):
self.change_label.setText("Emitted Signal successcully")
def emit_signal(self):
self.signal.changed()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Main()
app.exec_()
sys.exit(0)
The signal is called "signal", "changed" is just a method where the signal is emitted. Recommendation: Use more descriptive names to avoid this type of confusion
class TestSignal(QObject):
signal = Signal(float)
def changed(self, test_value: float):
self.signal.emit(test_value)
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.signal = TestSignal()
self.signal.signal.connect(self.test_slot)
self.central_widget = QWidget()
self.go_button = QPushButton("Emit")
self.go_button.clicked.connect(self.emit_signal)
self.change_label = QLabel("Push Button")
self.test_layout = QVBoxLayout()
self.test_layout.addWidget(self.change_label)
self.test_layout.addWidget(self.go_button)
self.setCentralWidget(self.central_widget)
self.central_widget.setLayout(self.test_layout)
self.show()
#Slot(float)
def test_slot(self, test_value):
self.change_label.setText("Emitted Signal successcully {}".format(test_value))
def emit_signal(self):
self.signal.changed(5.0)
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 can't find a good answer for this: is there a way for double click to execute a certain function, and single click one other function?? For example:
def func1(self):
print('First function')
def func2(self):
print('Second function')
self.ui.button.clicked.connect(self.func1)
self.ui.button.doubleClicked.connect(self.func2)
I've seen double clicking is possible for the QTreeview but not a QPushButton. Thanks!
You can add the functionality easily yourself by extending QPushButton class:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class QDoublePushButton(QPushButton):
doubleClicked = pyqtSignal()
clicked = pyqtSignal()
def __init__(self, *args, **kwargs):
QPushButton.__init__(self, *args, **kwargs)
self.timer = QTimer()
self.timer.setSingleShot(True)
self.timer.timeout.connect(self.clicked.emit)
super().clicked.connect(self.checkDoubleClick)
#pyqtSlot()
def checkDoubleClick(self):
if self.timer.isActive():
self.doubleClicked.emit()
self.timer.stop()
else:
self.timer.start(250)
class Window(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.button = QDoublePushButton("Test", self)
self.button.clicked.connect(self.on_click)
self.button.doubleClicked.connect(self.on_doubleclick)
self.layout = QHBoxLayout()
self.layout.addWidget(self.button)
self.setLayout(self.layout)
self.resize(120, 50)
self.show()
#pyqtSlot()
def on_click(self):
print("Click")
#pyqtSlot()
def on_doubleclick(self):
print("Doubleclick")
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
However, I would not recommend it. Users do not expect to double-click buttons. You can refer to Command Buttons Microsoft guidelines.
Consider the following example:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from mplayer import *
class mplayerStarter(QMainWindow):
def __init__(self, parent=None):
super(mplayerStarter, self).__init__(parent)
the_button = QPushButton('Start Mplayer')
the_button.clicked.connect(self.start)
self.setCentralWidget(the_button)
def start(self):
player = Player()
player.loadfile('/tmp/video.mp4')
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
form = mplayerStarter()
form.show()
app.exec_()
If I invoke the program and press the button, the video appears but vanishes immediatly. Any idea how to fix this?
I think it might be being garbage collected. Try this:
class mplayerStarter(QMainWindow):
def __init__(self, parent=None):
super(mplayerStarter, self).__init__(parent)
the_button = QPushButton('Start Mplayer')
the_button.clicked.connect(self.start)
self.setCentralWidget(the_button)
self.player = None
def start(self):
self.player = Player()
self.player.loadfile('/tmp/video.mp4')