Встраивание стороннего приложения в python GUI

Необходимо в свой GUI встроить одним из виджетов окно xfce4 (не все настройки, а только некоторые, например xfce4-display-settings). Подскажите, какие есть рабочие способы это сделать на python-3.x ?

Пробовал в PyQt5 использовать createWindowContainer (window_id отлавливал через xwininfo), но оно не помещалось внутрь виджета, а открывалось поверх формы.

Опыты с gtk.Plug и gtk.Socket тоже не дали результата.


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

Автор решения: S. Nick

я не совсем понял ваши пояснения, но отвечая на ваш прямой вопрос с использованием PyQt5, это может выглядеть примерно так:

import sys
import subprocess
import threading
import time
import win32gui
from PyQt5.QtCore    import Qt
from PyQt5.QtGui     import QWindow, QPixmap
from PyQt5.QtWidgets import (QWidget, QApplication, QVBoxLayout,
                             QGridLayout, QMainWindow, QLabel) 


class Example(QMainWindow):
    def __init__(self):
        super().__init__()

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        
        self.widget = QWidget()
        self.widget.setFixedSize(230, 280)
        self.widget.setStyleSheet("background-color: yellow;")
        self.label = QLabel(self)
        self.label.setPixmap(
            QPixmap('images/splash_.jpg').scaled(self.size().width()/2, self.size().height())
        )
        
        self.grid_layout = QGridLayout(self.central_widget)
        self.grid_layout.addWidget(self.widget, 0, 0, 2, 1)
        
        self.v_layout = QVBoxLayout(self.widget)
        self.initUI()
        self.grid_layout.addWidget(self.label, 0, 1, 1, 1) 
 
    def initUI(self):
        t = threading.Thread(target=self.runExe)
        t.start()
 
        hwnd1 = win32gui.FindWindowEx(0, 0, "CalcFrame", "Калькулятор")
        start = time.time()
        while hwnd1 == 0:
            time.sleep(0.01)
            hwnd1 = win32gui.FindWindowEx(0, 0, "CalcFrame", "Калькулятор")
            end = time.time()
            if end - start > 5:
                return
        window = QWindow.fromWinId(hwnd1)
        widget = self.createWindowContainer(window, self.central_widget)
        self.v_layout.addWidget(widget)
 
    @staticmethod
    def runExe():
        exePath = "C:/Windows/system32/calc.exe"
        subprocess.Popen(exePath)

 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.resize(550, 400)
    ex.show()
    sys.exit(app.exec_())

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

→ Ссылка
Автор решения: Artem Voyush

Нашел решение с использованием GTK+ 3.0

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from subprocess import Popen

class MainWindow(Gtk.ApplicationWindow):
    def __init__(self):
        Gtk.Window.__init__(self, title="Настройки")
        self.set_border_width(10)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_default_size(800, 480)

        self.vbox = Gtk.Box(spacing=10, orientation='vertical')
        self.add(self.vbox)

        self.hbox1 = Gtk.Box(spacing=10, orientation='horizontal')
        self.vbox.pack_start(self.hbox1, False, False, 0)

        self.i_display = Gtk.Image()
        self.i_display.set_from_file('image/display.png')
        self.i_display.show()
        self.b_display = Gtk.Button()
        self.b_display.add(self.i_display)
        self.b_display.show()
        self.hbox1.pack_start(self.b_display, True, True, 0)

        self.i_sesson = Gtk.Image()
        self.i_sesson.set_from_file('image/setting.png')
        self.i_sesson.show()
        self.b_sesson = Gtk.Button()
        self.b_sesson.add(self.i_sesson)
        self.b_sesson.show()
        self.hbox1.pack_start(self.b_sesson, True, True, 0)

        widget = Gtk.Frame()

        self.vbox.pack_start(widget, True, True, 0)
        widget.hide()
        self.b_display.connect("clicked", lambda x: self.Display_settings(widget))
        self.b_sesson.connect("clicked", lambda x: self.Session_settings(widget))

        self.label = Gtk.Label()
        self.label.set_text("Для настройки необходимых параметров,\nиспользуйте кнопки.")
        self.label.set_justify(Gtk.Justification.LEFT)
        self.label.show()
        self.vbox.pack_start(self.label, True, False, 0)

        self.hbox2 = Gtk.Box(spacing=10, orientation='horizontal')
        self.vbox.pack_start(self.hbox2, False, False, 0)

        self.b_back = Gtk.Button(label='Назад')
        self.b_back.set_property("width-request", 85)
        self.b_back.set_property("height-request", 15)
        self.b_back.show()
        self.b_back.connect("clicked", lambda x: self.Back(widget))
        self.hbox2.pack_start(self.b_back, True, True, 0)

        self.b_exit = Gtk.Button(label='Выход')
        self.b_exit.set_property("width-request", 85)
        self.b_exit.set_property("height-request", 15)
        self.b_exit.show()
        self.b_exit.connect("clicked", Gtk.main_quit)
        self.hbox2.pack_start(self.b_exit, True, True, 0)

        self.vbox.show()
        self.hbox1.show()
        self.hbox2.show()

    def Display_settings(self, widget):
        widget.show()
        self.label.hide()
        self.hbox1.hide()
        self.socket = Gtk.Socket()
        widget.add(self.socket)
        self.sock_id = str(self.socket.get_id())
        self.socket.show()
        cmd = ["xfce4-display-settings", "--socket-id=" + str(self.sock_id)]
        Popen(cmd)

    def Session_settings(self, widget):
        widget.show()
        self.label.hide()
        self.hbox1.hide()
        self.socket = Gtk.Socket()
        widget.add(self.socket)
        self.sock_id = str(self.socket.get_id())
        self.socket.show()
        cmd = ["xfce4-session-settings", "--socket-id=" + str(self.sock_id)]
        Popen(cmd)

    def Back(self, widget):
        self.socket.destroy()
        widget.hide()
        self.hbox1.show()
        self.label.show()


win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show()
Gtk.main()
→ Ссылка