Reputation: 53
The purpose of "Qthread_check.py" is to find MS Office files.
and deliver the result to "main_gui.py" So I have to find "main_gui.FindExcel"
I used QApplication.topLevelWidgets
to find "main_gui.FindExcel"
however, TopLevelWidgets
and isinstance
have different results than I thought.
main_gui.py
[... pyqt5 import...]
import sys
import os
import check_core
import Qthread_check
class FindExcel(QWidget):
def __init__(self):
super().__init__()
self.label_width = 90
self.core = check_core.CheckCore()
self.th = Qthread_check.Search()
self.run_pw = Qthread_check.SetPW()
self.initro_msg = "hihi"
self.init_gui()
def init_gui(self):
# intro msg
intro_label = QLabel()
intro_label.setText(self.initro_msg)
[... Widget And layout ...]
class MainWin(QMainWindow):
def __init__(self):
super().__init__()
self.main_ui_layout()
def main_ui_layout(self):
# create QTabWidget and add Tab..
tab_w = QTabWidget()
tab_w.addTab(GeneralCheck(), "General Check")
tab_w.addTab(FindExcel(), "MS Office PW")
self.setWindowTitle("T.T")
# Set main Central Widget
self.setCentralWidget(tab_w)
self.setGeometry(100, 100, 900, 900)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
start = MainWin()
sys.exit(app.exec_())
Qthread_check.py
from PyQt5.QtCore import QThread, pyqtSignal, QWaitCondition, QMutex
from PyQt5.QtWidgets import QApplication
import Main_gui
class Search(QThread):
file_changed = pyqtSignal(str)
done_msg = pyqtSignal(dict)
def __init__(self):
QThread.__init__(self)
self.cond = QWaitCondition()
self.mutex = QMutex()
self._status = False
for w in QApplication.topLevelWidgets():
print(w, isinstance(w, Main_gui.FindExcel)) #<<=== Why is this no match?
print("")
self.main_gui = [w for w in QApplication.topLevelWidgets() if isinstance(w, Main_gui.FindExcel)][0] #<== self.main_gui = []
def __del__(self):
self.wait()
def run(self):
[...]
Why do i get the following results? I don't know why the self.main_gui
is empty.
I think this is true. ==> <__main__.FindExcel object at 0x031FFC60> False
but..
# for w in QApplication.topLevelWidgets():
# print(w, isinstance(w, Main_gui.FindExcel))
# print("")
# result from above
<__main__.FindExcel object at 0x031FFC60> False <==== why?
<PyQt5.QtWidgets.QTabWidget object at 0x031FF990> False
<__main__.MainWin object at 0x031FF7B0> False
<PyQt5.QtWidgets.QMenu object at 0x031FF8F0> False
<PyQt5.QtWidgets.QMenu object at 0x031FF940> False
Process finished with exit code 1
plz help...
def __init__(self):
QThread.__init__(self)
self.cond = QWaitCondition()
self.mutex = QMutex()
self._status = False
for w in QApplication.topLevelWidgets():
print(w, w.__class__, Main_gui.FindExcel, isinstance(w, Main_gui.FindExcel))
print("")
output
<PyQt5.QtWidgets.QMenu object at 0x0383F940> <class 'PyQt5.QtWidgets.QMenu'> <class 'Main_gui.FindExcel'> False
<PyQt5.QtWidgets.QTabWidget object at 0x0383F990> <class 'PyQt5.QtWidgets.QTabWidget'> <class 'Main_gui.FindExcel'> False
<PyQt5.QtWidgets.QMenu object at 0x0383F8F0> <class 'PyQt5.QtWidgets.QMenu'> <class 'Main_gui.FindExcel'> False
<__main__.FindExcel object at 0x0383FC60> <class '__main__.FindExcel'> <class 'Main_gui.FindExcel'> False
<__main__.MainWin object at 0x0383F7B0> <class '__main__.MainWin'> <class 'Main_gui.FindExcel'> False
Upvotes: 3
Views: 711
Reputation: 243945
As you indicate when executing:
print(w, w.__class__, Main_gui.FindExcel, isinstance(w, Main_gui.FindExcel))
The output is:
# ...
<__main__.FindExcel object at 0x0383FC60> <class '__main__.FindExcel'> <class 'Main_gui.FindExcel'> False
# ...
It is observed that the __class__ of the object is __main__.FindExcel
which is different from Main_gui.FindExcel
that I suspect is generating the problem.
It seems that isinstance()
does not consider the case that the class and instance are created in different scopes. Also, maybe it's a PyQt5 bug.
Solution 1:
Although I don't see the need to use topLevelWidgets() since you can pass the FindExcel directly:
# ...
class FindExcel(QWidget):
def __init__(self):
super().__init__()
self.label_width = 90
self.core = check_core.CheckCore()
self.th = Qthread_check.Search(self)
# ...
# ...
class Search(QThread):
file_changed = pyqtSignal(str)
done_msg = pyqtSignal(dict)
def __init__(self, main_gui):
QThread.__init__(self)
self.cond = QWaitCondition()
self.mutex = QMutex()
self._status = False
self.main_gui = main_gui
# ...
Solution 2:
Another option is to restructure your project by moving the if __name__ == "__main__":
code to another file:
|-- another_file.py
|-- Main_gui.py
`-- Qthread_check.py
another_file.py
from PyQt5.QtWidgets import QApplication
from Main_gui import MainWin
if __name__ == "__main__":
app = QApplication(sys.argv)
start = MainWin()
sys.exit(app.exec_())
Solution 3:
Or if you still want to use topLevelWidgets() then you can use the QMetaObject to get the class name and then use it to filter it:
# ...
class Search(QThread):
file_changed = pyqtSignal(str)
done_msg = pyqtSignal(dict)
def __init__(self):
QThread.__init__(self)
self.cond = QWaitCondition()
self.mutex = QMutex()
self._status = False
self.main_gui = None
for w in QtWidgets.QApplication.topLevelWidgets():
if w.metaObject().className() == "FindExcel":
self.main_gui = w
break
print(self.main_gui)
# ...
Note: FindExcel is a topLevelWidget only in the construction because then it is part of the QTabWidget and therefore it is no longer a window.
Upvotes: 2