Как в QTextEdit изменять фон текста в разные цвета до конца строки?

Нужно вывести текст в графический интерфейс, обработать и изменить фон текста в разные цвета до конца строки.

Проблема возникла с последним. Простой "span background-color" не доводит закраску до конца строки, а только до конца текста. "p" и "div" красит как нужно, но абсолютно все строки.

Благодарен за помощь.

import sys
import threading
from PyQt6.QtWidgets import QApplication,QMainWindow, QTextEdit
from PyQt6.QtCore import pyqtSignal

class MainWindow(QMainWindow):
    # Создаем сигнал для обновления консольного окна
    update_display = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        self.setGeometry(700, 300, 200, 200)

        self.output_display = QTextEdit(self)
        self.output_display.setGeometry(10, 10, 180, 180)

        # Подключаем сигнал к слоту для обновления окна вывода текста
        self.update_display.connect(self.update_output_display)

    def add_background_color(self, text, color):
        #colored_text = f"<p style='background-color: {color};'>{text}</p>"
        colored_text = f"<span style='background-color: {color};'>{text}</span>"

        return colored_text

    def update_output_display(self, text):
        if "example" in text:
            html_text = self.add_background_color(text, "green")
        elif "primer" in text:
            html_text = self.add_background_color(text, "blue")
        else:
            html_text = text
        self.output_display.append(html_text)

def process_output_handler(window):
    # для примера
    window.update_display.emit("example")
    window.update_display.emit("primer")
    window.update_display.emit("example")
    window.update_display.emit("primer")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    thread = threading.Thread(target=process_output_handler, args=(window,), daemon=True).start()
    sys.exit(app.exec())

введите сюда описание изображения


У меня сейчас получается как во втором примере, то есть цвет фона распространяется только за текстом. А мне нужно как в первом случае, чтобы цветовая полоска продолжалась дальше, до конца окна.


Ответы (2 шт):

Автор решения: Александр

Вам наверное нужно что то наподобии?

<style>
    .red-text { color: #FF0000; }
    .blue-text { color: #0000A0; }
</style>
        <p>
            Обычный текст <span class="red-text">красное слово</span> обычный текст <span> class="blue-text">синее слово</span>.
        </p>
→ Ссылка
Автор решения: S. Nick

Ваша задача может выглядеть примерно так, см. ниже.

Обратите внимание, что я заменил виджет QTextEdit на QListWidget.
Вам не нужен модуль threading, в PyQt есть класс QThread

Попробуйте:

import sys
from random import choice
from PyQt5.Qt import *


class ListWidget(QListWidget):

    def resizeEvent(self, event: QResizeEvent) -> None:
        super().resizeEvent(event)
        row = 0
        while row < self.count():
            lwi_item = self.item(row)
            item_widget = self.itemWidget(lwi_item)
            if not (item_widget is None) and (item_widget.wordWrap()):
                width_int = self.width() \
                            - self.contentsMargins().left() \
                            - self.contentsMargins().right()
                fm = self.fontMetrics()
                text_str = item_widget.text()                           
                max_rect = QRect(0, 0, width_int, 1000)
                br = fm.boundingRect(max_rect, Qt.TextWordWrap, text_str)
                
                font_br_size = br.size()
                heigth_int = font_br_size.height()
                total_height_int = heigth_int \
                                   + item_widget.contentsMargins().top() \
                                   + item_widget.contentsMargins().bottom()
                                   
                widget_size_hint = QSize(width_int, total_height_int)
                lwi_item.setSizeHint(widget_size_hint)                            # <---
            row += 1


class Thread(QThread):
    update_display = pyqtSignal(str)
    
    def __init__(self):
        super().__init__()
        self.flag_run = True        
        self._list = [
            'Этот текст содержит "example"', 
            'primer', 
            'У меня сейчас получается как во втором primerе, то есть цвет фона распространяется только за текстом.',
            ' А мне нужно как в первом случае, чтобы цветовая полоска продолжалась дальше, до конца окна.',
            'example',
            'Просто текст.',
            'покрасить фон текста в разные цвета до конца строки'
        ]
        
    def run(self):
        while self.flag_run:
            text = choice(self._list)
            self.update_display.emit(text)
            self.msleep(2000)
    

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
 
        self.list_widget = ListWidget()
        self.list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.list_widget.setResizeMode(QListView.Adjust)
        self.list_widget.setUniformItemSizes(False)  
        self.list_widget.setWordWrap(True)  

        self.pushButton = QPushButton("Start Thread")
        self.pushButton.clicked.connect(self.button_clicked)        
        self.pushButton.setCheckable(True)

        self.layout = QGridLayout(self.centralWidget)
        self.layout.addWidget(self.list_widget)
        self.layout.addWidget(self.pushButton)        

        self.thread = Thread()
        self.thread.update_display.connect(self.add_background_color)

    def button_clicked(self, status):
        if status:
            self.pushButton.setText("Stop Thread")
            self.thread.flag_run = True 
            self.thread.start()
        else:
            self.thread.flag_run = False 
            self.pushButton.setText("Start Thread")
        
    def add_background_color(self, text):
        item = QListWidgetItem(self.list_widget)
        self.list_widget.addItem(item)
        
        item_qlabel = QLabel(text)
        item_qlabel.setSizePolicy(QSizePolicy.Expanding, 
                                  QSizePolicy.Expanding)
        item_qlabel.setWordWrap(True)        

        if "example" in text:
            bg_color = "#238b45"        
        elif "primer" in text:
            bg_color = "#1d91c0"
        else:
            bg_color = "#edf8fb"
            
        item_qlabel.setStyleSheet(
            f"*{{background-color: {bg_color}; border: 1px solid #d90909;;}}")
        item.setSizeHint(item_qlabel.sizeHint())
        self.list_widget.setItemWidget(item, item_qlabel)        


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setFont(QFont("Times", 12, QFont.Bold))
    w = MainWindow()
    w.resize(500, 400)
    w.show()
    sys.exit(app.exec())

введите сюда описание изображения

введите сюда описание изображения

→ Ссылка