С помощью QTextCursor выделить и удалить заданную строку из QTextBrowser

Рейтинг: 0Ответов: 1Опубликовано: 04.08.2023

Прошу помощи с приведенным в заголовке вопросом.

В textBrowser поступают ссылки из процесса опрашивающего сервер OTRS на предмет заявок с флагом 'open', если этот флаг меняется на 'close', то строка предназначенная для удаления передается другим сигналом и должна быть удалена из textBrowser.

Скитания по интернету и документации не помогли найти ответ.

main.py

import os
import sys
import requests
import pygame
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtCore import QThread, pyqtSignal
from gui import Ui_MainWindow
from pyotrs import Client


class Parser(QThread):
    ticket_list_signal = pyqtSignal(str)
    new_ticket_signal = pyqtSignal(str)
    ticket_list_remove_signal = pyqtSignal(str)
    error_signal = pyqtSignal(str)
    cycle_counter = 0

    def __init__(self, parent=None):
        QThread.__init__(self, parent)
        self.ticket_tuple = []
        self.links_list = []
        self.removed_link = []
        self.ticket_id_list = []
        self.wait_time = None
        self.url = None
        self.log = None
        self.pas = None
        self.sound_file = None

    def run(self):
        while True:
            self.pars()

    def pars(self):
        try:
            response = requests.get(
                f'{self.url}/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/TicketSearch?UserLogin={self.log}&Password={self.pas}',
                )
            response = response.content.decode("utf-8")
            resp_values = eval(response)
        except Exception as ex:
            print(f'{ex}')
            self.error_signal.emit('Problems connecting to the server')
        print(resp_values)
        client = Client(self.url, self.log, self.pas)
        client.session_create()

        for item in resp_values['TicketID']:
            ticket = client.ticket_get_by_id(int(item))
            self.ticket_id_list.append(item)

            if ticket.field_get("TicketNumber") not in self.ticket_tuple and ticket.field_get("State") == "open":
                self.ticket_tuple.append(f'{ticket.field_get("TicketNumber")}')

                if self.cycle_counter > 0:
                    self.new_ticket_signal.emit(f'{ticket.field_get("TicketNumber")} {ticket.field_get("Title")}')
                    pygame.mixer.init()
                    pygame.mixer.music.load(self.sound_file)
                    pygame.mixer.music.play()
                link_url = f'{self.url}/otrs/index.pl?Action=AgentTicketZoom;TicketID={item}'
                self.links_list = f'<a href="{link_url}">№ {ticket.field_get("TicketNumber")} Title: {ticket.field_get("Title")}</a>'
                print(f'BEFORE REMOVE: {self.links_list}')
                self.ticket_list_signal.emit(self.links_list)

            elif ticket.field_get("TicketNumber") in self.ticket_tuple and ticket.field_get("State") != "open":
                self.ticket_tuple.remove(f'{ticket.field_get("TicketNumber")}')
                link_url = f'{self.url}/otrs/index.pl?Action=AgentTicketZoom;TicketID={item}'
                self.removed_link = f'<a href="{link_url}">№ {ticket.field_get("TicketNumber")} Title: {ticket.field_get("Title")}</a>'
                print(f'AFTER REMOVE: {self.removed_link}')
                self.ticket_list_remove_signal.emit(self.removed_link)

            else:
                pass
        print(self.ticket_tuple)
        self.cycle_counter = self.cycle_counter + 1

        if self.cycle_counter > 50:
            self.cycle_counter = 1
        print(self.cycle_counter)
        print(f'TIME WAIT: {self.wait_time}')
        QThread.sleep(self.wait_time)


class ConfGUI(QtWidgets.QMainWindow):
    def __init__(self):
        super(ConfGUI, self).__init__(parent=None)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.file_path = os.path.dirname(__file__)
        self.sound_file = os.path.join(self.file_path, 'sounds/notice_notice.mp3')
        
        self.ui.lineEdit_4.setText(self.sound_file)
        self.ui.pushButton.clicked.connect(self.get_file)

        self.pars_thread = Parser()
        self.ui.pushButton_2.clicked.connect(self.create_session)
        self.ticket_links = self.pars_thread.ticket_list_signal.connect(self.links_add, QtCore.Qt.ConnectionType.QueuedConnection)
        self.new_ticket = self.pars_thread.new_ticket_signal.connect(self.mb, QtCore.Qt.ConnectionType.QueuedConnection)
        self.remove_ticket_links = self.pars_thread.ticket_list_remove_signal.connect(self.remove_links, QtCore.Qt.ConnectionType.QueuedConnection)
        self.error_message = self.pars_thread.error_signal.connect(self.mb, QtCore.Qt.ConnectionType.QueuedConnection)

    def get_file(self):
        try:
            self.sound_file = QtWidgets.QFileDialog.getOpenFileName(self, 'Выберете звук сигнала')
            self.sound_file = self.ui.lineEdit_4.textChanged(self.sound_file)
        except Exception as e:
            logging.warning(f'Exception in get folder: {e}', exc_info=True)

    def create_session(self):
        wait_time = int(self.ui.lineEdit_5.text())
        url = self.ui.lineEdit.text()
        log = self.ui.lineEdit_2.text()
        pas = self.ui.lineEdit_3.text()
        self.pars_thread.wait_time = wait_time
        self.pars_thread.url = url
        self.pars_thread.log = log
        self.pars_thread.pas = pas
        self.pars_thread.sound_file = self.sound_file
        self.pars_thread.start()

    def links_add(self, links):
        self.ui.textBrowser.append(links)

    def remove_links(self, removed_links): # этот метод должен удалять строки
        cursor = self.ui.textBrowser.textCursor()
        # cursor.selectedText(removed_links) # TypeError: selectedText(self): too many arguments
        cursor.selection(removed_links) # TypeError: selection(self): too many arguments
        cursor.removeSelectedText()
        cursor.clearSelection()
        self.ui.textBrowser.textCursor(cursor)

    def mb(self, d_msg):
        dlg = QMessageBox(self)
        dlg.setWindowTitle('Attention!')
        dlg.setText(d_msg)
        dlg.setIcon(QMessageBox.Icon.Information)
        dlg.setStandardButtons(QMessageBox.StandardButton.Ok)
        dlg.exec()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = ConfGUI()
    win.show()
    sys.exit(app.exec_())  

gui.py

# Form implementation generated from reading ui file 'gui.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(400, 550)
        MainWindow.setMinimumSize(QtCore.QSize(400, 550))
        MainWindow.setMaximumSize(QtCore.QSize(500, 550))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setMinimumSize(QtCore.QSize(140, 20))
        self.label.setObjectName("label")
        self.verticalLayout.addWidget(self.label)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName("lineEdit")
        self.verticalLayout.addWidget(self.lineEdit)
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setMinimumSize(QtCore.QSize(140, 20))
        self.label_2.setObjectName("label_2")
        self.verticalLayout.addWidget(self.label_2)
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setText("")
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.verticalLayout.addWidget(self.lineEdit_2)
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setMinimumSize(QtCore.QSize(140, 20))
        self.label_3.setObjectName("label_3")
        self.verticalLayout.addWidget(self.label_3)
        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_3.setText("")
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.verticalLayout.addWidget(self.lineEdit_3)
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setMinimumSize(QtCore.QSize(140, 20))
        self.label_5.setObjectName("label_5")
        self.verticalLayout.addWidget(self.label_5)
        self.lineEdit_5 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_5.setObjectName("lineEdit_5")
        self.verticalLayout.addWidget(self.lineEdit_5)
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setObjectName("pushButton_2")
        self.verticalLayout.addWidget(self.pushButton_2)
        self.verticalLayout_3.addLayout(self.verticalLayout)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setMinimumSize(QtCore.QSize(140, 20))
        self.label_4.setObjectName("label_4")
        self.verticalLayout_2.addWidget(self.label_4)
        self.lineEdit_4 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_4.setObjectName("lineEdit_4")
        self.verticalLayout_2.addWidget(self.lineEdit_4)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setMinimumSize(QtCore.QSize(140, 25))
        self.pushButton.setObjectName("pushButton")
        self.verticalLayout_2.addWidget(self.pushButton)
        self.verticalLayout_3.addLayout(self.verticalLayout_2)
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setObjectName("textBrowser")
        self.textBrowser.setOpenExternalLinks(True)
        self.verticalLayout_3.addWidget(self.textBrowser)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "New ticket finder"))
        self.label.setText(_translate("MainWindow", "URL"))
        self.lineEdit.setText(_translate("MainWindow", "http://127.0.0.1"))
        self.lineEdit_5.setText(_translate("MainWindow", "10"))
        self.label_2.setText(_translate("MainWindow", "Login"))
        self.label_3.setText(_translate("MainWindow", "Password"))
        self.label_5.setText(_translate("MainWindow", "The interval between requests (sec)"))
        self.pushButton_2.setText(_translate("MainWindow", "Connect"))
        self.label_4.setText(_translate("MainWindow", "Звук уведомления"))
        self.pushButton.setText(_translate("MainWindow", "Выбрать файл"))

Редакция 1:

Довел функция remove_links до такого вида:

def remove_links(self, removed_links):
    cursor = self.ui.textBrowser.textCursor()
    self.ui.textBrowser.moveCursor(QtGui.QTextCursor.MoveOperation.Start)
    self.ui.textBrowser.find(removed_links, QtGui.QTextDocument.FindFlag.FindWholeWords)
    cursor.select(QTextCursor.SelectionType.LineUnderCursor)
    cursor.removeSelectedText()
    self.ui.textBrowser.setTextCursor(cursor)

Теперь она удаляет последнюю строку списка, но не ищет точного совпадения с переданной ей в переменной.

Скрин интерфейса:

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

Ответы

▲ 0

Небольшой пример для QTextEdit:

class Window(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QVBoxLayout()
        self.textEdit = QTextEdit()
        self.button = QPushButton("Clear")
        layout.addWidget(self.textEdit)
        layout.addWidget(self.button)
        self.setLayout(layout)

        self.button.clicked.connect(self.clear)

    # Удаление последней строки в документе
    def clear(self):
        # Перемещаем курсор в конец документа (он же конец последней строки)
        self.textEdit.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)

        # Перемещаем курсор в начало строки
        self.textEdit.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor)
        
        # Перемещаем курсор в конец строки, но теперь с выделением этой строки
        self.textEdit.moveCursor(QTextCursor.End, QTextCursor.KeepAnchor)
        
        # Удаляем выделенную строку
        self.textEdit.textCursor().removeSelectedText()

if __name__== '__main__':
    app = QApplication(sys.argv)
    main = Window()
    main.show()

    app.exec()