6

既存の 2 つのウィジェットの動作を組み合わせた単一のウィジェットを作成したいと考えています。たとえば、チェックボックスも含むボタンであるウィジェットです。ユーザーは大きなボタンをクリックできますが、その中のチェックボックスもクリックできます。

たとえば、gmail では、クリックするとメニューが表示される「すべて選択」ボタンが導入されましたが、すべてのメールを選択するチェックボックスも統合されています。例については、次のスクリーンショットを参照してください。
ここに画像の説明を入力


既存のウィジェットの動作を組み合わせてこの効果を得るにはどうすればよいでしょうか? ウィジェットの動作を組み合わせることができ、競合する場所のみをオーバーライドする必要があるソリューションを望んでいます。

この質問は、qt で複数のウィジェットを 1 つに結合する質問に似ていますが、2 つのウィジェットを重ねて配置し、1 つのウィジェットとして表示するという点で異なります。

cbamber85 の返信に応えて、以下のコードを追加して、返信をどの程度統合できたかを示します。cbamber85 の返信と同様に、これには実際の機能は含まれておらず、彼のコードの PyQT バージョンにすぎません。

from PyQt4 import QtCore, QtGui

class CheckBoxButton(QtGui.QWidget):
    checked = QtCore.pyqtSignal(bool)

    def __init__(self, *args):
        QtGui.QWidget.__init__(self, *args)
        self._isdown = False
        self._ischecked = False

    def isChecked(self):
        return self._ischecked

    def setChecked(self, checked):
        if self._ischecked != checked:
            self._ischecked = checked
            self.checked.emit(checked)

    def sizeHint(self, *args, **kwargs):
        QtGui.QWidget.sizeHint(self, *args, **kwargs)
        return QtCore.QSize(128,128)

    def paintEvent(self, event):
        p = QtGui.QPainter(self)
        butOpt = QtGui.QStyleOptionButton()
        butOpt.initFrom(self)
        butOpt.state = QtGui.QStyle.State_Enabled
        butOpt.state |= QtGui.QStyle.State_Sunken if self._isdown else QtGui.QStyle.State_Raised

        self.style().drawControl(QtGui.QStyle.CE_PushButton, butOpt, p, self)

        chkBoxWidth = self.style().pixelMetric(QtGui.QStyle.PM_CheckListButtonSize,
                                               butOpt, self) / 2
        butOpt.rect.moveTo((self.rect().width() / 2) - chkBoxWidth, 0)

        butOpt.state |= QtGui.QStyle.State_On if self._ischecked else QtGui.QStyle.State_Off
        self.style().drawControl(QtGui.QStyle.CE_CheckBox, butOpt, p, self)

    def mousePressEvent(self, event):
        self._isdown = True
        self.update()

    def mouseReleaseEvent(self, event):
        self.setChecked(not self.isChecked())
        self._isdown = False
        self.update()


class Dialog(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        widg = CheckBoxButton(self)
        self.setCentralWidget(widg)


if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = Dialog()
    window.show()
    app.exec_()
4

2 に答える 2

5

はい、もちろんできますが、ウィジェットをどのように組み合わせるかによって、どれだけ簡単かが決まります。

たとえば、内側ではなく横にラベルを持つボタンを作成する場合は、 から派生させ、メンバーとしてandをQWidget追加し、コンストラクターでウィジェットの内部レイアウトに単純に追加します。(これを行うにはさまざまな方法があることを指摘しておく必要があります)。QLabelQPushButton

ただし、ビヘイビアーを新しい視覚的に異なるウィジェットに結合するウィジェットの場合、Qt にペイント方法を指示する必要があります。paintEvent(..)そのため、ウィジェットをサブクラス化し、手動でQPainter(this). また、ウィジェットを現在のスタイルに合わせるにQStyleは、コンポーネントの描画を行う必要があります。これにより、作業が大幅に楽になります。

次に、マウスの操作をオーバーライドして手動で処理する必要がありますmouse###Event(..)(キーボードの操作も必要になる場合があります)。

面倒ですが、ウィジェットが既存のウィジェットに近ければ近いほど、当然、作業は少なくなります。QToolButtonあなたの場合、すでにドロップダウンメニューをサポートしているため、私は派生します。次に、 を再実装paintEvent(..)し、呼び出しQStyle::drawControl(CE_PushButtonBevel, ...てボタンQStyle::drawControl(CE_CheckBox, ...を描画し、チェックボックスを正しい状態で描画します。次に、 を再実装mousePressEvent(..)し、チェックボックスのヒット領域内にあるかどうかを調べ、それに応じて状態を変更します。

ばかげた例

この無意味なウィジェットは、上記のテクニックのいくつかを示しています。

class WeirdCheckBoxButton : public QWidget
{
    Q_OBJECT

public:
    explicit WeirdCheckBoxButton( QWidget* parent = nullptr )
             : QWidget( parent ), checked_( false ), down_( false ) {}
    virtual ~WeirdCheckBoxButton() {}

    bool isChecked() const { return checked_; }
    QSize sizeHint () const { return QSize( 128, 128 ); }

public slots:
    virtual void setChecked( bool checked )
    {
        if ( checked_ != checked ) {
            checked_ = checked;
            emit clicked( checked );
        }
    }

signals:
    void clicked( bool checked );

protected:
    virtual void paintEvent( QPaintEvent* event )
    {
        Q_UNUSED( event )
        QPainter p( this );

        //  QStyleOption, and derived classes, describe the state of the widget.
        QStyleOptionButton butOpt;
        butOpt.initFrom( this ); // A convenience function that steals state
                                 // from this widget.
        butOpt.state = QStyle::State_Enabled;
        butOpt.state |= down_ ? QStyle::State_Sunken : QStyle::State_Raised;

        //  Renders the widget onto the QPainter.
        style()->drawControl( QStyle::CE_PushButton, &butOpt, &p, this );

        //  pixelMetric() gives you style relevant dimensional data.
        int chkBoxWidth = style()->pixelMetric( QStyle::PM_CheckListButtonSize,
                                                &butOpt, this ) / 2;
        butOpt.rect.moveTo( ( rect().width() / 2 ) - chkBoxWidth, 0 );
        butOpt.state |= checked_ ? QStyle::State_On : QStyle::State_Off;
        style()->drawControl( QStyle::CE_CheckBox, &butOpt, &p, this );
    }

    virtual void mousePressEvent( QMouseEvent* event )
    {
        Q_UNUSED( event )

        down_ = true;
        update();
    }

    virtual void mouseReleaseEvent( QMouseEvent* event )
    {
        Q_UNUSED( event )

        setChecked( !isChecked() );
        down_ = false;
        update();
    }

private:
    bool checked_;
    bool down_;
};

これは薄い例ですが、コピーして実験するには機が熟しています。たとえば、 にアクセスするbutOpt.paletteと、レンダリングされたウィジェットの色を状態に応じて微調整できます。

于 2012-08-08T12:24:28.760 に答える
0

はい、可能です。QtDesigner で、すべての機能と追加ウィジェットの相互作用をすべて備えた個別のウィジェットを構築できます。また、バックエンド (Python や C++ など) のコードを記述して、複雑な対話性を処理することもできます。すべてを終えたら。QtDesignerPluginWidget としてパックできます。QtDesigner のウィジェット リスト ボックスで利用できるもの。これをドラッグ アンド ドロップして、メイン アプリケーションを構築できます。

チェック: http://doc.qt.nokia.com/qq/qq26-pyqtdesigner.html (C++ ベース) http://diotavelli.net/PyQtWiki/Using_Python_Custom_Widgets_in_Qt_Designer (Python ベース)

于 2012-08-08T12:07:50.127 に答える