PyQt5 signal communication error - python

I need your help with the following problem that I've encountered.
I have two Python files, Main.py and Module.py, which need to communicate using PyQt5 signals. Here's the code:
Main.py
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from MyGUI import main_window_GUI
from Modules import Module.py
class MainWindow(QMainWindow, main_window_GUI.Ui_main_window):
def __init__(self):
QMainWindow.__init__(self)
main_window_GUI.Ui_main_window.__init__(self)
self.setupUI(self)
sub_win = QMdiSubWindow()
sub_win.setWidget(Module.moduleWindow())
self.mdi.addSubWindow(sub_win)
# this part reports error saying:
# 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
Module.moduleWindow.my_signal.connect(self.do_something)
def do_something(self):
pass
Module.py
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from MyGUI import module_window_GUI
class moduleWindow(QMainWindow, module_window_GUI.Ui_module_window):
my_signal = pyqtSignal()
def __init__(self):
QMainWindow.__init__(self)
module_window_GUI.Ui_module_window.__init__(self)
self.setupUI(self)
# the rest is not important
# what is important is th following function
def closeEvent(self, event):
# when the user closes this subwindow signal needs to
# be emitted so that the MainWindow class knows that
# it's been closed.
self.my_signal.emit()
event.accept()
Any kind of help is more than welcome. Thanks in advance.

You need to connect the signal from an instance of the moduleWindow class, and not from the class itself:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from MyGUI import main_window_GUI
from Modules import Module
class MainWindow(QMainWindow, main_window_GUI.Ui_main_window):
def __init__(self):
QMainWindow.__init__(self)
main_window_GUI.Ui_main_window.__init__(self)
self.setupUI(self)
sub_win = QMdiSubWindow()
module_window = Module.moduleWindow()
sub_win.setWidget(module_window)
self.mdi.addSubWindow(sub_win)
module_window.my_signal.connect(self.do_something)
#pyqtSlot()
def do_something(self):
pass
I would also recommend to decorate the do_something method with pyqtSlot as reported in the documentation

Related

Showing output from two different classes in pyqt5 gui python

Program
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import *
from PySide2 import *
from ui_test import *
class MainThread(QThread):
def __init__(self):
super(MainThread,self).__init__()
def run(self):
self.task()
def task(self):
while True:
com="runnning"
print(com)
startexecution = MainThread()
class main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.ti = Ui_MainWindow()
self.ti.setupUi(self)
self.ti.run_btn.clicked.connect(self.starttask)
self.ti.close.clicked.connect(self.close)
self.show()
def starttask(self):
startexecution.start()
if __name__=="__main__":
app =QApplication(sys.argv)
window = main()
sys.exit(app.exec_())
It is an example of the problem I am facing in my original program
MainThread class run is the main program that runs in the backend and the main class runs GUI in frontend. I want to show the output generated by the backend program in textbrowser of my UI as an output

How to call widget class in different module in PYQT with multiple Ui file structure

The issue comes from the multi-module Pyqt structure.
To get you to speed, all of my files with the issue are readily available in github repo here.
I downloaded the code from the Stackoverflow inquiry about the side bar in PYQT when using multiple UI file structure.
#Eyllanesc, kudos to his help with Qt answered the question and provided an example here.
The issue is, when calling Pyqt5 objects (such as lineEdit) via Widget class it throws various errors.
I am trying (for the sake of this example) fill one lineEdit in module customerpage.py with the text from other lineEdit in module loginpage.py.
call in loginpage.py (works)
def test(self):
try:
return CustomerWidget.test_func(self.lineEdit_server.text())
except Exception as e:
print(e)
pass
receiving in customerpage.py (error)
def test_func(name):
print(name)
CustomerWidget.parent().lineEdit_cust_name.setText(name)
The errors that I get when referencing CustomerWidget in the module customerpage are following.
For reference as CustomerWidget it is error type object 'CustomerWidget' has no attribute 'lineEdit_cust_name.
For reference as CustomerWidget() it is error wrapped C/C++ object of type QLineEdit has been deleted.
For reference as CustomerWidget().parent(). it is error NoneType' object has no attribute 'lineEdit_cust_name'.
For reference as CustomerWidget.parent(). it is error parent(self): first argument of unbound method must have type 'QObject'.
How to refer to the widget class in other module with the PYQT Ui structure that it gets recognised?
Structure
├── main.py
├── pages
│ ├── loginpage.py
│ └── customer.py
└── ui
├── main.ui
├── login.ui
└── customer.ui
main.py
import os
from PyQt5 import QtGui, uic, QtCore, QtWidgets
from PyQt5.QtCore import QAbstractTableModel, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView
from functools import partial
import os.path
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
current_dir = os.path.dirname(os.path.abspath(__file__))
Form, Base = uic.loadUiType(os.path.join(current_dir, "ui/main.ui"))
class MainWidget(Base, Form):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.setupUi(self)
buttons = (self.loginbutton,self.customerbutton)
for i, button in enumerate(buttons):
button.clicked.connect(partial(self.stackedWidget.setCurrentIndex, i))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle("Breeze")
w = MainWidget()
w.show()
sys.exit(app.exec_())
loginpage.py
import os
from PyQt5 import QtGui, uic
import ctypes
import os.path
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
from .customerpage import CustomerWidget
current_dir = os.path.dirname(os.path.abspath(__file__))
Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/login.ui"))
class LoginWidget(Base, Form):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.setupUi(self)
self.pushButton_test.clicked.connect(self.test)
self.lineEdit_server.setText("localhost")
def test(self):
try:
return CustomerWidget.test_func(self.lineEdit_server.text())
except Exception as e:
print(e)
pass
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = LoginWidget()
w.show()
sys.exit(app.exec_())
customerpage.py
from PyQt5 import QtGui, uic
from PyQt5.QtCore import QSize, Qt, QSortFilterProxyModel
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QLineEdit,
QMainWindow,
QWidget,
QMessageBox
)
import os
import os.path
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
current_dir = os.path.dirname(os.path.abspath(__file__))
Form, Base = uic.loadUiType(os.path.join(current_dir, "../ui/customer.ui"))
class CustomerWidget(Base, Form):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.setupUi(self)
self.lineEdit_cust_name.setText("")
def test_func(name):
print(name)
CustomerWidget.parent().lineEdit_cust_name.setText(name)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = CustomerWidget()
w.show()
sys.exit(app.exec_())
Okay, so there is an issue with accessing the objects, as they are not recognized as class variables.
This might not be a proper way how to do it in PYQT but it certainly works for this example. It can be done by declaring them within __init__ of thewidget class.
CustomerWidget.lineEdit_cust_name = self.lineEdit_cust_name

How to call an event from another class in PyQt5

I'm trying to call a mouse click event in QWebview to get a text by copy in the QWebView page but I don't know how. I have been trying to solve this for sometimes now.
Here is the minor code
import sys
from PyQt5.QtWidgets import *
from PyQt5 import Qt
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWebKitWidgets import *
class sw(QWebView):
def keyPressEvent(self, e):
clipboard=QApplication.clipboard()
data=clipboard.mimeData()
print(data.text)
super(Mainw, self).keyPressEvent(e)
class Mainw(QWidget):
def __init__(self):
super().__init__()
#QTextEdit().__init__()
self.m=QMenuBar(self)
self.file=self.m.addMenu("file")
self.new=QAction("new", self)
self.file.addAction(self.new)
ed=QWebView(self)
ed.setHtml(imported_data)
ed.setGeometry(20,30,400,400)
if __name__=="__main__":
a=QApplication(sys.argv)
app=Mainw()
#sb=app.open()
app.show()
sys.exit(a.exec_())
I know there are alot or errors in this code

PyQt5 from apt install python3-pyqt5 [duplicate]

My code was created with PyQt4 and I want to convert it to PyQt5.
I have tried some scripts to convert the code; but, nothing changed except the name.
What do I need to change manually in order to make the code work with PyQt5?
Here is the first part of my code:
import sys
from pymaxwell import *
from numpy import *
from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtGui import QMainWindow, QApplication
from PyQt4.QtCore import *
from PyQt4.phonon import Phonon
from ffmpy import FFmpeg
import os
import app_window_dark
import about
uifile = 'Ui/app_window_dark.ui'
aboutfile = 'Ui/about.ui'
Ui_MainWindow, QtBaseClass = uic.loadUiType(uifile)
Ui_Dialog= uic.loadUiType(uifile)
class About(QtGui.QMainWindow, about.Ui_Dialog):
def __init__(self, parent=None):
super(About, self).__init__()
QtGui.QMainWindow.__init__(self, parent)
Ui_Dialog.__init__(self)
self.setWindowModality(QtCore.Qt.ApplicationModal)
point = parent.rect().bottomRight()
global_point = parent.mapToGlobal(point)
self.move(global_point - QPoint(395, 265))
self.setupUi(self)
class MyApp(QtGui.QMainWindow, app_window_dark.Ui_MainWindow):
def __init__(self):
super(MyApp, self).__init__()
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow.__init__(self)
self.setupUi(self)
self.about_btn.clicked.connect(self.popup)
#prev next
self.btn_next.clicked.connect(self.renderSet)
self.btn_prev.clicked.connect(self.renderSet)
and also this code:
if __name__ == "__main__":
app = QApplication(sys.argv)
#style = QApplication.setStyle('plastique')
window = MyApp()
window.setFixedSize(750, 320)
window.show()
sys.exit(app.exec_())
The main change from Qt4 to Qt5 and hence from PyQt4 to PyQt5 is the rearrangement of certain classes so that the Qt project is scalable and generates a smaller executable.
The QtGui library was divided into 2 submodules: QtGui and QtWidgets, in the second only the widgets, namely QMainWindow, QPushButton, etc. And that is the change you must make:
[...]
from PyQt5 import QtGui, QtCore, uic, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import *
[...]
Ui_MainWindow, QtBaseClass = uic.loadUiType(uifile)
Ui_Dialog= uic.loadUiType(uifile)
class About(QtWidgets.QMainWindow, about.Ui_Dialog):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.setWindowModality(QtCore.Qt.ApplicationModal)
point = parent.rect().bottomRight()
global_point = parent.mapToGlobal(point)
self.move(global_point - QPoint(395, 265))
class MyApp(QtWidgets.QMainWindow, app_window_dark.Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
self.about_btn.clicked.connect(self.popup)
#prev next
self.btn_next.clicked.connect(self.renderSet)
self.btn_prev.clicked.connect(self.renderSet)
Note: Phonon does not exist in PyQt5, you must use QtMultimedia, an accurate solution you can find it in the following answer: Phonon class not present in PyQt5

PyQt - Correct Position Of Import Statements

In light of segregating/organising code, am lost on the best approach. The below works, with app.py imports after the MainWindow instantiation, but will that create subsequent problems, as I can't see how else things can be done (putting the imports after MainWindow is instantiated obviously gives 'main not found' from formatting.py).
app.py
from PyQt4.QtCore import *; from PyQt4.QtGui import *; from PyQt4.uic import *; from PyQt4.QtSql import *
app = QApplication(sys.argv)
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMaximumSize(500,500); self.showMaximized()
def test(self):
print self.sender()
main = Main()
main.show()
from ui.formatting import *
formatting.py
from PyQt4.QtCore import *; from PyQt4.QtGui import *; from PyQt4.uic import *; from PyQt4.QtSql import *
from app import main
class LineEdit(QLineEdit):
def __init__(self):
QLineEdit.__init__(self)
self.setParent(main)
self.show()
self.textChanged.connect(main.test)
lineEdit = LineEdit()
Much appreciated
You should never rely on an object being instantiated when the import takes place (OK, there are a few times when you might want to do this, but it's very rare).
Instead, generally, you should use import statements to import modules, classes and/or functions. If an imported module/class/function requires access to something from another import (or from your main script) then you should pass that in explicitly when you use/instantiate/call said module/class/function.
So your example becomes:
formatting.py
from PyQt4.QtCore import *; from PyQt4.QtGui import *; from PyQt4.uic import *; from PyQt4.QtSql import *
class LineEdit(QLineEdit):
def __init__(self, main):
QLineEdit.__init__(self)
self.setParent(main)
self.show()
self.textChanged.connect(main.test)
app.py
from PyQt4.QtCore import *; from PyQt4.QtGui import *; from PyQt4.uic import *; from PyQt4.QtSql import *
from ui.formatting import *
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMaximumSize(500,500); self.showMaximized()
def test(self):
print self.sender()
app = QApplication(sys.argv)
main = Main()
lineedit = LineEdit(main)
main.show()
Of course, this is a bit of a contrived example because it makes more sense to set the parent, and make the connection with your QLineEdit in app.py. Eg:
lineedit = LineEdit()
lineedit.setParent(main)
lineedit.textChanged.connect(main.test)
And then in that case, you don't need to subclass QLineEdit at all.

Categories