Embedding an Application (In This Case a Terminal) Within a Qt Application

embedding an application (in this case a terminal) within a QT application

Sorry, I've tried your solution before posting oh this site and it does not work.
I've solved switching to kdelibs and using those imports and this code

#include <kparts/part.h>
#include <assert.h>
#include <kde_terminal_interface.h>
#include <kpluginfactory.h>
#include <klibloader.h>

KLibFactory* factory = KLibLoader::self()->factory( "libkonsolepart" );
KParts::Part* p = static_cast<KParts::Part*>(factory->create( this,"tralala",
QStringList() << "dio") );

assert(p);
setCentralWidget( p->widget() );
TerminalInterface *t = qobject_cast<TerminalInterface*>(p);
t->showShellInDir( QDir::home().path() );

QT 5.5 embed external application into QWidget

The following achieves the desired result, the key was adding the FramelessWindowHint:

QWindow *window = QWindow::fromWinId(211812356);
window->setFlags(Qt::FramelessWindowHint);

QWidget *widget = QWidget::createWindowContainer(window);

QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(widget);
this->setLayout(layout);

PyQT(also C++ QT binding) embedded urxvt terminal loosing focus

From the docs for QX11EmbedContainer:

It is possible for QX11EmbedContainer to embed XEmbed widgets from
toolkits other than Qt, such as GTK+. Arbitrary (non-XEmbed) X11
widgets can also be embedded, but the XEmbed-specific features such as
window activation and focus handling are then lost.

So perhaps urxvt (or your version of it) does not support all the necessary features of the XEmbed Protocol.

A web search turned up this comment:

urxvt -embed almost works. It claims to support it and everything, but
does not send XEMBED_REQUEST_FOCUS when you click in it. This means
there's no way to get focus back after it's lost it.

how to use a terminal embedded in a PyQt GUI

If it has to be a real terminal and a real shell (and not just accepting a line of input, running some command, then displaying output) -- how about tmux?

You could use something like tee to get the output back into your program.

Note that tmux sessions may persist across your program runs, so you'd need to read up on how that works and how to control it.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class embeddedTerminal(QWidget):

def __init__(self):
QWidget.__init__(self)
self._processes = []
self.resize(800, 600)
self.terminal = QWidget(self)
layout = QVBoxLayout(self)
layout.addWidget(self.terminal)
self._start_process(
'xterm',
['-into', str(self.terminal.winId()),
'-e', 'tmux', 'new', '-s', 'my_session']
)
button = QPushButton('List files')
layout.addWidget(button)
button.clicked.connect(self._list_files)

def _start_process(self, prog, args):
child = QProcess()
self._processes.append(child)
child.start(prog, args)

def _list_files(self):
self._start_process(
'tmux', ['send-keys', '-t', 'my_session:0', 'ls', 'Enter'])

if __name__ == "__main__":
app = QApplication(sys.argv)
main = embeddedTerminal()
main.show()
sys.exit(app.exec_())

A bit more here: https://superuser.com/questions/492266/run-or-send-a-command-to-a-tmux-pane-in-a-running-tmux-session

PyQt5 pass command to embedded terminal 'urxvt' or 'xterm'

One possible solution is to use tmux as an intermediary to send the commands:

import sys
import time
import uuid

from PyQt5 import QtCore, QtGui, QtWidgets

import gi

gi.require_version("Wnck", "3.0")
from gi.repository import Wnck, Gdk

class TerminalContainer(QtWidgets.QTabWidget):
def __init__(self, parent=None):
super().__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
lay.setContentsMargins(0, 0, 0, 0)
self.name_session = uuid.uuid4().hex

def start(self):
started, procId = QtCore.QProcess.startDetached(
"xterm", ["-e", "tmux", "new", "-s", self.name_session], "."
)
if not started:
QtWidgets.QMessageBox.critical(
self, 'Command "{}" not started!'.format(command), "Eh"
)
return
attempts = 0
while attempts < 10:
screen = Wnck.Screen.get_default()
screen.force_update()
time.sleep(0.1)
while Gdk.events_pending():
Gdk.event_get()
for w in screen.get_windows():
print(attempts, w.get_pid(), procId, w.get_pid() == procId)
if w.get_pid() == procId:
win32w = QtGui.QWindow.fromWinId(w.get_xid())
widg = QtWidgets.QWidget.createWindowContainer(win32w)
self.layout().addWidget(widg)
self.resize(500, 400)
return
attempts += 1
QtWidgets.QMessageBox.critical(
self, "Window not found", "Process started but window not found"
)

def stop(self):
QtCore.QProcess.execute("tmux", ["kill-session", "-t", self.name_session])

def send_command(self, command):
QtCore.QProcess.execute(
"tmux", ["send-keys", "-t", self.name_session, command, "Enter"]
)

class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)

self.ifconfig_btn = QtWidgets.QPushButton("ifconfig")
self.ping_btn = QtWidgets.QPushButton("ping")
self.terminal = TerminalContainer()

central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)

lay = QtWidgets.QGridLayout(central_widget)
lay.addWidget(self.ifconfig_btn, 0, 0)
lay.addWidget(self.ping_btn, 0, 1)
lay.addWidget(self.terminal, 1, 0, 1, 2)

self.terminal.start()

self.resize(640, 480)

self.ifconfig_btn.clicked.connect(self.launch_ifconfig)
self.ping_btn.clicked.connect(self.launch_ping)

def launch_ifconfig(self):
self.terminal.send_command("ifconfig")

def launch_ping(self):
self.terminal.send_command("ping 8.8.8.8")

def closeEvent(self, event):
self.terminal.stop()
super().closeEvent(event)

if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

QX11EmbedWidget and QX11EmbedContainer

The first example work because xterm is able to reparent its top level widget (an X11 window). You tell it to do so with the argument -into <WinId>.

I don't know if Konsole can do that, i don't use it and the man page doesn't seem to talk about this.

But that doesn't mean it is not doable, the X Window system is very flexible and anyone can reparent another window (that's how windows managers add decorations to windows).

Take a look at man 3 XReparentWindow ;-)

Embedding IPython Qt console in a PyQt application

Ok, this code seems to do the trick (i.e. it puts a non-blocking ipython interpreter in a Qt widget, which can be embedded into other widgets). Keywords passed to terminal_widget get added to the namespace of the widget

import atexit

from IPython.zmq.ipkernel import IPKernelApp
from IPython.lib.kernel import find_connection_file
from IPython.frontend.qt.kernelmanager import QtKernelManager
from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.utils.traitlets import TraitError
from PyQt4 import QtGui, QtCore

def event_loop(kernel):
kernel.timer = QtCore.QTimer()
kernel.timer.timeout.connect(kernel.do_one_iteration)
kernel.timer.start(1000*kernel._poll_interval)

def default_kernel_app():
app = IPKernelApp.instance()
app.initialize(['python', '--pylab=qt'])
app.kernel.eventloop = event_loop
return app

def default_manager(kernel):
connection_file = find_connection_file(kernel.connection_file)
manager = QtKernelManager(connection_file=connection_file)
manager.load_connection_file()
manager.start_channels()
atexit.register(manager.cleanup_connection_file)
return manager

def console_widget(manager):
try: # Ipython v0.13
widget = RichIPythonWidget(gui_completion='droplist')
except TraitError: # IPython v0.12
widget = RichIPythonWidget(gui_completion=True)
widget.kernel_manager = manager
return widget

def terminal_widget(**kwargs):
kernel_app = default_kernel_app()
manager = default_manager(kernel_app)
widget = console_widget(manager)

#update namespace
kernel_app.shell.user_ns.update(kwargs)

kernel_app.start()
return widget

app = QtGui.QApplication([])
widget = terminal_widget(testing=123)
widget.show()
app.exec_()


Related Topics



Leave a reply



Submit