QTreeWidget 捕获项目编辑完成,没有文本更改
QTreeWidget catch item editing finished with no text change
我正在 Qt Designer 窗体上使用 QTreeWidget 开发 Qt 应用程序。用户可以按添加新项目按钮,新项目将以默认名称出现,之后用户必须输入项目名称。
所以这是我的代码:
void MyFormClass::on_addNewItemButton_clicked()
{
auto newItem = new QTreeWidgetItem({ _defaultName });
newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
ui->tree->addTopLevelItem(newItem);
ui->tree->editItem(newItem);
}
在 MyFormClass 中,我还捕获了 itemChanged 信号以对新创建的项目及其名称进行一些操作:
void MyFormClass::on_tree_itemChanged(QTreeWidgetItem *item, int column)
{
if (item->text(0).isEmpty()) {
...
} else {
...
}
}
一切正常,除非用户 不做任何更改 并且只是在某处按 Enter/left-click。这种情况下 QTreeWidget [可能] 检查该项目实际上没有被改变并且没有发出正确的信号。
所以有什么想法可以创建新项目,然后允许用户立即编辑它并最终捕获任何编辑结果(即与默认设置相同)?也许使用 QTreeView 会有帮助?
Qt 5.4.2,C++11,Linux/Windows 平台
奖金问题:为什么 Qt 是这样设计的?我的意思是,检查项目是否已更改不是我的事吗?好的,信号被称为 itemChanged,但是为什么没有 editFinished 信号什么的?
我想应用该方法的正确范围是 QTreeWidget。所以,我们可以通过MyTreeWidget来继承QTreeWidget。
ui->tree = new MyTreeWidget(this); // or how exactly it is initialized
我们的工作领域有一百万个谜团。当事情没有按照我们希望的那样工作时,我们可以尝试诱捕罪魁祸首。当我 运行 在 Qt 小部件中表现得不像我期望的那样时,我跟踪它做了什么:
bool MyTreeWidget::event(QEvent* pEvent)
{
qDebug() << pEvent;
// parent class method call
return QTreeWidget::event(pEvent);
}
然后根据针对特定情况记录的日志,我要么尝试重载特定事件(更好、更安全),要么立即在重载的通用事件处理程序中执行此操作:
bool MyTreeWidget::event(QEvent* pEvent)
{
// suppose this to be a 'culprit' event
if (pEvent->type() == QEvent::WindowDeactivate)
doTheRightThingHere(); // what expected to be done
// parent class method call
return QTreeWidget::event(pEvent);
}
同样的方法也适用于 Event Filter。
首先,我听从了@AlexanderVX 的建议并捕捉到了事件。用户以任何方式完成编辑后,QEvent::ChildRemoved 将在所有情况下出现。我写了一些代码来捕获这个事件结束处理它。
但经过几天的研究,我了解了一些关于项目委托的信息,它可以处理用户编辑,所以这是我的解决方案:
class MyEditingDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyEditingDelegate(QObject *parent = nullptr) : QItemDelegate(parent) {}
virtual void setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
QItemDelegate::setModelData(editor, model, index);
if (index.column() == 0) {
emit editingFinished(index);
}
}
signals:
void editingFinished(const QModelIndex &) const;
};
class MyTreeWidget : public QTreeWidget
{
public:
MyTreeWidget(QWidget *parent = nullptr) : QTreeWidget(parent) {}
QTreeWidgetItem *getItemFromIndex(const QModelIndex &index) const
{
return itemFromIndex(index);
}
};
MyFormClass::MyFormClass()
{
...
auto editDelegate = new MyEditingDelegate(this);
ui->tree->setItemDelegate(editDelegate);
connect(editDelegate,
&MyEditingDelegate::editingFinished,
[this] (const QModelIndex &index) {
auto item = ui->tree->getItemFromIndex(index);
onItemEditingFinished(item); // this is my handler
});
...
}
我正在 Qt Designer 窗体上使用 QTreeWidget 开发 Qt 应用程序。用户可以按添加新项目按钮,新项目将以默认名称出现,之后用户必须输入项目名称。
所以这是我的代码:
void MyFormClass::on_addNewItemButton_clicked()
{
auto newItem = new QTreeWidgetItem({ _defaultName });
newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
ui->tree->addTopLevelItem(newItem);
ui->tree->editItem(newItem);
}
在 MyFormClass 中,我还捕获了 itemChanged 信号以对新创建的项目及其名称进行一些操作:
void MyFormClass::on_tree_itemChanged(QTreeWidgetItem *item, int column)
{
if (item->text(0).isEmpty()) {
...
} else {
...
}
}
一切正常,除非用户 不做任何更改 并且只是在某处按 Enter/left-click。这种情况下 QTreeWidget [可能] 检查该项目实际上没有被改变并且没有发出正确的信号。
所以有什么想法可以创建新项目,然后允许用户立即编辑它并最终捕获任何编辑结果(即与默认设置相同)?也许使用 QTreeView 会有帮助?
Qt 5.4.2,C++11,Linux/Windows 平台
奖金问题:为什么 Qt 是这样设计的?我的意思是,检查项目是否已更改不是我的事吗?好的,信号被称为 itemChanged,但是为什么没有 editFinished 信号什么的?
我想应用该方法的正确范围是 QTreeWidget。所以,我们可以通过MyTreeWidget来继承QTreeWidget。
ui->tree = new MyTreeWidget(this); // or how exactly it is initialized
我们的工作领域有一百万个谜团。当事情没有按照我们希望的那样工作时,我们可以尝试诱捕罪魁祸首。当我 运行 在 Qt 小部件中表现得不像我期望的那样时,我跟踪它做了什么:
bool MyTreeWidget::event(QEvent* pEvent)
{
qDebug() << pEvent;
// parent class method call
return QTreeWidget::event(pEvent);
}
然后根据针对特定情况记录的日志,我要么尝试重载特定事件(更好、更安全),要么立即在重载的通用事件处理程序中执行此操作:
bool MyTreeWidget::event(QEvent* pEvent)
{
// suppose this to be a 'culprit' event
if (pEvent->type() == QEvent::WindowDeactivate)
doTheRightThingHere(); // what expected to be done
// parent class method call
return QTreeWidget::event(pEvent);
}
同样的方法也适用于 Event Filter。
首先,我听从了@AlexanderVX 的建议并捕捉到了事件。用户以任何方式完成编辑后,QEvent::ChildRemoved 将在所有情况下出现。我写了一些代码来捕获这个事件结束处理它。
但经过几天的研究,我了解了一些关于项目委托的信息,它可以处理用户编辑,所以这是我的解决方案:
class MyEditingDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyEditingDelegate(QObject *parent = nullptr) : QItemDelegate(parent) {}
virtual void setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const
{
QItemDelegate::setModelData(editor, model, index);
if (index.column() == 0) {
emit editingFinished(index);
}
}
signals:
void editingFinished(const QModelIndex &) const;
};
class MyTreeWidget : public QTreeWidget
{
public:
MyTreeWidget(QWidget *parent = nullptr) : QTreeWidget(parent) {}
QTreeWidgetItem *getItemFromIndex(const QModelIndex &index) const
{
return itemFromIndex(index);
}
};
MyFormClass::MyFormClass()
{
...
auto editDelegate = new MyEditingDelegate(this);
ui->tree->setItemDelegate(editDelegate);
connect(editDelegate,
&MyEditingDelegate::editingFinished,
[this] (const QModelIndex &index) {
auto item = ui->tree->getItemFromIndex(index);
onItemEditingFinished(item); // this is my handler
});
...
}