我有4个不同的可执行程序,您可以认为它们是大小相同的空矩形窗口,并且我想在一个qt qml窗口中运行这些exe。
a,b,c,d是固定大小相同的不同可执行文件,而x是用qt5.11 / qml quick2编写的Windows,请问如何在qt / qml项目中做到这一点?
我正在尝试使用窗口容器,但没有任何进展。 exe将其窗口ID写入文本,而我正在从该文本中读取。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.addImportPath(QLatin1String("modules"));
viewer.setOrientation(QtQuick2ApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qrc:///main.qml"));
viewer.showExpanded();
QProcess ps;
ps.start("sudo ./exe 1");
sleep(10);
ifstream myfile;
myfile.open("winid.txt");
WId id ; myfile >> id;
cout<<"WId ? "<<id<<endl;
myfile.close();
//WId id = (WId)FindWindow(NULL, L"PMON");
QWindow *container = QWindow::fromWinId(id);
container->setFlags(Qt::FramelessWindowHint);
QWidget *program_start = QWidget::createWindowContainer(container);
program_start->setWindowTitle("Fero");
QVBoxLayout *manageWindows = new QVBoxLayout(program_start);
//manageWindows->addWidget(program_start);
//manageWindows->setGeometry(QRect(0,0,1400,800));
program_start->setLayout(manageWindows);
program_start->show();
return app.exec();
}
答案 0 :(得分:1)
您基本上是在问如何创建一个包含的窗口系统。在某些操作系统中,这既不容易,也不是不可能。
如果您的4个“可执行文件”是您有权访问的QML代码,则可以轻松地将它们组成一个可执行文件。
如果它们是第三方应用程序,则不是那么容易。在Linux下,可以通过使用Wayland甚至使用某些X API来实现。但是在Windows上,您实际上并没有获得这种访问权限,至少,我还没有找到一种方法来执行此操作,操作系统控制着进程窗口,您对此无能为力。>
可能可以使用窗口可能提供的低级GUI API,并且如果可能的话,隐藏4个窗口的装饰,并组成窗口,使它们位于QML应用程序窗口的顶部,并缩放和移动窗口。随着您的QML应用程序窗口的缩放和移动,代码会显示4个窗口。
无论如何,您似乎已经大大低估了执行此操作的复杂性,主要是因为对一个人应该能够做到这一点并不是不合理的期望,但是实际情况却有所不同。窗口系统在很大程度上仍然是黑匣子,人们不应该干预的事情。
答案 1 :(得分:0)
Assuming you really are trying to embed the GUI elements of child processes into your own process then the code you've has a few potential issues.
Firstly, it is possible that on some platforms QProcess::start
simply queues the required data. The child process won't actually fork until the event loop is entered. Thus when you have...
QProcess ps;
ps.start("sudo ./exe 1");
sleep(10);
ifstream myfile;
myfile.open("winid.txt");
WId id;
myfile >> id;
it's possible that the sleep(10)
call simply blocks everything and the process hasn't yet started when you try to read. Even if the child process does start there's no guarantee that it will have written its window id to winid.txt
by the time you read it -- far better to act on the QProcess::readyReadStandardOutput
signal instead.
Secondly, you pass a complete command line to QProcess::start
. On certain platforms that will pass the command through a shell meaning you have to be very careful about quoting/escaping special characters. Better to use the...
void QProcess::start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode = ReadWrite)
...overload instead.
Finally, the command you're actually running here is sudo
. Assuming this is on a Linux
system (or similar) then sudo
may well require a password and you haven't set up any means of providing one.
By way of an example, the following code does one of two things depending on how it's invoked.
If invoked with a single command line argument it creates/shows a QPushButton
derived widget and writes that widget's window id to standard output.
If invoked with no arguments it will act as a parent process. It starts several child processes and, when each prints its window id to stdout, captures and embeds the associated widget within its own.
#include <cstdlib>
#include <iostream>
#include <set>
#include <QApplication>
#include <QDebug>
#include <QLabel>
#include <QProcess>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QWindow>
namespace {
/*
* This is the basic QPushButton derived widget that will be created by the
* child process(es).
*/
class remote_process_widget: public QPushButton {
using super = QPushButton;
public:
explicit remote_process_widget (const QString &name, QWidget *parent = nullptr)
: super(name, parent)
{
}
};
}
int
main (int argc, char **argv)
{
try {
QApplication app(argc, argv);
std::set<QProcess *> processes;
if (argc > 1) {
/*
* This process was started with at least one command line arg so we
* assume it's a managed child process. Need to write the window id to
* stdout for the parent process to read.
*/
auto *w = new remote_process_widget(QString::fromStdString(argv[1]));
w->show();
std::cout << w->winId() << std::endl;
} else {
/*
* No command line args so start up as the parent process. Create some
* child processes and set things up to manage their widgets.
*/
auto *w = new QWidget;
auto *l = new QVBoxLayout(w);
auto *label = new QLabel("Parent process");
label->setAlignment(Qt::AlignCenter);
l->addWidget(label);
w->show();
/*
* Now create/start the child processes.
*/
for (int i = 0; i < 4; ++i) {
auto *process = new QProcess;
processes.insert(process);
/*
* Connect to the `QProcess::readyReadStandardOutput` signal of the
* child. This is where the real work is done regarding the
* capture/embedding of the child processes widgets.
*/
QObject::connect(process, &QProcess::readyReadStandardOutput,
[l, process]()
{
auto wid = QString(process->readAllStandardOutput()).toULongLong();
std::cout << "wid = " << wid << "\n";
if (auto *window = QWindow::fromWinId(wid)) {
if (auto *container = QWidget::createWindowContainer(window)) {
l->addWidget(container);
}
}
});
/*
* Start the child process.
*/
process->start(argv[0], QStringList() << QString("Remote process %1").arg(i));
}
}
app.exec();
/*
* Shut down all child processes.
*/
for (auto process: processes) {
process->terminate();
std::cout << "waiting for process " << process->processId() << " to terminate\n";
while (!process->waitForFinished())
;
}
std::cout << "done\n";
}
catch (std::exception &ex) {
qCritical() << "\n" << ex.what();
}
catch (...) {
qCritical() << "\nunrecognized exception";
}
exit(0);
}
So, while it doesn't use QML
, if you run it without any arguments it should create its own widget, create four child processes and embed the widgets associated with those child processes. Something like...
答案 2 :(得分:0)
如果您使用的是Linux,则可以编写一个Wayland合成器来编写应用程序。
这应该做您想要的:
import QtQuick 2.0
import QtWayland.Compositor 1.3 // or 1.2 on Qt 5.11
import QtQuick.Window 2.2
WaylandCompositor {
id: wlcompositor
WaylandOutput {
sizeFollowsWindow: true
compositor: wlcompositor
window: Window {
width: 1024
height: 768
visible: true
title: wlcompositor.socketName
Grid {
columns: 2
Repeater {
model: shellSurfaces
ShellSurfaceItem {
autoCreatePopupItems: true
shellSurface: modelData
onSurfaceDestroyed: shellSurfaces.remove(index)
}
}
}
}
}
ListModel { id: shellSurfaces }
// Qt 5.11+
XdgShellV6 {
onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface})
}
// Qt 5.12+
XdgShell {
onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface})
}
// Qt 5.12+ Disable window decorations (for qt applications you can also do this by setting
// QT_WAYLAND_DISABLE_WINDOWDECORATION=1 in the client's environment (any version).
XdgDecorationManagerV1 {
preferredMode: XdgToplevel.ServerSideDecoration
}
}
然后可以使用./myclient -platform wayland
来启动客户端。
如果您正在运行嵌套的Wayland会话,则必须通过相应设置WAYLAND_DISPLAY
即env WAYLAND_DISPLAY=wayland-1 ./myclient -platform wayland
答案 3 :(得分:0)
经过长时间的研究,我本可以设法在qt应用程序中运行可执行文件,这就是我的方法:如果您的程序每个窗口都有一个窗口
有一个ID,您可以使用它,首先,我正在运行我的外包可执行文件(例如4个spearate进程,但使用相同的exe),然后他们在文件'md5s': x['md5s'].sum()
之后创建自己的Win ID并创建文件当qt容器创建的everty进程进入该qt容器内部时,带有该wid的qt容器(wid具有x和y轴的某些功能)现在在一个分割的窗口中运行着一些备用进程。
enter image description here
s write finished, my main window program reading that wid
CreateContainer createContainerOBJ;
grids-> setCellWidget(i +(i + 1),j,createContainerOBJ.createContainer(id [i * tableCol + j])); // createConteiner是一个函数,下面有两行
// createContainer功能内容
// QWindow *容器= QWindow :: fromWinId(id);
// program_start = QWidget :: createWindowContainer(container);
int main(int argc, char *argv[]){
QApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.addImportPath(QLatin1String("modules"));
viewer.setOrientation(QtQuick2ApplicationViewer::ScreenOrientationAuto);
viewer.setMainQmlFile(QLatin1String("qrc:///main.qml"));
viewer.showExpanded();
QProcess ps;
ps.start("sudo ./exe 1");
sleep(10);
ifstream myfile;
myfile.open("winid.txt");
WId id ; myfile >> id;
cout<<"WId ? "<<id<<endl;
myfile.close();
QTableWidget* grids ;