PDA

View Full Version : Model-view: Creating a custom view



taboom
16th August 2007, 18:59
After reading http://doc.trolltech.com/4.3/model-view-view.html and http://doc.trolltech.com/4.3/model-view-delegate.html over and over again I still wonder how I am supposed to create my custom view. What I want is to take a tree-structure (I already have the model done) and show nodes in different ways.

I already did so by starting from QTreeView and reimplementing paintEvent() and going forward from there, just like QTreeView does with drawTree() until I realized I could use readily available widgets to display nodes instead. Say I want to use tabs to display nodes and QTextEdits (or any other widget) when editing information in them.

As an example, say I have a tree with a Root and it has 2 children, 1 QTextEdit and 1 QTabWidget. The QTabWidget has 2 children, both QTextEdits. The code for this is:



QWidget parent; //somehow defined
//Root
QTabWidget *qtabwidget = new QTabWidget(parent);

QWidget *qwidgetPage = new QWidget(qtabwidget);
QVBoxLayout *qvboxlayoutPage = new QVBoxLayout(qwidgetPage);
qvboxlayoutPage->setSpacing( 2 );
qvboxlayoutPage->setMargin( 1 );

//Create and add children
QTextEdit *qtextEdit = new QTextEdit(qwidgetPage);
QTabWidget *qtabwidget2 = new QTabWidget(qwidgetPage);
qvboxlayoutPage->addWidget(qtextEdit);
qvboxlayoutPage->addWidget(qtabwidget2);

//Child1
QWidget *qwidgetPage2 = new QWidget(qtabwidget);
QVBoxLayout *qvboxlayoutPage2 = new QVBoxLayout(qwidgetPage2);
qvboxlayoutPage2->setSpacing( 2 );
qvboxlayoutPage2->setMargin( 1 );
QTextEdit *qtextEdit2 = new QTextEdit(qwidgetPage2);
qvboxlayoutPage2->addWidget(qtextEdit2);

//Child2
QWidget *qwidgetPage2b = new QWidget(qwidgetPage2);
QVBoxLayout *qvboxlayoutPage2b = new QVBoxLayout(qwidgetPage2b);
qvboxlayoutPage2b->setSpacing( 2 );
qvboxlayoutPage2b->setMargin( 1 );
QTextEdit *qtextEdit3 = new QTextEdit(qwidgetPage2);
qvboxlayoutPage2b->addWidget(qtextEdit3);


qtabwidget->addTab( qwidgetPage, "Root");
qtabwidget2->addTab( qwidgetPage2, "Node1");
qtabwidget2->addTab( qwidgetPage2b, "Node2");


Where am I supposed to do this? I can't do it in the paintEvent() for sure.

I just cannot find the function from where I can start creating these widgets to create my own view. The tree is defined in the model so the function I'm looking for is loaded after setModel has been called.

Could it possibly be that I should use QItemDelegate for this - I still have problems understanding how and when they are supposed to be used. If so, how? Any guides available online?

wysota
17th August 2007, 02:13
It'd be easier to answer if you provided a screenshot of what you want to achieve. From what I understand you want "level 1" items to be tabs in a tabwidget and "level 2" nodes to be QTextEdits, correct?

If so, I'd suggest implementing the view from scratch (inheriting QAbstractItemView) and draw "tabs" using QStylePainter (or QStyle).

taboom
17th August 2007, 18:54
Yeah, sorry for not giving a screenshot, but my question is actually much simpler than what it may seem like. The thing is I want to inherit QAbstractItemView (or QTreeView if it helps me somehow) and continue from there, I just don't know what function to reimplement.

I can't create widgets inside the paintEvent()-function of QAbstractItemView and get the widgets visible, right? Even if I could do it, it's pretty unefficient to do so, paintEvent is called pretty often after all. There must be some function where I can do this. I could start the creation of widgets in the setModel()-function as that's where I set the model I need to show, but what if something is changed after this? Say the user resizes the window and nodes should be moved around not to be on top of each other but besides each other instead. Or the user selects something and a new set of widgets should be shown. Where is this then done?

Hmm.. hard to explain and understand I guess. Let's make things super simple. Where can I do this and get it to show in the view?



QModelIndex index = this->model()->index(0,0);
QString string = index.data().toString();
QLabel *qw = new QLabel(string, this);


In what function within QAbstractItemView can I do this to create my view based on my model? Where can I create a (visible) widget? If I do this from within an event I see nothing. If I do it in the constructor, I don't have a model. I want to be able to change the model so that this view updates also.

wysota
17th August 2007, 19:21
The point is not to use any child widgets, but to fake them.

taboom
17th August 2007, 20:12
So I've been on the right track when I've drawn lines/QRects and text via paintEvent()? I cannot use pre-made widgets but have to create them completely myself?

That's kinda strange, as there already exist good widgets, but I cannot use them, don't you think?

Anyways, thanks for the answer :)

wysota
17th August 2007, 20:36
So I've been on the right track when I've drawn lines/QRects and text via paintEvent()?
Yes.

I cannot use pre-made widgets but have to create them completely myself?
That's kinda strange, as there already exist good widgets, but I cannot use them, don't you think?
You can use real widgets, but the solution won't be scalable. Imagine you have to visualize a model that has 1000 items - this means 1000 (or more) widgets. In Qt 4.4+ this won't be a problem, but currently it's quite resource consuming.

If you really want to use standard widgets, you'll have to reimplement resizeEvent and connect to all needed signals from within a model and adjust the position and content of each of the widgets. You can also go for a hybrid solution - use QTabWidget (or better yet QTabBar) and draw its contents yourself, creating QTextEdit widgets for editors when you need them (like the delegates do).