@luchs
Новичок в деле программирования

Почему при вызове setHtml программа вылетает?

Программа загружает с сети html страницу и отображает её в QTextBrowser функцией setHtml, а затем ещё 4 картинки и отображает их в QLabel.
Т.к. загрузка страницы и картинок занимает время и на это время программа пересовала отвечать (зависала), исправил это - вынес в отдельный класс наследованный от QThread (в отдельный поток), а в основном классе лишь вызывал его в определённый момент. И если с картинками не возникло никаких проблем, то с QTextBrowser возникли - в строчке myapp.textBrowser.setHtml(res.text) программа вылетает без объяснения причин и не успев отобразить картинки и саму страницу, отлавливание ошибки не помогает.
Если закомментировать строчку, то программа далее исправно работает, загружая картинки и отображая их.

Это ошибка самого QTextBrowser? Я что-то не понимаю (я новичок)? Есть способ исправить или придётся использовать другие формы?

Проблемный кусок кода:
# python3
if os.path.exists("temp/"+trek+".html"):  # Если страница уже была ранее загружена
    with open("temp/"+trek+".html") as w:
        myapp.textBrowser.setHtml(w.read())  # Вылетает здесь
else:
    res = requests.get('http://URL/'+trek+".html") 
    res.encoding = 'utf-8'
    with open("temp/"+trek+".html", "w") as ri:
        ri.write(res.text)
    myapp.textBrowser.setHtml(res.text)  # И здесь

P.S. Если программа не найдя во временной папке страницу загружает по новой и вылетает, то эта страница остаётся в этой папке т.к. программа завершилась не корректно и при повторном запуске уже не скачивает, но всё равно вылетает.
  • Вопрос задан
  • 330 просмотров
Решения вопроса 1
@Sergey6661313
res = requests.get('http://URL/'+trek+".html")
orly?
ну ей богу написали хотя бы "yandex.ru/index.html" для примера.

без объяснения причин
ну пожалуйста пользуйтесь pycharm - есть бесплатная редакция. Он честно открывает консоль для каждой запущенной программы. В которую честно пишется причина. И которая, Самое главное, не закрывается после ошибки.

куски кода надо делать минимальными, НО запускаемыми. например такими:
import sys
import requests
import os
from PyQt5.QtWidgets import QTextBrowser
from PyQt5.Qt import QApplication
from PyQt5.Qt import QThread

trek = "index"
myapp = QApplication(sys.argv)
myapp.textBrowser = QTextBrowser()

class ExperementalThread(QThread):
    def run(self):
        if os.path.exists("temp/"+trek+".html"):  # Если страница уже была ранее загружена
            with open("temp/"+trek+".html") as w:
                myapp.textBrowser.setHtml(w.read())  # ни разу не вылетело
        else:
            res = requests.get('http://yandex.ru/'+trek+".html")
            res.encoding = 'utf-8'
            with open("temp/"+trek+".html", "w") as ri:
                ri.write(res.text)
            myapp.textBrowser.setHtml(res.text)  # И здесь

thread = ExperementalThread()
myapp.textBrowser.show()
thread.start()
myapp.exec()


и ошибка соотв. будет QObject: Cannot create children for a parent that is in a different thread.
что значит что метод setHtml пытается для себя создать отдельный поток. А потоки из потоков создавать запретил сам батюшка Ленин ( цитата от ██.██.19██г. ).

Значит придётся использовать сигналы и слоты.
я создал свой класс MyQTextBrowser с наследованием QTextBrowser и сигналом signal_load_html. Который в свою очередь связал с setHTML.

# coding=utf-8

import sys, requests, os                            # импортировали,
from PyQt5.Qt        import QApplication, QThread   # импортировали,
from PyQt5.QtCore    import pyqtSignal              # да не
from PyQt5.QtWidgets import QTextBrowser            # выпереимпортировали.

trek = "index"                                      # ну в самом деле надо же указать чему равна ваша переменная.
myapp = QApplication(sys.argv)                      # я угадал?
                                                    # обязательно делаем отступы перед каждым классом
class MyQTextBrowser(QTextBrowser):                 # создаём класс и наследуем QTextBrowser
    signal_load_html = pyqtSignal(str)              # назначаем сигнал (сигнал принимает значение str (строки) )
                                                    # тут тоже отступ
    def __init__(self):                             # переназначаем метод создания объектов
        super().__init__()                          # наследуем/выполняем QTextBrowser.__init__(self)
        self.signal_load_html.connect(self.setHtml) # тут связываем наш сигнал с setHtml
myapp.textBrowser = MyQTextBrowser()                # ну и создаём вообщемто обьект нашего класса MyQTextBrowser
                                                    # обязательно делаем отступы после каджого класса.
                                                    # обязательно делаем отступы перед каждым классом
class ExperementalThread(QThread):                  # названия придумываем на ходу
    def run(self):                                  # init не нужен сразу run
        if os.path.exists("temp/"+trek+".html"):    # Если страница уже была ранее загружена
            with open("temp/"+trek+".html") as w:   # открываем наш фаил в папке temp
                # myapp.textBrowser.setHtml(w.read())  # вылетает? у меня кстати нет, но я читер :)
                myapp.textBrowser.signal_load_html.emit(w.read())  # ни разу не вылетело.
        else:                                       # люблю когда много коментариев в коде
            res = requests.get('http://yandex.ru/'+trek+".html") # "Люблю говорить - это помогает думать."
            res.encoding = 'utf-8'                  # -- Томас Стернз Элиот
            with open("temp/"+trek+".html", "w") as ri: # когда этот код уже кончится?
                ri.write(res.text)                  # тут пусто потому что в оригинале у вас был "URL" а не yandex
            # myapp.textBrowser.setHtml(res.text)   # И здесь
            myapp.textBrowser.signal_load_html.emit(res.text)  # ни разу не вылетело
                                                    # обязательно делаем отступы после каждого класса.
thread = ExperementalThread()                       # создаём наш поток
myapp.textBrowser.show()                            # ах да - самое главное показать окно. Иначе ничего не произойдёт
thread.start()                                      # запускаем поток
myapp.exec()                                        # Ой, всё!()


p.s.
Вообще setHtml не метод QTextBrowser. Это метод из QTextEdit (который QTextBrowser наслеует. ) Сам же QTextBrowser создан для того чтобы самостоятельно загружать и показывать страницы с интернета. (по урлу.)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
SDT Москва
от 150 000 до 250 000 ₽
SDT Москва
от 100 000 до 160 000 ₽
Graebert Санкт-Петербург
До 3 000 $