Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QGuiApplication::primaryScreen() not telling me what I need to know



  • I'm using Qt 5.14.2 on Linux. I have two screens, my "laptop screen" and my "external monitor". My program wants to get information about the screen ("monitor") on which the window is actually displayed, because it wants to find out the (physical) DPI for that screen. The documentation says

    primaryScreen : QScreen* const

    This property holds the primary (or default) screen of the application.

    This will be the screen where QWindows are initially shown, unless otherwise specified.

    The primaryScreenChanged signal was introduced in Qt 5.6.

    Notwithstanding the above, it always returns the laptop screen, even when the window is initially opened on the external monitor or if I move it from the laptop to the external monitor and try that function again. And the two screens have different physical DPIs, so finding out about the laptop screen is only good sometimes.

    I have also tried
    QScreen * canvas_screen = QGuiApplication::screenAt(canvas_pos);
    but that also gives me the same thing as the laptop screen, even when the window is completely on the external monitor.

    I don't know whether there is a bug in the documentation, a bug in the implementation, or (more likely?) a misunderstanding of these functions on my part. But, in any case, is anyone able to enlighten me on way to find the physical DPI of the screen on which a particular window resides?

    Thanks



  • QList<QScreen *> QGuiApplication::screens() to find the list of screens and you will know which one is your external screen?
    compare with the pointer address of your primary screen: no==>external screen



  • How do you get canvas_pos?
    Are you sure it is the right global position?



  • @JoeCFD Joe, thanks for the answer. I'm not sure what you meant by your first sentence, given that it ends with a '?'. Iterating through the list of screens I see both screens; here is some output:
    There are 2 screens
    The next screen info:
    serial number //
    available size: wd 2880 * ht 1800
    logical DPI is 163.16
    physical DPI is 219.69
    The next screen info:
    serial number /20206/
    available size: wd 3840 * ht 2160
    logical DPI is 163.16
    physical DPI is 161.96
    But I am not sure what you are suggesting about looking at the pointer address of my primary screen. Can you clarify that a bit?



  • @Bonnie Here is the code I used to get canvas_pos. (And no, I'm not sure it is right. I'm certainly open to being corrected.)
    QWidget * wind = ui->canvas->window();
    QPoint canvas_pos = wind->pos();

    (Is that enough info to answer your question?)
    Thanks.



  • @zsd Your result may be not accurate, but should work if "the window is completely on the external monitor".
    How about these approaches?

    QPoint canvas_pos = ui->canvas->window()->mapToGlobal(QPoint(0, 0));
    QScreen * canvas_screen = QGuiApplication::screenAt(canvas_pos);
    
    QPoint canvas_pos = ui->canvas->mapToGlobal(QPoint(0, 0));
    QScreen * canvas_screen = QGuiApplication::screenAt(canvas_pos);
    
    if(QWindow * wind = ui->canvas->window()->windowHandle()) {
        QScreen * canvas_screen = wind->screen();
    }
    


  • @Bonnie ,
    thanks very much. I now see that there is another issue involved.

    I am looking for this information after the following code (in main()):
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    At that point (after calling w.show()) all three versions of your code are still returning the laptop screen information, even when the window opens completely on the external monitor.

    On the good side, all three give the correct screen if I call a function to print things out when a menu item is chosen (nothing magic about a menu item, it just seemed a quick way to test things out).

    So perhaps my question should be modified to the following:
    How can I get the correct screen information after w.show() but before I call
    a.exec()
    In other words (possibly!), how can I get Qt to really look and see which monitor the window is on before calling a.exec() ?

    Thanks to anyone who can provide enlightenment!


  • Lifetime Qt Champion

    Hi,

    Here is the trick: show has no effect until exec runs. The show method schedules an event to bring the widget to screen. Hence you might want to move some logic in the showEvent method.



  • @SGaist
    Thanks for the information. I had previously tried a sleep(5) after show() before exec() and a window (albeit empty) showed up on the monitor before exec() was called, and so I thought (ha!) that Qt would know which monitor it was on.

    I tried putting a showEvent() in my main window class and that was called when w.show() was called (and thus before a.exec()), so it still has the wrong answer.

    I've hunted around on the net, but I haven't found any enlightenment suitable for my level of Qt n00bness. Are you able to either elaborate a bit further or point me in the direction of a "how to use showEvent() at just the right place and just the right time for n00bs" document?

    Thanks.



  • This post is deleted!


  • @zsd In case anyone is still watching and interested, the problem persists in 5.15.0.
    If anyone has any more thoughts to share, I'd be happy to hear them.


  • Qt Champions 2019

    @zsd said in QGuiApplication::primaryScreen() not telling me what I need to know:

    In other words (possibly!), how can I get Qt to really look and see which monitor the window is on before calling a.exec() ?

    You can't since even Qt does not know this.



  • @Christian-Ehrlicher Thanks for the answer. I find this surprising, given that the w.show() causes an empty window frame to pop up on the monitor.

    However, I still need the info. The program could ask for it each and every time a user does something which needs the information, or the program could wait for such an event and cache the information, but are you able to recommend a Qt-approved way of doing something once when a.exec() is called?

    Thanks.


  • Qt Champions 2019

    @zsd said in QGuiApplication::primaryScreen() not telling me what I need to know:

    Qt-approved way of doing something once when a.exec() is called?

    Not sure what exactly your use case is, but what about QTimer?



  • @jsulm Hmmm... that might work, although it strikes me as a bit kludgy (no offense intended). My "use case" is explained in my original message. Is that insufficient in some way? I can supply more information, but I'm not sure what would be relevant.



  • @Christian-Ehrlicher By the way... given that a.show() causes the window manager to open a window on the display, can you explain why you say that Qt doesn't know whicih monitor its window in on before a.exec() is called?
    Thanks.


Log in to reply