首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何开发新的Qt 5.7+高-新闻部每监视器新闻部感知应用程序?

如何开发新的Qt 5.7+高-新闻部每监视器新闻部感知应用程序?
EN

Stack Overflow用户
提问于 2016-10-03 02:42:58
回答 1查看 5.7K关注 0票数 15

我读过官方的Qt文档和许多关于StackOverflow的文章和问题,都是关于Qt中新闻部的支持。所有这些程序都专注于移植旧应用程序,并使它们尽可能少地进行更改。

但是,如果我要启动一个全新的应用程序,并打算支持每个监视器的DPI感知应用程序,那么最好的方法是什么?

如果我正确理解的话,Qt::AA_EnableHighDpiScaling与我想要的完全相反。我实际上应该禁用HighDpiScaling并在运行时手动计算所有维度?

许多建议说,不要使用大小,使用浮动布局。但在许多情况下,希望至少存在最小宽度和/或最小高度。由于Qt设计器只允许我将值放在绝对像素中,那么正确的方法是什么?如果监视器分辨率发生变化,我应该将代码放在哪里重新计算维度?

还是我应该用自动缩放的方法?

我以前的Qt应用程序的解决方案(测试不太好)

在我的一个老应用程序中,我尝试添加HighDPI支持,我使用了这种方法-列出DOM的所有子程序,并按一定比例逐个调整它们的大小。Ratio =1将产生与我在dimensions中指定的维度相等的维度。

代码语言:javascript
代码运行次数:0
运行
复制
    void resizeWidgets(MyApp & qw, qreal mratio)
    {

        // ratio to calculate correct sizing
        qreal mratio_bak = mratio;

        if(MyApp::m_ratio != 0)
            mratio /= MyApp::m_ratio;

        // this all was done so that if its called 2 times with ratio = 2, total is not 4 but still just 2 (ratio is absolute)
        MyApp::m_ratio = mratio_bak;

        QLayout * ql = qw.layout();

        if (ql == NULL)
            return;

        QWidget * pw = ql->parentWidget();

        if (pw == NULL)
            return;

        QList<QLayout *> layouts;

        foreach(QWidget *w, pw->findChildren<QWidget*>())
        {
            QRect g = w->geometry();

            w->setMinimumSize(w->minimumWidth() * mratio, w->minimumHeight() * mratio);
            w->setMaximumSize(w->maximumWidth() * mratio, w->maximumHeight() * mratio);

            w->resize(w->width() * mratio, w->height() * mratio);
            w->move(QPoint(g.x() * mratio, g.y() * mratio));
            
        }

        foreach(QLayout *l, pw->findChildren<QLayout*>())
        {
            if(l != NULL && !(l->objectName().isEmpty()))
                layouts.append(l);
        }
        
        foreach(QLayout *l, layouts) {
            QMargins m = l->contentsMargins();

            m.setBottom(m.bottom() * mratio);
            m.setTop(m.top() * mratio);
            m.setLeft(m.left() * mratio);
            m.setRight(m.right() * mratio);

            l->setContentsMargins(m);

            l->setSpacing(l->spacing() * mratio);

            if (l->inherits("QGridLayout")) {
                QGridLayout* gl = ((QGridLayout*)l);

                gl->setHorizontalSpacing(gl->horizontalSpacing() * mratio);
                gl->setVerticalSpacing(gl->verticalSpacing() * mratio);
            }

        }
        
        QMargins m = qw.contentsMargins();

        m.setBottom(m.bottom() * mratio);
        m.setTop(m.top() * mratio);
        m.setLeft(m.left() * mratio);
        m.setRight(m.right() * mratio);

        // resize accordingly main window
        qw.resize(qw.width() * mratio, qw.height() * mratio);
        qw.setContentsMargins(m);
        qw.adjustSize();
    }

从main调用:

代码语言:javascript
代码运行次数:0
运行
复制
int main(int argc, char *argv[])
{

    QApplication a(argc, argv);
    MyApp w;

    // gets DPI
    qreal dpi = a.primaryScreen()->logicalDotsPerInch();

    MyApp::resizeWidgets(w, dpi / MyApp::refDpi);

    w.show();

    return a.exec();
}

我不认为这是个好办法。考虑到我正在重新开始,并且我可以根据最新的Qt标准完全定制我的代码,我应该使用什么方法来获取HighDPI应用程序呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-03 04:00:28

如果我要启动一个全新的应用程序,目的是支持每一个监测新闻部的意识,什么是最好的方法?

我们不依赖于Qt来自动调整每个监视器的DPI感知模式。至少QT5.7-与Qt::AA_EnableHighDpiScaling集的应用程序不这样做,‘高新闻部缩放’是更准确的绘图,无论像素密度。

要调用每个监视器DPI感知模式,您需要在项目可执行文件所在的同一个目录中修改Qt.conf文件:

代码语言:javascript
代码运行次数:0
运行
复制
[Platforms]
# 1 - for System DPI Aware
# 2 - for Per Monitor DPI Aware
WindowsArguments = dpiawareness=2

# May need to define this section as well
#[Paths]
#Prefix=.

如果我正确理解的话,Qt::AA_EnableHighDpiScaling与我想要的完全相反。我实际上应该禁用HighDpiScaling并在运行时手动计算所有维度?

不,这不是一回事,而是另一回事。有几个Qt错误被关闭为无bug:QTBUG-55449QTBUG-55510显示了该特性背后的意图。顺便说一句,QTBUG-55510提供了一种编程解决方法,用于设置Qt感知而不修复qt.conf (使用自行决定,因为它使用“私有”Qt实现类来更改接口,而无需任何更新的Qt版本通知)。

并且您表达了正确的方法来执行每个监视器DPI感知模式的缩放。不幸的是,当时没有太多的选择。但是,当窗口从一个监视器移动到另一个监视器时,有一些编程方法可以帮助对窗口进行事件处理。在这个问题的开头,像resizeWidget这样的方法(一个,不是很多)应该使用(Windows)这样的方法来调用:

代码语言:javascript
代码运行次数:0
运行
复制
// we assume MainWindow is the widget dragged from one monitor to another
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
   MSG* pMsg = reinterpret_cast<MSG*>(message);

   switch (pMsg->message)
   {
      case WM_DPICHANGED:
         // parameters TBD but mind that 'last' DPI is in
         // LOWORD(pMsg->wParam) and you need to detect current
         resizeWidget(monitorRatio());
         break;

这是相当困难和麻烦的方式,我求助于通过让用户选择该模式并重新启动应用进程(要么修复qt.conf,要么在应用程序开始时从QTBUG-55510中解决),使应用程序能够在System和process新闻部感知模式之间切换。我们的希望是Qt公司意识到,需要每个监视器新闻部感知模式,自动缩放的小部件。我们为什么需要它(?)是另一个问题。在我的例子中,我在自己的app小部件画布中有每个监视器呈现,应该是缩放的。

一开始,我从@selbie上读到对这个问题的评论,我意识到,在应用程序启动时,也许有一种方法可以尝试设置QT_SCREEN_SCALE_FACTORS:

QT_SCREEN_SCALE_FACTORS列表指定每个屏幕的缩放因子。这不会改变点大小字体的大小。此环境变量主要用于调试,或用于处理带有错误EDID信息的监视器(扩展显示标识数据)。

然后,我阅读了关于如何应用多个屏幕因素的Qt博客,并尝试对4K和1080 p监视器执行以下操作,其中首先列出4K (main)。

代码语言:javascript
代码运行次数:0
运行
复制
qputenv("QT_SCREEN_SCALE_FACTORS", "2;1");

这确实有点帮助:几乎正确的呈现,但是引入了窗口大小的缺陷,同时将窗口从一个监视器移动到另一个监视器,就像QTBUG-55449一样。我想,如果客户认为当前的应用程序行为是一个bug,我将使用WM_DPICHANGED + QT_SCREEN_SCALE_FACTORS方法(我们通过System为所有监视器建立了相同的基础)。但是还没有准备好使用Qt的解决方案。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39823918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档