Q_PROPERTY, qual sua real vantagem?



  • Durante uma pesquisa para descobrir se Qt disponibiliza algum recurso para o clichê get e set, descobri a macro Q_PROPERTY. Li parte da documentação (confesso que não li tudo) e não entendi qual é a vantagem proposta, visto que ainda se tem que escrever os métodos gets e sets. Eu esperava algo que poupasse o trabalho como os recursos do C# e Python.
    Não entendi o que Q_PROPERTY se propõe a fazer. Meta objeto é um recurso do Qt que ainda não entendo bem como funciona.



  • bq. Não entendi o que Q_PROPERTY se propõe a fazer

    De acordo com o meu entendimento, Q_PROPERTY é a solução que os engenheiros do Qt criaram para resolver alguns dos seus próprios problemas como por exemplo editar widgets no Qt-Designer.

    Se você não está interessado em criar plugins para o Qt-Designer e nem usando o QtScript eu vejo só dois motivos para usar Q_PROPERTY:

    • a possibilidade de se atribuir o valor de uma Q_PROPERTY usando um style sheet
    • a possibilidade de criar um style sheet que considera o valor das propriedades do widget.

    H.



  • Então para uma simples classe 'Pessoa' e seus atributos (ex. nome, sobrenome, sexo) Q_PROPERTY não é a solução?



  • O Q_PROPERTY cria a idéia de propriedade, semelhantemente como existe em outras linguagens anotadas como C#/Python/Java.

    Em C#, se você cria uma classe assim:
    @
    public class Test
    {
    public String Nome { get; set; }
    public String Telefone { get; set; }
    }
    @

    Nome e Telefone são propriedades.

    Se escrever assim:

    @
    public class Test
    {
    public String Nome;
    public String Telefone;
    }
    @

    São membros públicos

    São a mesma coisa? Não.

    Por exemplo: No C#, por que preciso criar uma propriedade em vez de um membro? Membros não são serializados automaticamente, e propriedades sim. Além disso, membros públicos podem ser acessados. Numa propriedade, você pode restringir o acesso, tornando a mesma "read-only".

    O Q_PROPERTY faz a mesma coisa: dar o sentido de propriedade à classe (e não simplesmente um membro). E anota a classe

    É usado, por exemplo, quando você escreve um objeto em C++ e usa ele no QML.



  • Entendi, só não consigo ver qual o beneficio em fazer uso do Q_PROPERTY ou optar por criar uma classe C++ simples. Exemplo:

    @ class Pessoa {
    public:
    QString getNome();
    int getIdade();
    QChar getSexo();
    void setName(QString nome);
    void setIdade(int idade);
    void setSexo(QChar sexo);
    private:
    QString nome;
    int idade;
    QChar sexo;
    };
    @

    A única ocasião que me vem à mente onde Q_PROPERTY seria necessário é caso fosse necessário acompanhar em tempo de execução as mudanças nas propriedades do objeto, para disparar um evento qualquer por exemplo.
    Mas como trata-se unicamente de um objeto de transferência (DTO) para persistência, não vejo necessidade.



  • Suponhamos que você crie um novo widget que desenha um círculo, assim:

    @class Circulo : public QWidget
    {
    Q_OBJECT
    public:
    explicit Circulo(QWidget *parent = 0);

    // propriedade "raio"
    double raio() const;            // get
    void setRaio(double raio);      // set
    
    // propriedade "cor"
    QColor cor() const;             // get
    void setCor(const QColor &cor); // set
    
    // função responsável por desenhar o widget
    virtual void paintEvent(QPaintEvent *event);
    

    private:
    double m_raio;
    QColor m_cor;
    }@

    Agora suponhamos que você deseja arrastar e soltar esse widget no Qt Designer (ou no modo "Design" do Qt Creator), assim como você faria com qualquer outro widget. Como o Qt Designer vai conseguir te mostrar todas as propriedades que você pode editar (raio e cor)? Quando você arrasta um "Push Button" e solta ele na sua janela, você vê a propriedade "text" na lista de propriedades que fica no canto inferior-direito porque essa propriedade foi marcada com Q_PROPERTY, sem isso não tem como o Qt Designer adivinhar quais funções são os getters e setters dos diversos membros privados.

    Outro benefício do Q_PROPERTY é no QML. Suponha o seguinte código em QML.

    @import QtQuick 2.0

    Rectangle {
    id: retangulo
    width: 100
    height: 100

    Text {
        id: texto
        text: retangulo.width
    }
    

    }@

    Nesse caso, toda vez que a largura do retangulo mudar, o texto será atualizado para mostrar a nova largura do retangulo. Como o Qt saberá que a largura mudou? Porque a propriedade "width" foi marcado com Q_PROPERTY, assim:

    Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged RESET resetWidth FINAL)

    Na verdade, a linha de código acima faz parte do QQuickItem, mas Rectangle é um tipo de QQuickItem. Enfim, veja que nessa linha de código o NOTIFY indica qual signal é emitido quando a propriedade "width" mudar. Assim, sempre que a largura do retangulo mudar (ou seja, quando o signal dado for emitido), o Qt reavaliará todas as expressões que dependem da largura. No exemplo acima, o Qt é capaz de atualizar o texto para a nova largura do retangulo assim que a largura mudar, e sim, isso ocorre em tempo real.

    Esses são alguns dos benefícios do Q_PROPERTY, devem haver outros. Se você não precisa de integrar seu widget no Qt Designer ou se você não quiser fazer um tipo de item em QML, então usando Q_PROPERTY não faria mal mas provavelmente seria desnecessário. Para uma simples classe que guarda alguns dados em uma aplicação realmente não vejo necessidade de usar Q_PROPERTY.



  • Grato pela resposta daniel era o que eu queria saber.
    Quando resolvi procurar por este assunto, na verdade eu buscava algo referente a sintaxe, como no caso do C# citado pelo TioRoy. Eu buscava por saber se Qt implementava alguma solução para evitar as várias linha de código com get e set, imagine um classe com 10 atributos... dói só de pensar.



  • É, C++ não oferece um recurso para propriedades diretamente como o C#, mas o Qt Creator tem uma opção para implementar uma propriedade automaticamente. Por exemplo, digite o seguinte na sua classe:

    @Q_PROPERTY(int exemplo READ exemplo WRITE setExemplo)@

    e depois, com o cursor em cima do Q_PROPERTY, pressione Alt+Enter, aparecerá um menu, agora pressione Enter novamente. O Qt Creator então criará um membro privado e funções para get e set que fazem uso do membro privado. Depois de criado esse membro privado e essas funções get e set, você pode remover o Q_PROPERTY da sua classe mas não tem necessidade. Outra forma de fazer isso é clicar com o botão direito no Q_PROPERTY e dentro do submenu 'Refactoring' você clica em 'Generate Missing Q_PROPERTY Members...'.

    Quando o Qt Creator cria código para propriedades desse jeito, ele sempre dá o nome 'arg' para o argumento da função que faz o set, então talvez você queira ajustar isso para que seu código fique mais elegante. Talvez você queira acrescentar uma lógica mais sofisticada para as funções get e set, depende do que você precisa, mas essa é uma forma rápida e fácil de criar propriedades básicas.



  • O objetivo maior do Q_PROPERTY é prover um mecanismo de reflexão, de tal forma que se consiga conhecer a estrutura interna de um objeto qualquer em tempo de execução.

    Quando utilizamos a macro Q_PROPERTY em conjunto com Q_OBJECT, construímos a implementação do método metaObject(), que cria um objeto que permite por exemplo a listagem das propriedades presentes naquele objeto, bem como a utilização de mecanismos para acessar e alterar estas propriedades. Existem outros mecanismos de reflexão voltados para a listagem e chamada de métodos também.

    Porém para utilizar este mecanismo de propriedades, sua classe deve herdar de QObject, o que torna impossível o objeto ser passado como cópia para métodos devido a restrições impostas pela própria implementação de QObject.

    Dê uma olhada em:
    http://qt-project.org/doc/qt-5/metaobjects.html#meta-object-system
    http://qt-project.org/doc/qt-5/properties.html



  • Outra coisa que esqueci de falar, o QtCreator tem um atalho para criar métodos get e set. Crie uma variável dentro de uma seção private, coloque o cursor de edição em cima do nome da variável e pressione alt+enter. Dentre as opções que aparecem, aparece uma para criar os gets e sets.



  • Bom,
    eu estava utilizando o Q_PROPERTY e escrevia os gets e sets todos na mão como ele falou e ainda fazia a verificação para evitar o "binding loop", mas depois de um tempo eu percebi que não era necessário, era preciso apenas duas funções Q_INVOKABLE uma para ler e outra para escrever passando o nome do QSqlField, uma vez que um QSqlField guarda um valor QVariant a função de leitura retorna um QVariant para o campo na interface QML, e quando atualiza o valor no QSqlRecord envia um QVariant e tudo ficou muito mais simples e mais rápido. Foi possível excluir vários arquivos fontes apenas com gets e sets, criei apenas um RecordBase herdando QSqlRecord criei o set e o get, e um ModelBase que conecta com banco e lê os campos e os tipos de dados de cada Tabela, e ao selecionar a tabela para cada registro no banco é criado um RecordBase com os tipos corretos que o modelo fornece, fazer a ligação com os campos da interface QML é muito fácil.
    É uma ideia alternativa para o Q_PROPERTY que você pode implementar.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.