4

アプリケーションを MFC から Qt に移行しています。

MFC アプリは、GDI 呼び出しを使用してウィンドウ (基本的にはグラフ プロット) を構築します。メモリ ビットマップ バック バッファーに描画し、それを BitBlt して画面に描画します。ただし、Qt はすでにダブル バッファリングを行っています。

ユーザーがグラフをクリックしてドラッグすると、ウィンドウのそのセクションが反転するようにしたいと思います。

これを行うための最良の方法を見つけたいと思います。画面ではなく、ウィジェットのバック バッファから取得するgrabWindow()のようなことを行う方法はありますか? ...多分 BitBlt(..., DST_INVERT) と同等ですか?

QPainter で setCompositionMode() を見ましたが、QImage で動作するペインターでのみ機能するとドキュメントに記載されています。(それ以外の場合は、反転効果のようなものを得るために派手な構成モードでウィジェットに塗りつぶされた長方形の画像を合成することができます)

QImage バック バッファにペイントする MFC と同じことを実行できますが、この方法ではハードウェア アクセラレーションが機能しない可能性があることを読みました。Qt で既に提供されているダブル バッファリングを再実装するのはもったいないようです。また、ウィジェットのダブル バッファリングをオフにした場合の副作用についてもよくわかりません (トリプル バッファリングを避けるため)。

ある時点で、それを保護する再帰防止フラグを使用した複雑な QPixmap::grabWidget() 呼び出しがありましたが、それはすべてを 2 回レンダリングし、QImage に描画するよりも明らかに悪いです。(そして、それは特にドキュメントで警告されています)

基本的にMFCで行ったように、あきらめてすべてをQImageに描画する必要がありますか?

編集:

さて、QPixmap ペインタは現在のダイレクトとほぼ同じ速度で実行されます。そのため、QPixmap バックバッファーを使用することがこれを行うための最良の方法のようです。

解決策は私には明らかではありませんでしたが、おそらくもっと多くの例 (Ariya の Monster デモなど) を見れば、予想どおりにコーディングしただけで、問題なく動作したはずです。

これが違いです。これを使用したヘルプ システムのデモを見ました。

    QPainter painter(this)

paintEvent() の先頭。したがって、QPixmap へのダブル バッファリングを行ってから画面にペイントするには、次のようにする必要があることに自然に従うように思われました。

    QPainter painter(&pixmap);
    QPainter painterWidget(this);
    ...  draw using 'painter' ...
    painterWidget.drawPixmap(QPoint(0,0), pixmap);

実際、明らかにこれを行うことになっている場合:

    QPainter painter;
    painter.begin(&pixmap);
    ... draw using 'painter' ...
    painter.end();
    painter.begin(this);
    painter.drawPixmap(QPoint(0,0), pixmap);
    painter.end();

私のやり方には、同時に 2 人のアクティブなペインターがいたことがわかります。なぜ速いのかは完全にはわかりませんが、直感的には後者の方が好きです。これは単一の QPainter オブジェクトであり、一度に 1 つのことしか行いません。誰かが最初の方法が悪い理由を説明できるでしょうか? (Qt レンダリング エンジンの壊れた仮定に関して)

4

3 に答える 3

4

グラフ領域の上に描画すると、合成モードを使用して反転できるはずです。差分合成モードを使用して白を描画します。次の例は、ピックスマップを表示する QLabel のサブクラスです。

void Widget::paintEvent(QPaintEvent *pe)
{
    // make sure we paint background
    QLabel::paintEvent(pe);

    // paint the overlay
    if (!selectionRect.isNull()) {
        QPainter p(this);
        p.setCompositionMode(QPainter::CompositionMode_Difference);
        p.fillRect(selectionRect,QColor("#FFFFFF"));
    }
}

代替テキスト http://chaos.troll.no/~hhartz/yesManInverted.png

于 2009-05-22T13:02:54.200 に答える
4

オフスクリーン バッファからピクセル値を実際に取得したくない場合 (むしろ、その上に何かを再度描画して画面に再度ブリットするだけ)、バッファとして QImage ではなく QPixmap を使用する必要があります。後者を使用すると、Qt がソフトウェア ラスター エンジンを使用してフォールバックするため、すべてのペイント アクセラレーションが無効になるため、QPixmap を使用します。OpenGL グラフィック システムを使用している場合でも、その恩恵を受けることができます。

これを行う方法の例については、Monster demo を実行している私の最後のコードを確認してください。コンポジション モードでソースを使用して繰り返しペイントすることでモーション ブラー効果が発生するため、オフスクリーン ピックスマップが必要です。

Qt のバッキング ストアを無効にするには (一般的には良い考えではありません)、トップレベル ウィジェットにQt::WA_PaintOnScreenを使用します。

少し関係ありませんが、 QRubberBandウィジェットを見てみたいと思うかもしれません。

于 2009-05-22T11:37:16.337 に答える
0

私が知っている単純で最も簡単な答えは、以前と同じように QImage に対して行い、QImage を画面上のウィジェットのソースとして使用することです。

もう 1 つのオプションは、グラフの反転部分のみを描画する透明なウィジェットをグラフに追加することです。ただし、これで描画が最適化されるとはまったく思いません。基になるグラフが描画され、反転部分がオーバーレイされる可能性があります。

于 2009-05-21T17:39:18.457 に答える