Item delegate editor focus problem



  • I want to create an editor widget wich can be returned be QAbstractItemDelegate::createEditor(). MyEditorWidget shown below has some focus problems. When used in e.g. a list view pressing 'tab' while the editor is active will change the selection in the list but not close the editor. If I return a QSpinBox directly in createEditor() it works correctly (the editor follows the list selection when tabbing). I suspect I need to do something with focus events or similar. Are there some specific requirements for an editor widget regarding this focus issue?

    @
    class MyEditorWidget : public QWidget
    {
    Q_OBJECT
    public:
    explicit MyEditorWidget(QWidget *parent = 0) : QWidget(parent) {
    setLayout(new QHBoxLayout());
    layout()->setMargin(0);
    layout()->addWidget(new QSpinBox());
    }
    };
    @

    Thanks,

    Jakob



  • Just a wild guess: it could help to "setFocusPolicy() ":http://doc.qt.nokia.com/4.7/qwidget.html#focusPolicy-prop and/or a "focus proxy":http://doc.qt.nokia.com/4.7/qwidget.html#setFocusProxy



  • If you only use a spin box, use it directkly as editor widget, otherwise, as volker stated, use setFocusPolicy and setFocusProxy.



  • Ok, maybe my code sample was a bit too simplified. I need an editor which contains more than one child widget, for example:

    @
    class MyEditorWidget : public QWidget
    {
    Q_OBJECT
    public:
    explicit MyEditorWidget(QWidget *parent = 0) : QWidget(parent) {
    setLayout(new QHBoxLayout());
    layout()->setMargin(0);
    setFocusPolicy(Qt::StrongFocus);

        QLineEdit* l1 = new QLineEdit();
        l1->setFocusPolicy(Qt::StrongFocus);
    
        QLineEdit* l2 = new QLineEdit();
        l1->setFocusPolicy(Qt::StrongFocus);
    
        layout()->addWidget(l1);
        layout()->addWidget(l2);
    }
    

    };
    @

    I have tried different focus policies for the widgets. I have tried to make the parent the focus proxy for the children. Whatever I do I still have the issue that the current item on the view may move away while the editor stays open and other similar strange focus behaviors.

    It seems that none of the Qt examples on model view delegates have editors with multiple child widgets. Maybe the framework isn't built for this :-(



  • I'm sure, it is possible.

    Please have a look at the code of the base delegate implementations. They react to several signals / events from the editors. I think you have to change such things in your custom delegate.



  • My delegate derives from QItemDelegate. It implements createEditor(), setEditorData(), and setModelData(). It works fine if I return a Qt widget - eg. QSpinBox - as an editor but breaks (focus issues) if I return my own editor (as described above). This makes me think that the problem is with my editor and not my delegate. However, looking at the code for for QSpinBox (which does in fact have multiple child widgets) it is not easy to determine exactly what is needed by the model/view/delegate framework since QSpinBox is fairly complex. So I was hoping that there were some relative simple rules that an item delegate editor should adhere to. If this is not the case, you may be right (Gerolf), that I should turn my attention to the delegate instead...



  • The problem is NOT the widget, it's the delegate.

    The delegate is more than just createEditor, setEditorData, setModeldata.

    If you have complex editor widgets, you have to overwrite more functions, like :

    • virtual bool editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index )
    • virtual bool eventFilter ( QObject * editor, QEvent * event )

    please see the docs and the code. It is possible, but not trivial. I did such things once in a project, but that code is not publicly available, sorry.

    But if you look at the code of Qt default delegates, they implement those functions, you can see what happens. Also as I did that, I checked the code of one view to see, what happens there. It is definitly possible, but not very easy...



  • What do you mean by "Qt default delegates"? QItemDelegate and QStyledItemDelegate? Please note that I am deriving my delegate from QItemDelegate and thus already have implementations for editorEvent() and eventFilter().



  • It does not matter if you derive. And is does not matter which of them, the event handling is equal.

    Read the code of those delegate. Look what they do when. Look how they handle tab, cursor, focus etc. This is all done by the delegates. And the default behavior might lead to your problems, as you have a different behaving widget.

    Read the code of QItemDelegate and QTableView to understand what they do when and how they do it. Then perhaps you find a way, how you have to change things so your editor works!

    I have a delegate (CombBox as auto filter) which in some cases opens a modal dialog. you then have to change that behavior. But to see what and where, you first have to read the Qt code.

    So again: read the code of the trolls for that.



  • Yes, reading and understanding the code of the trolls will of course help me solve the problem. But it is a rather large chunk of code - QAbstractItemView is 4000 lines alone. Maybe I just hasn't got what it takes :-)

    Thanks anyway.



  • start with the delaget code
    For the view to understand, mouse and key events and eventFilter if it exists.

    But start with the delegate. And then perhaps also look, where the delegate is used in the view.



  • At the end of your constructor add

    @
    setFocusProxy(l1);
    @

    Also, create a new item delegate and reimplement

    • createEditor
    • setEditorData
    • setModelData

    @
    QWidget *MyDelegate::createEditor ( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const
    {
    return new MyEditorWidget(parent);
    }

    void MyDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const
    {
    if(MyEditorWidget *me = qobject_cast<MyEditorWidget *>(editor))
    me->l1->setText(index.data(Qt::EditRole));
    }

    void MyDelegate::setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const
    {
    if(MyEditorWidget *me = qobject_cast<MyEditorWidget *>(editor))
    model->setData(index, me->l2->text());
    }
    @

    This should be all you need.



  • It doesn't work for me. The solution you suggest has several issues:

    • It is not possible to use tab to navigate between l1 and l2. If l1 has focus and tab is pressed MyEditorWidget will be closed and the next cell will be selected in the list view.

    • Minor issue: If an editor is opened on a cell and tab is pressed the focus moves to the next cell but an editor is not opened in the new cell (as it happens when the editor is a Qt widget - eg QSpinBox).

    • Bizarre issue: If an editor is opened on cell 1 with focus on l2 and tab is pressed the editor is closed and focus moves to cell 2. But if tab is pressed a second time nothing happens. If tab is pressed a third time focus moves to cell 4, skipping cell 3.



  • Set l2 to NoFocus.

    Everything else regarding tab key cannot work, as the view intercepts the tab keys. You will have to change the view too, to make it work.

    Regarding the second issue, that might go away with l2 on NoFocus too. I'd suggest you play around with setFocus on l1 and l2 a bit. It might be enough to have it on the outer container (MyEditWidget).



  • [quote author="Volker" date="1298461923"]Set l2 to NoFocus.

    Everything else regarding tab key cannot work, as the view intercepts the tab keys. You will have to change the view too, to make it work.

    Regarding the second issue, that might go away with l2 on NoFocus too. I'd suggest you play around with setFocus on l1 and l2 a bit. It might be enough to have it on the outer container (MyEditWidget).[/quote]

    It' s the delegate implementation, as I already stated above.

    • virtual bool Q(Styled)Itemdelegate::editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index )
    • virtual bool Q(Styled)Itemdelegate::eventFilter ( QObject * editor, QEvent * event )

    And this is the point, where you can change the logic for tab etc.



  • Thank's Gerolf, I missed this from the first comments, sorry. That should do the trick.



  • Seems I have the same problem. I tried to solve it like I described on SO: http://stackoverflow.com/questions/12145522/why-pressing-of-tab-key-emits-only-qeventshortcutoverride-event


Log in to reply
 

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