2016-10-03 5 views
11

Qtの高DPIサポートについては、Qt documentationの公式と多くの記事や質問をStackOverflowで読んでいます。それらのすべては、古いアプリケーションを移植し、できるだけ変更を少なくして動作させることに重点を置いています。新しいQt 5.7+ High-DPI Per Monitor DPI対応アプリケーションの開発にアプローチする方法は?

しかし、新しいアプリケーションを開始する場合は、モニタごとのDPI対応アプリケーションをサポートするという意図で、最良のアプローチは何ですか?

私が正しく理解していれば、Qt::AA_EnableHighDpiScalingは私が欲しいものの正反対です。私は実際にHighDpiScalingを無効にし、実行時にすべての寸法を手動で計算する必要がありますか?

多くの提案は、フローティングレイアウトを使用するためにサイズをまったく使用しないと言っています。しかし、多くの場合、少なくとも最小幅および/または最小高さが存在することが望ましい。 Qt Designerでは、絶対ピクセルで値を入力することしかできませんが、正しいアプローチは何ですか?モニター解像度が変更された場合、ディメンションを再計算するためのコードはどこに置く必要がありますか?

また、自動スケーリングを使用するだけでいいですか?私はHighDPIサポートを追加しようとした私の古いアプリケーションの一つで、以前のQtアプリ(十分にテストされていない)

から

私のソリューションは、私はこのアプローチを使用 - DOMのすべての子を一覧表示し、それらに与えられた一つ一つのサイズを変更しますいくつかの比率。 Ratio = 1は、Qt Designerで指定した次元に等しい次元を生成します。私はこの良い解決策は考えていない

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(); 
} 

:メインから呼び出され

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(); 
    } 

。私は新鮮な状態から始めて、自分のコードを最新のQt標準に完全にカスタマイズすることができるので、HighDPIアプリケーションを入手するにはどうすればいいですか?

+0

Win32では、OS(GetDeviceCaps)にモニタのdpi設定を照会し、96.0で割って、env変数「QT_SCALE_FACTOR」を一致させるだけで成功しました。トレードオフがある。 Macでは、何もする必要はありませんでした。 YMMV。 – selbie

+0

@selbie、QT_SCALE_FACTORのモニタごとのスケーリングの設定方法は? – AlexanderVX

+0

多分、このQT_SCREEN_SCALE_FACTORS [list]は、各画面のスケール係数を指定します。これにより、ポイントサイズのフォントのサイズは変更されません。この環境変数は、主にデバッグや誤ったEDID情報(拡張ディスプレイ識別データ)を持つモニターを回避するのに便利です。しかし、誰かがアプリ内からそれを設定しようとする気になれば分かりませんか? – AlexanderVX

答えて

7

モニタごとのDPI認識をサポートするという意図で、新しいアプリケーションを開始する場合は、どのような方法が最適ですか?

私たちはモニタごとのDPI認識モードで自動スケーリングにQtを使用しません。 Qt::AA_EnableHighDpiScalingが設定されたQt 5.7ベースのアプリは、それを行わず、「高DPIスケーリング」はピクセル密度に関係なく正確な描画です。

そして、あなたはあなたが実行可能ファイルをプロジェクトと同じディレクトリにQt.confファイルを変更する必要があるごとモニターDPI対応モードを起動するには、次のとおりです。

[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バグはno-bugsとして閉じられています:QTBUG-55449QTBUG-55510は、機能の背後にある意図を示しています。ところで、QTBUG-55510固定のないQt DPI認識を設定するためのプログラム的な回避策があります(より新しいQtバージョンで通知することなくインターフェイスを変更する 'プライベート' Qt実装クラスを使用するため、独自の裁量で使用します)。

そして、モニターごとのDPI認識モードでスケーリングを行う正しい方法を示しました。残念ながら、当時はそれほど多くの選択肢はありません。しかし、あるモニターから別のモニターに移動するときにウィンドウスケーリングのイベント処理を支援するプログラム的な方法があります。 (Windowsの場合)のようなものを使用して呼び出されるべきこの質問の先頭にresizeWidgetのような方法(1、いない多くの):

// 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の回避策を実行する)ことで、システムとモニタごとのDPI対応モードを切り替えます。私たちの希望は、Qt社は、ウィジェットの自動スケーリング機能を備えたモニターごとのDPI認識モードが必要であることを認識しています。なぜそれが必要なのでしょうか(?)は別の質問です。私の場合は、スケールされるはずの自分のアプリウィジェットキャンバス内でモニターごとのレンダリングがあります。私は多分、アプリが起動している間QT_SCREEN_SCALE_FACTORSを設定しようとする方法があり実現@selbieからこの質問にコメントを読んでまず

、:

QT_SCREEN_SCALE_FACTORS [リスト]各 画面のスケールファクタを指定します。これにより、ポイントサイズのフォントのサイズは変更されません。この 環境変数は、主にデバッグや、間違ったEDID情報を持つ モニタ(拡張ディスプレイID データ)を回避するのに便利です。

次に、複数のスクリーン係数を適用する方法については、Qt blogを読んで、4Kが最初に(主に)リストされている4Kおよび1080pモニターに対して以下を実行しようとしました。

ビットを助けない
qputenv("QT_SCREEN_SCALE_FACTORS", "2;1"); 

:ほとんどレンダリングは正しいがQTBUG-55449のような他のほとんどに1人のモニターからウィンドウを移動させながら、ないウィンドウサイズで欠陥を導入しています。私はWM_DPICHANGED + QT_SCREEN_SCALE_FACTORSのアプローチをとっていると思います。顧客が現在のアプリケーションの動作をバグと見なす場合(私たちはすべてのモニタDPIをSystem DPI Aware経由で同じベースにしています)。まだQtのソリューションを使用する準備ができていません。

+0

お返事ありがとうございます。 Androidプログラミングのような簡単なhighdpiソリューションのサポートの欠如は私を狂わせる。 resizeWidgets関数に何かを追加する必要がありますか?あなたはQt highdpi機能を備えたopensourceデモアプリケーションを知っていますか? thx –

+0

@TomášNavaraまだオープンソースソリューションを知らない。私はその方法を試してみることは、あまりにも多くの日常的なスケーリングを行うための鉱山の分野です。既にプログラムで実行する必要があることの理解が示されていますが、WindowsではWM_DPICHANGED、MAYBEの設定を使用できます。QT_SCREEN_SCALE_FACTORS [list]は、アプリケーションの起動時に既に接続されているモニタに対して機能します。私はそのためにいくつかのステートメントを追加しました。 – AlexanderVX

+0

だから明確にする - dpichangeイベントを受け取ったときにコード内からすべての作業を自分自身で行うと、dpiawareness = 2を指定するとどのような利点がありますか?そして、Linuxはどうですか? –

関連する問題