Вне проблемы, на которую вы указываете, у вас есть другие ошибки, и они более опасны, чем указанная: вы не должны обращаться к GUI из другого потока, и вы также не должны обращаться к той же переменной из 2 потоков без защиты через мьютекс, семафор или подобный. Например, вы вызываете self.web.page().action(QWebEnginePage.Reload).trigger()
и self.msg.information(None, 'INFO', 'PLEASE CHECK YOUR INTERNET CONNECTION!!!')
из вторичного потока, а переменная is_connected доступна нескольким потокам.
Другая ошибка заключается в том, что метод QMessage::information()
is stati c и генерирует новый объект, который не доступен напрямую, вместо этого вы должны использовать объект «self.msg» через его собственные методы для отображения необходимой информации.
Учитывая вышеизложенное, я создал класс, который отвечает только за анализирует состояние соединения и, если оно меняется, испускает сигнал. Для передачи информации между потоками в Qt вы можете использовать сигналы или QMetaObject::invokedMethod()
в дополнение к мьютексам и семафорам * * * * * * * * * * * * * * * * * * * для того, чтобы анализировать значение статуса, отправленного на * 1019. * для реализации логики c:
import sys
import threading
import time
import urllib
from urllib.request import urlopen
from PyQt5 import QtCore, QtWidgets, QtNetwork, QtWebEngineWidgets
class ConnectivityManager(QtCore.QObject):
statusChanged = QtCore.pyqtSignal(bool)
def __init__(self, *, timeout=4000, parent=None):
super().__init__(parent)
self._status = False
self._timeout = timeout
def start(self):
threading.Thread(target=self._check, daemon=True).start()
@QtCore.pyqtProperty(bool, notify=statusChanged)
def status(self):
return self._status
@QtCore.pyqtSlot(bool)
def _update_status(self, status):
if self._status != status:
self._status = status
self.statusChanged.emit(self.status)
def _check(self):
while True:
try:
urlopen("http://www.google.com", timeout=1)
status = True
except urllib.error.URLError as Error:
status = False
QtCore.QMetaObject.invokeMethod(
self,
"_update_status",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(bool, status),
)
time.sleep(5)
class WebApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("OZI")
self.web = QtWebEngineWidgets.QWebEngineView()
self.setCentralWidget(self.web)
self.web.load(QtCore.QUrl("http://www.google.com"))
self.connectivity_manager = ConnectivityManager()
self.connectivity_manager.statusChanged.connect(self.on_status_changed)
self.connectivity_manager.start()
self.msg = QtWidgets.QMessageBox()
self.msg.setWindowTitle("INFO")
self.msg.setText("PLEASE CHECK YOUR INTERNET CONNECTION!!!")
@QtCore.pyqtSlot(bool)
def on_status_changed(self, status):
if status:
self.msg.hide()
self.statusBar().showMessage("Connected")
self.web.page().action(QtWebEngineWidgets.QWebEnginePage.Reload).trigger()
else:
self.statusBar().showMessage("Disconnected")
self.msg.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = WebApp()
ex.showFullScreen()
sys.exit(app.exec_())
С другой стороны, те же логики c могут быть реализованы с использованием QtNetwork без необходимости в потоках:
import sys
from PyQt5 import QtCore, QtWidgets, QtNetwork, QtWebEngineWidgets
class ConnectivityManager(QtCore.QObject):
statusChanged = QtCore.pyqtSignal(bool)
def __init__(self, *, timeout=4000, parent=None):
super().__init__(parent)
self._status = False
self._timeout = timeout
self.manager = QtNetwork.QNetworkAccessManager()
self._timer = QtCore.QTimer(
singleShot=True, interval=self._timeout, timeout=self.verify_status
)
def start(self):
QtCore.QTimer.singleShot(0, self._check)
@QtCore.pyqtProperty(bool, notify=statusChanged)
def status(self):
return self._status
@QtCore.pyqtSlot(bool)
def _update_status(self, status):
if self._status != status:
self._status = status
self.statusChanged.emit(self.status)
def _check(self):
url = QtCore.QUrl("https://www.google.com/")
req = QtNetwork.QNetworkRequest(url)
self._reply = self.manager.get(req)
self._reply.finished.connect(self.verify_status)
self._timer.start()
@QtCore.pyqtSlot()
def verify_status(self):
if self._timer.isActive():
self._timer.stop()
if self._reply.error() == QtNetwork.QNetworkReply.NoError:
v = self._reply.attribute(
QtNetwork.QNetworkRequest.HttpStatusCodeAttribute
)
if 200 <= v < 300:
self._update_status(True)
else:
print("error", "code error: {}".format(v))
self._update_status(False)
else:
print("error", self._reply.errorString())
self._update_status(False)
else:
self._reply.finished.disconnect(self.verify_status)
self._reply.abort()
print("Timeout")
self._update_status(False)
QtCore.QTimer.singleShot(5000, self._check)
self._reply.deleteLater()
class WebApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("OZI")
self.web = QtWebEngineWidgets.QWebEngineView()
self.setCentralWidget(self.web)
self.web.load(QtCore.QUrl("http://www.google.com"))
self.connectivity_manager = ConnectivityManager()
self.connectivity_manager.statusChanged.connect(self.on_status_changed)
self.connectivity_manager.start()
self.msg = QtWidgets.QMessageBox()
self.msg.setWindowTitle("INFO")
self.msg.setText("PLEASE CHECK YOUR INTERNET CONNECTION!!!")
@QtCore.pyqtSlot(bool)
def on_status_changed(self, status):
if status:
self.msg.hide()
self.statusBar().showMessage("Connected")
self.web.page().action(QtWebEngineWidgets.QWebEnginePage.Reload).trigger()
else:
self.statusBar().showMessage("Disconnected")
self.msg.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = WebApp()
ex.showFullScreen()
sys.exit(app.exec_())