PyQt5中

时间:2017-08-17 18:13:47

标签: python python-3.x pyqt pyqt5 carriage-return

我现在被卡住了。我试图让它QTextBrowser能够很好地呈现它从程序输出中得到的文本馈送(多个部分)。但是下载进度变成了几行文本,因为我无法实现一种处理回车的方法。这是一个附加到我的QTextBrowser的字符串,其中显示了\r\n

  

dQw4w9WgXcQ:正在下载缩略图... \ n

     

dQw4w9WgXcQ:将缩略图写入:D:\ Musikk \ DLs \ Rick Astley - 永远不会给你Up.jpg \ n

     

目的地:D:\ Musikk \ DLs \ Rick Astley - 永远不会给你Up.webm \ n

     

\ r \ n3.33MiB的0.9%,4.03MiB / s ETA 00:00

     

\ r \ n 3.33MiB的1.8%,3.62MiB / s ETA 00:00

最后两行将有很多,因为它将下载所有100%和几个文件。

我目前的实施很简单(并没有处理这个问题),

self.textBrowser.append(text)

你会得到这样的结果(这一切的片段):

  

dQw4w9WgXcQ:正在下载缩略图......

     

dQw4w9WgXcQ:将缩略图写入:D:\ Musikk \ DLs \ Rick Astley - 永远不会给你Up.jpg

     

目的地:D:\ Musikk \ DLs \ Rick Astley - 永远不会给你Up.webm

     

3.33MiB的0.0%,19.15KiB / s ETA 02:58

     

0.13.3.33MiB,57.44KiB / s ETA 00:59

     

0.23.3.33MiB,131.57KiB / s ETA 00:25

我还可以删除字符串中的\n,以便在存在这些字符串的行之间留出较小的空格。

我尝试了另一种部分解决方案,当字符串包含\r时,而不是附加,但是,某些字符串包含多个\r个字符,而这并不能解释这一点。

        self.textbrowser.insertPlainText(text)
        if '\r' in text:
            self.textbrowser.moveCursor(QTextCursor.End, mode=QTextCursor.MoveAnchor)
            self.textbrowser.moveCursor(QTextCursor.StartOfLine, mode=QTextCursor.MoveAnchor)
            self.textbrowser.moveCursor(QTextCursor.End,mode=QTextCursor.KeepAnchor)
            self.textbrowser.textCursor().removeSelectedText()
            self.textbrowser.textCursor().deletePreviousChar() 

我也尝试过:

        self.textbrowser.append(text) 
        self.textbrowser.textCursor().deletePreviousChar() 

然而它确实删除了行之间的一些空格(删除换行符.append()添加。)但它仍然没有做任何事情,只是删除\ r \ n字符,就好像它不存在。而且我根本无法获得一致的解决方案。

作为参考,这是youtube-dl.exe的包装器。如果你在控制台中使用youtube-dl.exe(例如Windows 10上的Powershell)它会做正确的事情并在更新百分比时跳转到行的开头,这样你就会得到一个很好的下载线就其自身而言,ETA也会倒计时,而不会超过多行。

对于简化代码,这是一个显示正在使用的示例,除了附加解码后的字符串之外没有其他解决方案。请注意,这是来自前一段时间的答案,其中有一个QTextEdit而不是QTextBrowser。它需要youtube-dl.exe位于python脚本的工作目录中。在这种情况下,QTextEdit称为self.edit

import sys

from PyQt5.QtCore import QProcess
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QTextEdit, QLabel, QLineEdit


class GUI(QProcess):
    def __init__(self, parent=None):
        super(GUI, self).__init__(parent=parent)

        # Create an instance variable here (of type QTextEdit)
        self.startBtn = QPushButton('OK')
        self.stopBtn = QPushButton('Cancel')

        self.hbox = QHBoxLayout()
        self.hbox.addStretch(1)
        self.hbox.addWidget(self.startBtn)
        self.hbox.addWidget(self.stopBtn)

        self.label = QLabel("Url: ")
        self.lineEdit = QLineEdit()

        self.lineEdit.textChanged.connect(self.EnableStart)

        self.hbox2 = QHBoxLayout()
        self.hbox2.addWidget(self.label)
        self.hbox2.addWidget(self.lineEdit)

        self.edit = QTextEdit()
        self.edit.setWindowTitle("QTextEdit Standard Output Redirection")

        self.vbox = QVBoxLayout()
        self.vbox.addStretch(1)

        self.vbox.addLayout(self.hbox2)
        self.vbox.addWidget(self.edit)
        self.vbox.addLayout(self.hbox)

        self.central = QWidget()

        self.central.setLayout(self.vbox)
        self.central.show()

        self.startBtn.clicked.connect(self.startDownload)
        self.stopBtn.clicked.connect(self.kill)
        self.stateChanged.connect(self.slotChanged)

        self.EnableStart()

    def slotChanged(self, newState):
        if newState == QProcess.NotRunning:
            self.startBtn.setDisabled(False)
        elif newState == QProcess.Running:
            self.startBtn.setDisabled(True)

    def startDownload(self):
        self.start("youtube-dl", [self.lineEdit.text()])

    def readStdOutput(self):
        self.edit.append(str(self.readAllStandardOutput().data().decode('utf-8','ignore')))

    def EnableStart(self):
        self.startBtn.setDisabled(self.lineEdit.text() == "")


def main():
    app = QApplication(sys.argv)
    qProcess = GUI()

    qProcess.setProcessChannelMode(QProcess.MergedChannels)
    qProcess.readyReadStandardOutput.connect(qProcess.readStdOutput)

    return app.exec_()


if __name__ == '__main__':
    main()  

我真的不知道这是否可行,但总结一下:

  • 附加到QTextEdit的字符串确实包含换行符,有时还包含回车符。 (分别为\n\r

  • 字符串需要在没有换行的情况下追加,可能就像追加后删除最后一个换行符一样简单。

  • 有几次,句子会被发送到一堆,所以我的第二个实现不起作用。请注意以下内容,请注意输出是二进制的,因为在这种情况下它还没有转换为字符串。打印下面的解码流将为您提供控制台中的预期行为。 (但显然不在QTextEdit中)

b'[youtube] dQw4w9WgXcQ: Downloading webpage\n[youtube] dQw4w9WgXcQ: Downloading video info webpage\n[youtube] dQw4w9WgXcQ: Extracting video information\n[youtube] dQw4w9WgXcQ: Downloading MPD manifest\n[youtube] dQw4w9WgXcQ: Downloading thumbnail ...\n'

b'[youtube] dQw4w9WgXcQ: Writing thumbnail to: D:\\Musikk\\DLs\\Rick Astley - Never Gonna Give You Up.jpg\n'

b'[download] Destination: D:\\Musikk\\DLs\\Rick Astley - Never Gonna Give You Up.webm\n'

b'\r[download]   0.0% of 3.33MiB at 332.99KiB/s ETA 00:10\r[download]   0.1% of 3.33MiB at 856.39KiB/s ETA 00:03\r[download]   0.2% of 3.33MiB at  1.95MiB/s ETA 00:01 '

b'\r[download]   0.4% of 3.33MiB at  4.18MiB/s ETA 00:00 '

b'\r[download]   0.9% of 3.33MiB at  3.78MiB/s ETA 00:00 '

b'\r[download]   1.8% of 3.33MiB at  4.24MiB/s ETA 00:00 '

b'\r[download]   3.7% of 3.33MiB at  5.27MiB/s ETA 00:00 '
  • 我只需打印函数提供的每个字符串,然后设置end='',就可以在python控制台中获得所需的输出,因为它确实控制了控制台中的\ r \ n。 (如果重要的话,使用PyCharm)

这是一个冗长而混乱的问题,归结为,我可以获得\r的控制台功能,在这种情况下,使用youtube-dl,无需额外的行/空格,并且没有百分比超过许多线?我对我的上一个问题有点批评,所以我尽力将这些尝试和观察纳入其中。

任何帮助表示赞赏!

通过将self.edit.append(...)更改为

,按请求编辑,以字节为单位输出
print(str(self.readAllStandardOutput()))

byte output

在这里,如果我解码输出,并用

打印
print(str(self.readAllStandardOutput().data().decode('utf-8','ignore')), end='')

enter image description here

请注意,这只显示一行,因为每次提供新字符串时它都会更新。

1 个答案:

答案 0 :(得分:2)

要删除每个文本末尾的 \ n ,我们使用strip(),然后我们必须识别具有百分比的行和子串[download],这就足够了要解决这个问题,但在某些情况下我们得到的输入是单行文本中的几行,那么我们需要的是最后一行。

def readStdOutput(self):
    data = self.readAllStandardOutput().data()
    text = data.decode('utf-8','ignore').strip()

    # get the last line of QTextEdit
    self.edit.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
    self.edit.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor)
    self.edit.moveCursor(QTextCursor.End, QTextCursor.KeepAnchor)
    lastLine = self.edit.textCursor().selectedText()

    # Check if a percentage has already been placed.
    if "[download]" in lastLine and "%" in lastLine:
        self.edit.textCursor().removeSelectedText()
        self.edit.textCursor().deletePreviousChar()
        # Last line of text
        self.edit.append("[download] "+text.split("[download]")[-1])
    else:
        self.edit.moveCursor(QTextCursor.End, QTextCursor.MoveAnchor)
        if "[download]" in text and "%" in text:
            # Last line of text
            self.edit.append("[download] "+text.split("[download]")[-1])
        else:
            self.edit.append(text)