Разоблачение дочерних свойств в родительском

Я хочу создать собственный виджет, содержащий QSpinBox. Я хочу, чтобы пользовательский виджет предоставлял некоторые свойства QSpinBox как свои собственные, чтобы он мог удобно работать в Designer.

Есть ли удобный способ сделать такое проксирование свойств в Qt?

Я хочу еще раз повторить, что связь между моим пользовательским виджетом и QSpinBox — это включение, а не наследование. Я использую pyqt, но с радостью приму чистый ответ qt.

Чтобы уточнить, я хочу создать варианты стандартных виджетов, которые имеют некоторые дополнительные украшения. Например, я добавлю переключаемый значок рядом с моим QSpinBox. Однако я все еще хочу иметь возможность настраивать QSpinBox в дизайнере (т. е. устанавливать суффикс, верхний и нижний пределы, приращение и т. д.).


person goertzenator    schedule 29.08.2011    source источник


Ответы (3)


Алрите, вот способ сделать это.

Это лучше, чем писать функцию вручную для каждого свойства. По сути, вы пишете макрос, который расширяет код за вас. У меня есть doubleSpinBox в моем виджете, и его значение изменяется всякий раз, когда я меняю свойство. И вы излучаете сигнал всякий раз, когда изменяется свойство, которое связано с doubleSpinBox->setValue(). Проверено и работает отлично. Заполните код по этой ссылке. .

#ifndef MYWIDGET_H_
#define MYWIDGET_H_

#include <QtGui/QWidget>
#include <QtGui/QLabel>
#include "ui_mywidgetform.h"

#define MYPROPERTY_SET_FUNC(_PROPCLASS_, _PROP_PARAM_NAME_, _PROP_SET_FUNC_NAME_, _PROP_NOTIFY_) \
  void _PROP_SET_FUNC_NAME_(_PROPCLASS_ _PROP_PARAM_NAME_) \
  { \
    emit _PROP_NOTIFY_(_PROP_PARAM_NAME_); \
  }

#define MYPROPERTY_GET_FUNC(_PROPCLASS_, _PROP_READ_FUNC_NAME_, _PROP_VARIABLE_)\
  _PROPCLASS_ _PROP_READ_FUNC_NAME_() const  \
  { return _PROP_VARIABLE_; }

class MyWidget : public QWidget
{
  Q_OBJECT

public:
  MyWidget(QWidget *parent = 0);
  ~MyWidget();
  enum Accuracy {Good, Bad};

signals:
  void doubleSpinBoxValueChanged(double);
  void accuracyChanged(Accuracy);

private:
    Q_PROPERTY(Accuracy accuracy READ accuracy WRITE setAccuracy NOTIFY accuracyChanged)
    Q_PROPERTY(double doubleSpinBoxValue READ doubleSpinBoxValue WRITE setDoubleSpinBoxValue)

private:
  Accuracy m_accuracy;  //custom class property
  Ui::Form m_ui;

public:
  //Getter functions
  MYPROPERTY_GET_FUNC (double, doubleSpinBoxValue, m_ui.doubleSpinBox->value())
  MYPROPERTY_GET_FUNC (Accuracy, accuracy, m_accuracy)
  //Setter functions
  MYPROPERTY_SET_FUNC(Accuracy, accuracy, setAccuracy, accuracyChanged)
  MYPROPERTY_SET_FUNC(double, doubleSpinBoxValue, setDoubleSpinBoxValue, doubleSpinBoxValueChanged)

};

#endif // MYWIDGET_H_
person blueskin    schedule 29.08.2011

Вот версия PyQt, вдохновленная blueskin. Основное операционное отличие состоит в том, что пользовательский класс виджета создается во время выполнения, а не во время компиляции. Преимущество этого заключается в том, что мы можем программно проверять целевой метаобъект и использовать его для создания свойств прокси.

Теперь PyQt скомпилирован из C++, поэтому я должен верить, что также возможно генерировать типы qt во время выполнения в C++. Держу пари, что это было бы адски, однако.

from PyQt4 import QtGui, QtCore

def makeProxyProperty(childname, childtype, childpropname):

    metaobject = childtype.staticMetaObject
    metaproperty = metaobject.property(metaobject.indexOfProperty(childpropname))

    def getter(self):
        return metaproperty.read(getattr(self, childname))

    def setter(self, val):
        return metaproperty.write(getattr(self, childname), val)

    return QtCore.pyqtProperty(metaproperty.typeName(), fget=getter, fset=setter)


class Widget1(QtGui.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.spinbox = QtGui.QSpinBox()
        self.checkbox = QtGui.QCheckBox()
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.checkbox)
        layout.addWidget(self.spinbox)
        self.setLayout(layout)

    spinbox_suffix  = makeProxyProperty("spinbox", QtGui.QSpinBox, "suffix")
    spinbox_prefix  = makeProxyProperty("spinbox", QtGui.QSpinBox, "prefix")
    spinbox_minimum = makeProxyProperty("spinbox", QtGui.QSpinBox, "minimum")
    spinbox_maximum = makeProxyProperty("spinbox", QtGui.QSpinBox, "maximum")

Виджет1 в дизайнере

person goertzenator    schedule 30.08.2011
comment
хорошо, я думаю, PyQt даст больше гибкости во время выполнения. Я почти не использовал его. - person blueskin; 30.08.2011

Итак, чтобы немного прояснить ситуацию,

  1. вы будете использовать этот пользовательский виджет в дизайнере.
  2. Вам нужно, чтобы пользовательский виджет имел свойства, которые отображают свойства QSpinBox в качестве свойств виджета.

So,

в основном вы хотели бы создать свойство в своем пользовательском виджете, используя «Q_PROPERTY», и использовать методы установки и получения для изменения свойств QSpinBox. Я надеюсь, что этот пример поможет http://doc.qt.nokia.com/last/properties.html#a-simple-example

person blueskin    schedule 29.08.2011
comment
Я ищу что-то более автоматизированное. Я буду создавать пользовательские виджеты, которые охватывают многие из основных типов виджетов, и каждый из них будет иметь множество свойств для прокси. Проксирование каждого свойства вручную было бы подвержено ошибкам и трудоемко. - person goertzenator; 29.08.2011
comment
хорошо .. чтобы понять, почему вы хотите, чтобы свойства вспомогательных виджетов были свойством основного виджета? Если у вас уже есть пользовательский виджет в виде плагина Qt-Designer, вы должны иметь возможность устанавливать/получать свойства всех подвиджетов. - person blueskin; 29.08.2011
comment
У меня работает собственный виджет (производный от QWidget), который содержит QCheckBox и QSpinBox. В Designer я не вижу возможности редактировать свойства подвиджетов. - person goertzenator; 29.08.2011
comment
@goertzenator:: мой плохой. Я думал, что мы могли бы сделать это. Ну, тогда я не знаю другого пути. - person blueskin; 30.08.2011