Q_PROPERTY, qual sua real vantagem?
-
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: 100Text { 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.