如何将第三方应用程序(使用 SDL2)嵌入到 QWidget 中?
How to embed a third party application (using SDL2) into a QWidget?
我正在尝试在我的 PyQt5 应用程序中显示另一个进程 window。因为我在 Linux 上工作,所以我得到了这个 python gist 与 x11 一起工作。我将代码更改为从 PID 抓取,然后忙等到 window 打开并使用 subprocess.Popen
启动程序
然而,这种方法存在一些问题:
它有点不稳定。有时它无法获取 window,我认为这与在启动时直接从 QSettings
恢复布局有关。
我收到这些错误消息:
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 2577, resource id: 127926283, major code: 18 (ChangeProperty), minor code: 0
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 2578, resource id: 127926283, major code: 12 (ConfigureWindow), minor code: 0
这是什么意思?
但是,如果它不依赖于平台,我会接受不稳定的解决方案!我希望有一个独立于平台的解决方案,至少对于 Linux 和 Windows。我猜在我的 PyQt5 应用程序中使用 xlib 会将它绑定到 Linux。那么下一个问题是有一种独立于平台的方式来显示在我的 PyQt5 应用程序中使用 SDL2 的第三方应用程序吗?我不确定,但也许在我的应用程序中嵌入 xserver 是一个解决方案,但我对 xserver 了解不多,我认为这不是一件容易的事。
理想的解决方案纯粹是用 Python 编写的(如果没有其他方法,也可以用 C++ 编写),但是由于第三方应用程序是开源的 (C++),我可以这样重写应用程序一种支持被 PyQt5 独立抓取的平台的方法。这会很不方便,因为我无法使用预构建的二进制文件,但如果这是唯一的方法,并且付出了合理的努力,我会接受它。我的即时想法是通过 SDL 获取 window ID 并将其以某种方式发送到我的应用程序。我的研究没有就如何做到这一点以及 my attempt 使用
产生任何结果
SDL_GetWindowID(SDL_Window * window);
失败,因为很快我(认为我)发现它返回了 SDL 实习生 window ID 而不是操作系统 WID。所以我的问题是:如何从 SDL 获取 Window ID?或者如何让我的 PyQt5 应用程序获取它的 window?
也许最好(也是最困难)的解决方案是重写开源应用程序,以在 QWindow 中显示其内容并发送此 ID,但我不知道如何接近那个,也不是 link 这个应用程序与 qt。也许在这一点上值得注意,我是 Qt 的新手,这就是我使用 PyQt5 的原因。
你必须使用SDL_SysWMinfo
来获取Window的id,它根据OS提供不同的属性,例如X11你必须使用x11.window
windows win.window
:
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
uint32_t nix = 0;
auto win = SDL_CreateWindow("Test", 0, 0, 400, 200, nix);
SDL_RaiseWindow(win);
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(win, &wmInfo);
printf("ID: %d\n", wmInfo.info.x11.window);
fflush(stdout);
while (1) { usleep(100000); }
return 0;
}
import os
import sys
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
CURRENT_DIRECTORY = Path(__file__).resolve().parent
def find_id(executable):
win_id = -1
process = QtCore.QProcess()
process.setProgram(executable)
loop = QtCore.QEventLoop()
def handle_readyReadStandardOutput():
text = process.readAllStandardOutput().data().decode()
_, id_str = text.split()
nonlocal win_id
win_id = int(id_str)
loop.quit()
process.readyReadStandardOutput.connect(handle_readyReadStandardOutput)
process.start()
loop.exec_()
return win_id
def main():
app = QtWidgets.QApplication(sys.argv)
win_id = find_id(os.fspath(CURRENT_DIRECTORY / "test"))
main_widget = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(main_widget)
window = QtGui.QWindow.fromWinId(win_id)
widget = QtWidgets.QWidget.createWindowContainer(window)
button = QtWidgets.QPushButton("Close")
button.clicked.connect(main_widget.close)
layout.addWidget(widget)
layout.addWidget(button)
main_widget.show()
app.exec_()
if __name__ == "__main__":
main()
我正在尝试在我的 PyQt5 应用程序中显示另一个进程 window。因为我在 Linux 上工作,所以我得到了这个 python gist 与 x11 一起工作。我将代码更改为从 PID 抓取,然后忙等到 window 打开并使用 subprocess.Popen
启动程序
然而,这种方法存在一些问题:
它有点不稳定。有时它无法获取 window,我认为这与在启动时直接从 QSettings
恢复布局有关。
我收到这些错误消息:
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 2577, resource id: 127926283, major code: 18 (ChangeProperty), minor code: 0
qt.qpa.xcb: QXcbConnection: XCB error: 3 (BadWindow), sequence: 2578, resource id: 127926283, major code: 12 (ConfigureWindow), minor code: 0
这是什么意思?
但是,如果它不依赖于平台,我会接受不稳定的解决方案!我希望有一个独立于平台的解决方案,至少对于 Linux 和 Windows。我猜在我的 PyQt5 应用程序中使用 xlib 会将它绑定到 Linux。那么下一个问题是有一种独立于平台的方式来显示在我的 PyQt5 应用程序中使用 SDL2 的第三方应用程序吗?我不确定,但也许在我的应用程序中嵌入 xserver 是一个解决方案,但我对 xserver 了解不多,我认为这不是一件容易的事。
理想的解决方案纯粹是用 Python 编写的(如果没有其他方法,也可以用 C++ 编写),但是由于第三方应用程序是开源的 (C++),我可以这样重写应用程序一种支持被 PyQt5 独立抓取的平台的方法。这会很不方便,因为我无法使用预构建的二进制文件,但如果这是唯一的方法,并且付出了合理的努力,我会接受它。我的即时想法是通过 SDL 获取 window ID 并将其以某种方式发送到我的应用程序。我的研究没有就如何做到这一点以及 my attempt 使用
产生任何结果SDL_GetWindowID(SDL_Window * window);
失败,因为很快我(认为我)发现它返回了 SDL 实习生 window ID 而不是操作系统 WID。所以我的问题是:如何从 SDL 获取 Window ID?或者如何让我的 PyQt5 应用程序获取它的 window?
也许最好(也是最困难)的解决方案是重写开源应用程序,以在 QWindow 中显示其内容并发送此 ID,但我不知道如何接近那个,也不是 link 这个应用程序与 qt。也许在这一点上值得注意,我是 Qt 的新手,这就是我使用 PyQt5 的原因。
你必须使用SDL_SysWMinfo
来获取Window的id,它根据OS提供不同的属性,例如X11你必须使用x11.window
windows win.window
:
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
uint32_t nix = 0;
auto win = SDL_CreateWindow("Test", 0, 0, 400, 200, nix);
SDL_RaiseWindow(win);
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(win, &wmInfo);
printf("ID: %d\n", wmInfo.info.x11.window);
fflush(stdout);
while (1) { usleep(100000); }
return 0;
}
import os
import sys
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
CURRENT_DIRECTORY = Path(__file__).resolve().parent
def find_id(executable):
win_id = -1
process = QtCore.QProcess()
process.setProgram(executable)
loop = QtCore.QEventLoop()
def handle_readyReadStandardOutput():
text = process.readAllStandardOutput().data().decode()
_, id_str = text.split()
nonlocal win_id
win_id = int(id_str)
loop.quit()
process.readyReadStandardOutput.connect(handle_readyReadStandardOutput)
process.start()
loop.exec_()
return win_id
def main():
app = QtWidgets.QApplication(sys.argv)
win_id = find_id(os.fspath(CURRENT_DIRECTORY / "test"))
main_widget = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(main_widget)
window = QtGui.QWindow.fromWinId(win_id)
widget = QtWidgets.QWidget.createWindowContainer(window)
button = QtWidgets.QPushButton("Close")
button.clicked.connect(main_widget.close)
layout.addWidget(widget)
layout.addWidget(button)
main_widget.show()
app.exec_()
if __name__ == "__main__":
main()