gpt4 book ai didi

python-3.x - PyQt5 替代 Qtermwidget

转载 作者:行者123 更新时间:2023-12-04 09:37:43 26 4
gpt4 key购买 nike

我正在尝试寻找 Qtermwidget 的替代方法来显示终端输出并接受终端输入(很像标准的 linux 终端)。

我遇到的唯一问题是,在目标操作系统 (ubuntu) 上,由于某些问题,必须手动编译并重新安装它。

我试图使我的应用程序的设置尽可能简单快捷,大多数依赖项都是简单的 pip 包或标准的 apt-installs。

所以我的问题是:

是否有标准库或使用像 pyqt 中的输入/输出这样的终端的方法?我已经考虑过在 javascript 中构建它(足够简单)并使用 QWebEngineView 但这是最​​好的选择吗?

最佳答案

一种可能的选择是使用纯 python 编写 QTermWidget 逻辑以使其可移植,但这可能需要时间,因此在此答案中,我将使用 xterm.js 实现逻辑。在 QWebChannel 的帮助下:
index.html

<!doctype html>
<html>
<head>
<style>
* { padding: 0; margin: 0; }
html, body, #terminal-container {
min-height: 100% !important;
width: 100%;
height: 100%;
}
#terminal-container {
background: black;
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.5.0/css/xterm.css" />
<script src="https://cdn.jsdelivr.net/npm/xterm@4.5.0/lib/xterm.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.3.0/lib/xterm-addon-fit.js"></script>
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<div id="terminal-container"></div>
</body>
</html>
index.js
window.onload = function () {
const terminal = new Terminal();
f = new FitAddon.FitAddon();
terminal.loadAddon(f);
const container = document.getElementById('terminal-container');
terminal.open(container);
terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
f.fit();
new QWebChannel(qt.webChannelTransport, function (channel) {
var socket = channel.objects.socket;
var resize_listener = channel.objects.resize_listener;
terminal.onKey(function(e){
socket.send_data(e.key)
});
socket.dataChanged.connect(function(text){
terminal.write(text)
});
resize_listener.resized.connect(function(){
f.fit();
});
});
}
main.py
from functools import cached_property
import os

from PyQt5 import QtCore, QtWidgets, QtNetwork, QtWebEngineWidgets, QtWebChannel

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class TerminalSocket(QtNetwork.QTcpSocket):
dataChanged = QtCore.pyqtSignal(str)

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

self.readyRead.connect(self._handle_ready_read)
self.error.connect(self._handle_error)

@QtCore.pyqtSlot(str)
def send_data(self, message):
self.write(message.encode())

def _handle_ready_read(self):
data = self.readAll().data()
self.dataChanged.emit(data.decode())

def _handle_error(self):
print(self.errorString())


class ResizeListener(QtCore.QObject):
resized = QtCore.pyqtSignal()

def __init__(self, widget):
super().__init__(widget)
self._widget = widget
if isinstance(self.widget, QtWidgets.QWidget):
self.widget.installEventFilter(self)

@property
def widget(self):
return self._widget

def eventFilter(self, obj, event):
if obj is self.widget and event.type() == QtCore.QEvent.Resize:
QtCore.QTimer.singleShot(100, self.resized.emit)
return super().eventFilter(obj, event)


class TerminalWidget(QtWebEngineWidgets.QWebEngineView):
def __init__(self, ipaddr, port, parent=None):
super().__init__(parent)

resize_listener = ResizeListener(self)
self.page().setWebChannel(self.channel)
self.channel.registerObject("resize_listener", resize_listener)
self.channel.registerObject("socket", self.socket)
filename = os.path.join(CURRENT_DIR, "index.html")
self.load(QtCore.QUrl.fromLocalFile(filename))
self.socket.connectToHost(ipaddr, port)

@cached_property
def socket(self):
return TerminalSocket()

@cached_property
def channel(self):
return QtWebChannel.QWebChannel()


def main():
import sys

app = QtWidgets.QApplication(sys.argv)

QtCore.QCoreApplication.setApplicationName("QTermWidget Test")
QtCore.QCoreApplication.setApplicationVersion("1.0")

parser = QtCore.QCommandLineParser()
parser.addHelpOption()
parser.addVersionOption()
parser.setApplicationDescription(
"Example(client-side) for remote terminal of QTermWidget"
)
parser.addPositionalArgument("ipaddr", "adrress of host")
parser.addPositionalArgument("port", "port of host")

parser.process(QtCore.QCoreApplication.arguments())

requiredArguments = parser.positionalArguments()
if len(requiredArguments) != 2:
parser.showHelp(1)
sys.exit(-1)

address, port = requiredArguments
w = TerminalWidget(QtNetwork.QHostAddress(address), int(port))
w.resize(640, 480)
w.show()
sys.exit(app.exec_())


if __name__ == "__main__":
main()

关于python-3.x - PyQt5 替代 Qtermwidget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62479231/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com