Fazendo apenas uma coluna de um QTreeWidgetItem editável
-
25-09-2019 - |
Pergunta
Eu tenho um QTreeWidgetItem
com duas colunas de dados, existe alguma maneira de fazer somente a segunda coluna editável?Quando eu faço o seguinte:
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setFlags(item->flags() | Qt::ItemIsEditable);
todas as colunas tornar editável.
Solução
Parece que você terá que renunciar ao uso QTreeWidget
e QTreeWidgetItem
e vá com QTreeView
e QAbstractItemModel
. As classes "widgets" são classes de conveniência que são implementações concretas das versões mais abstratas, mas mais flexíveis. QAbstractItemModel
tem uma ligação flags(QModelIndex index)
onde você retornaria o valor apropriado para sua coluna.
Outras dicas
Você pode fazer apenas algumas colunas em uma QTreeWidget editável utilizando uma solução:
1) Definir o editTriggers propriedade do QTreeWidget para NoEditTriggers
2) Na inserção de itens, definir o Qt:ItemIsEditable bandeira do QTreeWidgetItem objeto
3) Conectar o seguinte slot para o "itemDoubleClicked" sinal da QTreeWidget objeto:
void MainWindow::onTreeWidgetItemDoubleClicked(QTreeWidgetItem * item, int column)
{
if (isEditable(column)) {
ui.treeWidget->editItem(item, column);
}
}
onde "isEditable" é uma função que você escreveu que retorna true para colunas editáveis e false para não-colunas editáveis.
Recentemente, tive o mesmo problema e descobri uma solução que funciona com todos os edittiggers, não apenas o DoubleClicked One (e a conexão com o sinal de clique duas vezes)
Crie um delegado, que retorne um ponteiro nulo para o editor:
class NoEditDelegate: public QStyledItemDelegate {
public:
NoEditDelegate(QObject* parent=0): QStyledItemDelegate(parent) {}
virtual QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
return 0;
}
};
E use -o mais tarde como um delegado personalizado para sua coluna
ui->parameterView->setItemDelegateForColumn(0, new NoEditDelegate(this));
Parece que o QtreeWidget padrão não permite isso. Eu acho que existem duas maneiras de fazer isso:
Use um QtreeView com sua própria classe derivada de QabstractItemModel e substitua a função Sinalizador
Use um QtreeView com um qStandardiTemmodel. Então, quando você adiciona o item, basta definir a coluna apropriada para permitir edições:
Aqui está algum código para a segunda opção:
QString x, y;
QList<QStandardItem*> newIt;
QStandardItem * item = new QStandardItem(x);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
newIt.append(item);
item = new QStandardItem(y);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsEditable);
newIt.append(item);
model->appendRow(newIt);
Acho a segunda abordagem mais simples, mas isso depende de quanta flexibilidade você deseja com seu modelo.
A maneira mais simples que eu encontrei foi usar qt :: itemflags
void myClass::treeDoubleClickSlot(QTreeWidgetItem *item, int column)
{
Qt::ItemFlags tmp = item->flags();
if (isEditable(item, column)) {
item->setFlags(tmp | Qt::ItemIsEditable);
} else if (tmp & Qt::ItemIsEditable) {
item->setFlags(tmp ^ Qt::ItemIsEditable);
}
}
O topo do if
adiciona a funcionalidade de edição através de um OR
, e o fundo verifica se está lá com AND
, então remove com um XOR
.
Dessa forma, a funcionalidade de edição é adicionada quando você deseja e removida quando não o fizer.
Em seguida, conecte esta função ao widget da árvore itemDoubleClicked()
sinalize e escreva o seu 'para editar ou não editar' a decisão dentro de isEditable()
class EditorDelegate : public QItemDelegate
{
Q_OBJECT
public:
EditorDelegate(QObject *parent):QItemDelegate(parent){};
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
QWidget* EditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 1)
{
return QItemDelegate::createEditor(parent, option, index);
}
return nullptr;
}
No QTreeWidget
:
myQTreeWidget::myQTreeWidget()
{
EditorDelegate *d = new EditorDelegate(this);
this->setItemDelegate(d);
}
Talvez um pouco tarde, mas possa ajudar:
void MyClass::on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column) {
Qt::ItemFlags flags = item->flags();
if(column == 0)
{
item->setFlags(flags & (~Qt::ItemIsEditable));
}
else
{
item->setFlags(flags | Qt::ItemIsEditable);
}
}
Aqui 0 está o índice da coluna que você deseja fazer readonly.
flags & (~Qt::ItemIsEditable)
Define a posição iticemedável para 0, independentemente do sinalizador anterior do seu item.
flags | Qt::ItemIsEditable
Define -o para 1 independentemente da bandeira anterior.
Eu sou novo no Pyside e Python em geral, mas consegui fazer isso funcionar registrando -se no Qtreewidget para o ItemClicked Retorpors. Dentro do retorno de chamada, verifique a coluna e ligue apenas para 'EditItem' se for para uma coluna que você deseja permitir a edição.
class Foo(QtGui.QMainWindow):
...
def itemClicked(self, item, column):
if column > 0:
self.qtree.editItem(item, column)
Ao não invocar o EditItem para a coluna 0, o evento é basicamente descartado.
Descobri que o código abaixo funciona bem para minhas necessidades e "meio" impede o usuário de editar certas partes das colunas:
Eu basicamente verifico a função e depois a coluna. Eu só permito editar na coluna 0. Portanto, se o usuário editá -lo em qualquer outra coluna, paro a edição do setData e nenhuma alteração estiver sendo feita.
void treeItemSubclassed::setData(int column, int role, const QVariant &value) {
if (role == Qt::ItemIsEditable && column != 0){
return;
}
QTreeWidgetItem::setData(column, role, value);
}
Defina o filho da árvore-widget editável ou não (itmes de árvore), com base na linha e na coluna.