PDA

View Full Version : How to get rid of focus of qtreewidgetitem after editing with a delegate



iwatsu
3rd July 2012, 18:46
I have a custom delegate and connected the closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint) to a slot. In this slot I call the signal commitData(widget) and would expect that after closing the editor it would also loose focus and the editor widget would get distroyed.

For some reason I first have to click outside somewhere in order for the destructor to get called.

How can I force the destruction of the editor widget and loose focus?

Thanks

iwatsu
5th July 2012, 17:57
Please let me know if I'm not clear enough:

I expect the widget that was previously created in createEditor() to be destroyed when the following method gets called. I listen to the signal
closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint) that is connected to SlotCloseEditor.



void Class::SlotCloseEditor(QWidget* widget)
{
MyWidget *w= dynamic_cast<MyWidget*>(widget);
if(w)
{
.....
emit commitData(widget);
}
}


Why is the destructor of this widget only called when I click outside and not immediately when I call: emit commit Data(widget)

Thanks

ChrisW67
6th July 2012, 00:52
The closeEditor() signal is only emitted when the user does something to terminate editing of the cell. For example if the user presses Escape to cancel editing, presses enter/shifts the focus to accept the edited value. Until the signal is emitted your slot code never executes.

What exactly are you trying to achieve?

iwatsu
6th July 2012, 01:05
I DO get to the slot code when I hit enter after I'm done editing. But for some reason the destructor of the editor widget doesn't get called. I want the editor be closed/destroyed when I exit the function.

ChrisW67
6th July 2012, 01:35
You don't need to do anything special to achieve that:


#include <QtGui>
#include <QDebug>

class MyLineEdit: public QLineEdit
{
public:
explicit MyLineEdit(QWidget *p = 0): QLineEdit(p) { qDebug() << "Constructed" << this; }
~MyLineEdit() { qDebug() << "Destroyed" << this; }
};

class MyDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
explicit MyDelegate(QObject *p = 0): QStyledItemDelegate(p) { }

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const {
return new MyLineEdit(parent);
}
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QTableWidget t(5, 5);
t.setItemDelegate(new MyDelegate(&t));
t.show();

return app.exec();
}
#include "main.moc"


Without more of your code we cannot see what you are doing that would change the situation.

iwatsu
10th July 2012, 01:11
Thanks for the sample code. I expanded the code to illustrate my problem:

DelegateProblem.h



#include <QtGui>

class MyTextEdit: public QTextEdit
{
Q_OBJECT
public:
explicit MyTextEdit(QWidget *p = 0): QTextEdit(p) {}
~MyTextEdit() {}
void keyPressEvent(QKeyEvent *event);
Q_SIGNALS:
void EnterPressed();
};

class ButtonEditor : public QAbstractButton
{
Q_OBJECT
public:
ButtonEditor(QWidget *parent = NULL);
~ButtonEditor() { qDebug() << "Destroyed" << this; }
virtual void mouseDoubleClickEvent( QMouseEvent * event );
virtual void paintEvent(QPaintEvent *e);

MyTextEdit *mTextEdit;
Q_SIGNALS:
void SignalEditingFinished(QWidget*);

public slots:
void EditingFinished();
};

class MyDelegate: public QStyledItemDelegate
{
Q_OBJECT
public:
explicit MyDelegate(QObject *p = 0);

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
ButtonEditor *btn = new ButtonEditor(parent);
Q_ASSERT(connect(btn, SIGNAL(SignalEditingFinished(QWidget*)), this, SLOT(SlotCloseEditor(QWidget*))));
return btn;
}

public slots:
void SlotCloseEditor(QWidget*);
};

class DelegateProblem : public QWidget
{
Q_OBJECT
public:
DelegateProblem(QWidget *parent = 0, Qt::WFlags flags = 0);
~DelegateProblem() {}
};



DelegateProblem.cpp



#include "DelegateProblem.h"

DelegateProblem::DelegateProblem(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags)
{
QVBoxLayout *layout = new QVBoxLayout;
QTableWidget *t = new QTableWidget(5, 5);
t->setItemDelegate(new MyDelegate(t));
t->setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);
layout->addWidget(t);
setLayout(layout);
}

//---------- MyDelegate---------------------------------------------
//-------------------------------------------------------------------
MyDelegate::MyDelegate( QObject *p /*= 0*/ )
: QStyledItemDelegate(p)
{
Q_ASSERT(connect(this, SIGNAL(closeEditor(QWidget*, QAbstractItemDelegate::EndEditHint)), this, SLOT(SlotCloseEditor(QWidget*))));
}

void MyDelegate::SlotCloseEditor( QWidget* )
{
qDebug() << "I don't hit ~ButtonEditor() afterwards";
}

//---------- ButtonEditor -------------------------------------------
//-------------------------------------------------------------------
void ButtonEditor::mouseDoubleClickEvent( QMouseEvent * event )
{
mTextEdit->setText(text());
mTextEdit->setVisible(true);
Q_ASSERT(connect(mTextEdit, SIGNAL(EnterPressed()), this, SLOT(EditingFinished())));
}

void ButtonEditor::paintEvent( QPaintEvent *e )
{
QStylePainter painter( this );
QStyleOptionButton opt;
opt.initFrom(this);
opt.palette = palette();
opt.state |= QStyle::State_AutoRaise;
painter.drawControl(QStyle::CE_PushButtonBevel, opt);
}

ButtonEditor::ButtonEditor( QWidget *parent /*= NULL*/ )
: QAbstractButton(parent)
{
mTextEdit = new MyTextEdit(this);
mTextEdit->setVisible(false);
mTextEdit->setAcceptRichText(false);
mTextEdit->setFrameShape(QFrame::Box);
mTextEdit->setFrameShadow(QFrame::Plain);
}

void ButtonEditor::EditingFinished()
{
mTextEdit->setVisible(false);
emit SignalEditingFinished(this);
}

//---------- MyTextEdit -------------------------------------------
//-------------------------------------------------------------------
void MyTextEdit::keyPressEvent( QKeyEvent *event )
{
if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{
emit EnterPressed();
}
QTextEdit::keyPressEvent(event);
}



Double click on the button and the custom text edit appears. after entering something, press the Enter key: MyDelegate::SlotCloseEditor() gets called but not the ButtonEditor() destructor (unless I click into another cell)
What prevents it from being called?

Thanks!

ChrisW67
10th July 2012, 08:20
At the moment when the user triggers editing (by clicking, double-clicking, or moving the current cell) a blank button is created in the table cell. When the user double clicks the blank button a text edit is created (this has nothing to do with the delegate). A text edit is a multi-line editor so hitting Enter does not close the editor and you have implemented a kludge to intercept and attempt to do something with the Enter key press. On my machine the SlotCloseEditor() is never called.

What effect are you trying to achieve?

iwatsu
10th July 2012, 16:05
add this to mouseDoubleClickEvent() to show the cursor directly after double clicking on the button.



mTextEdit->setFocus(Qt::OtherFocusReason);


Are you typing something and press Enter? You should hit the MyDelegate::SlotCloseEditor() function.

iwatsu
9th August 2012, 23:32
I'm still having this problem. I'm expecting that the editor gets closed (~ButtonEditor() should get called) when hitting Enter in the text edit field. That's why I implemented this kludge.

1. Double click in first cell
2. add some text
3. hit Enter key
MyDelegate::SlotCloseEditor() gets called: then I should hit the ButtonEditor destructor...

What prevents it from being called?
Thanks!

ChrisW67
10th August 2012, 04:36
In your example the text editor you create separately closes, emits a signal, triggers a slot:


void MyDelegate::SlotCloseEditor( QWidget* )
{
qDebug() << "I don't hit ~ButtonEditor() afterwards";
}

that does nothing. The button, i.e. the "editor", remains active and will not be destroyed until the focus is lost.

I still have no idea why you create a button as the "editor" or why you use a multiline editor QTextEdit only to remove the possibility of inserting a new line.

iwatsu
10th August 2012, 15:51
In your example the text editor you create separately closes, emits a signal, triggers a slot:


void MyDelegate::SlotCloseEditor( QWidget* )
{
qDebug() << "I don't hit ~ButtonEditor() afterwards";
}

that does nothing. The button, i.e. the "editor", remains active and will not be destroyed until the focus is lost.

Are you saying it's not possible to force it to loose the focus?



I still have no idea why you create a button as the "editor" or why you use a multiline editor QTextEdit only to remove the possibility of inserting a new line.

I'm reusing a class that allows multiline but for my case I don't need that feature. The button editor allows to popup a menu in order to change units but it's also possible to rename the button text.