【问题标题】:QDesktopWidget for an X display用于 X 显示的 QDesktopWidget
【发布时间】:2016-02-19 06:41:34
【问题描述】:

我有一个 X 显示器说 :2 。我想在给定的 X 上显示我的 qt 小部件 展示。该显示不同于主显示。所以除了主显示器(由环境变量 DISPLAY 设置)之外,我还想访问一个额外的 X 显示器。

我知道 QDekstopWidget 有屏幕功能()。这不是我想要的。一世 当我想使用 显示 ID。

让我知道是否有办法这样做。 更新:试过这个

#include<QApplication>
#include<QWidget>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>


int main(int argc, char *argv[])
{
QApplication a(argc, argv);

Display* display = XOpenDisplay(":1");

XSynchronize(display, True);
//XSetErrorHandler(myErrorHandler);

Window x11root = XDefaultRootWindow(display);

int x = 0;
int y = 0;
unsigned int width = 500;
unsigned int height = 500;
unsigned int borderWidth = 0;
long colorBlue = 0xff0000ff;

Window x11w = XCreateSimpleWindow(display, x11root, x, y, 
    width, height, borderWidth, 1 /*magic number*/, colorBlue);
XMapWindow(display, x11w); // must be performed after XReparentWindow, 
                           // otherwise the window is not visible.

QWidget w;
w.resize(200,200);
w.show();

XReparentWindow(display, w.winId(), x11w, 0, 0);

return a.exec();

}

按照建议尝试了 qscreen 测试。它检测到显示,但两个窗口都在显示:3

shiva@RSV-HP-ENVY-15-Notebook-PC:/tmp/korvins-qtbase-6226fcdc3e4ace4636c58778ef53fbf69f46c36e-6226fcdc3e4ace4636c58778ef53fbf69f46c36e/tests/manual/qscreen$ ./qscreen -platform xcb::3::5
qt.core.logging: Loading "/home/shiva/.config/QtProject/qtlogging.ini" ...
qt.qpa.screen: Output VGA-1-0 is not connected
qt.qpa.screen: Output HDMI-1-0 is not connected
qt.qpa.screen: adding QXcbScreen(0x1b82f60, name="eDP-1-0", geometry=1366x768+0+0, availableGeometry=1309x744+57+24, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=344.0x194.0mm, screenNumber=0, virtualSize=1366x768 (1366.0x768.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=59.0, root=2c1, windowManagerName="Compiz") (Primary: true )
qt.qpa.screen: primary output is "eDP-1-0"
qt.qpa.screen: connecting to additional display: "" "3"
qt.qpa.screen: adding QXcbScreen(0x1bae540, name="TurboVNC", geometry=1024x716+0+0, availableGeometry=1024x664+0+28, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=271.0x189.0mm, screenNumber=0, virtualSize=1024x716 (1024.0x716.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=60.0, root=6a, windowManagerName="Metacity") (Primary: true )
qt.qpa.screen: primary output is "TurboVNC"
qt.qpa.screen: connecting to additional display: "" "5"
qt.qpa.screen: adding QXcbScreen(0x1bd6ca0, name="TurboVNC", geometry=1024x716+0+0, availableGeometry=1024x664+0+28, devicePixelRatio=1.0, logicalDpi=QPair(96.0,96.0), physicalSize=271.0x189.0mm, screenNumber=0, virtualSize=1024x716 (1024.0x716.0mm), orientation=Qt::ScreenOrientation(LandscapeOrientation), depth=24, refreshRate=60.0, root=6a, windowManagerName="Metacity") (Primary: true ) 
qt.qpa.screen: primary output is "TurboVNC"
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Xlib: extension "GLX" missing on display ":5".
Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface. 

【问题讨论】:

    标签: c++ linux qt xserver


    【解决方案1】:

    QX11Info 提供对 X Display 信息的访问权限。参考:QX11Info::display()

    我假设您需要打开第二个 X 连接到第二个显示器,并将其传递给新创建的小部件。

    Here 也是一些信息。

    【讨论】:

    • 这会改变什么XReparentWindow(display, w.winId(), x11root, 0, 0);(我认为您不需要创建第二个窗口)?如果这没有帮助,除了拥有两个独立的 QApplications 之外,我没有更多的想法,但是您可能需要两个进程。
    • 是的,您不需要创建第二个窗口。它不适用于根窗口,所以我也创建了第二个窗口来尝试一下。
    【解决方案2】:

    如果您查看 QXcbConnection 构造函数,m_displayName 会初始化为 displayName 参数的内容(如果它不为 null),否则会初始化为 DISPLAY env 变量,然后它会使用该显示调用 xcb_connect(),并且从那时起,该 Qt 应用程序通常只与该显示器对话。它不会自动发现其他显示器。 QXcbConnection 在 QXcbIntegration 的构造函数中创建,然后在 QGuiApplication 的 init_platform 函数中创建。 QXcbIntegration 也会查找 -display 命令行参数,因此这是选择显示的第二种方式(覆盖 DISPLAY 环境变量)。

    配置它的第三种方法是init_platform 将附加到平台插件名称的任何冒号分隔的参数分开,这些参数最终作为 QXcbIntegration 构造函数的 QStringList 参数。 QXcbIntegration 一次接受两个,并为每对创建额外的 QXcbConnection 实例。因此,如果您使用-platform xcb::0.1::0.2 启动您的应用程序,它将连接到显示器:0.1 和:0.2 以及默认显示器(通常来自DISPLAY 环境变量)。但是,如果您提供无效的显示,它将失败,例如说“无法连接到显示:0.2”。

    现在尝试使用 QScreen 手动测试(假设您有显示 :0 和 :0.1 可用):

    cd path/to/qtbase/tests/manual/qscreen
    qmake
    make
    ./qscreen -platform xcb::0.1
    

    您将在每个显示的每个输出上获得一个窗口,而没有任何参数您将仅在默认显示的每个输出上获得一个窗口。

    您还可以设置环境变量QPA_PLATFORM,而不是提供-platform 参数。在您的主程序中,您甚至可以使用qputenv 在构造QApplication 之前设置环境变量,以防您想避免在shell 中配置环境变量。如果您弄清楚如何发现显示,您可以通过编程方式构建该参数。

    正如您在手动测试的 main.cpp 中看到的那样,QGuiApplication::screens() 将为您提供 Qt 连接到的每个显示器上的每个输出的 QScreen 实例。然后您可以使用QScreen:name() 或其他属性来识别您要使用的屏幕。一个显示器上的多个输出通常并排排列,因此调用setGeometry() 来定位窗口通常足以将其放到一个屏幕或另一个屏幕上;但是在您的情况下,您有多个显示器,因此您还需要调用 QWindow::setScreen() 将小部件的父级设置为适当的 QDesktopWidget 的屏幕小部件,如您在 screenAdded() 的中间所见功能。

    【讨论】:

    • 谢谢!我会试试看。你知道qt4中的方法吗...我们的应用程序在qt4中,因此我们必须为此升级到qt5。
    • 试过你的解决方案。如果我遗漏了什么,请告诉我
    • 试过 qscreen 测试。让我知道你的想法
    【解决方案3】:

    如果我正确理解了您的问题,那么我的解决方案就很糟糕。 您可以通过指定 ./app -display :2 手动设置显示 如果你不能这样做,你可以在 main() 函数中改变你的命令行选项。像这样的。

    #include <QApplication>
    #include <QWidget>
    #include <cstdio>
    #include <cstring>
    
    int main(int argc, char** argv)
    {
        char** args = (char**)malloc((argc + 2) * sizeof(char*));
        for(int i = 0; i < argc; ++i) {
                int l = strlen(argv[i]);
                args[i] = (char*)malloc(l * sizeof(char));
                strcpy(args[i], argv[i]);
        }
        const char* const display = "-display_";
        const char* const display_number = ":2_";
        args[argc] = (char*)malloc(strlen(display) * sizeof(char));
        args[argc + 1] = (char*)malloc(strlen(display_number) * sizeof(char));
        strcpy(args[argc], display);
        strcpy(args[argc + 1], display_number);
        args[argc][strlen(display) - 1] = 0;
        args[argc + 1][strlen(display_number) - 1] = 0;
        for(int i = 0; i < argc + 2; ++i) {
                printf("%s\t%d\n", args[i], strlen(args[i]));
        }
        int aargc = argc + 2;
        QApplication app(aargc, args);
        QWidget w;
        w.show();
        return app.exec();
    }
    

    希望你明白了。在我的机器上试了一下,效果很好。

    谢谢。

    【讨论】:

    • 在给定的显示器上显示整个应用程序很容易。您也可以在命令行上执行 export DISPLAY=:2 。我们想要的是一种编程方式......例如,我们可以在单个应用程序中在 display:1 上显示一个窗口,在 display:2 上显示另一个窗口。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 2012-02-05
    • 1970-01-01
    • 2022-01-22
    • 2018-03-15
    • 2021-09-03
    • 2019-08-11
    相关资源
    最近更新 更多