| Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date | |
| All threads index page 2 | |
Hi folks, In a model/view of my own, I would need to have interactive QWidget for various QModelIndexes, eg : - draw a progressbar - have an interactive button which icon depends on the QModelIndex's data - etc I am quite sure there is a **standard** way of having interactive QWidget in the wiew for QModelIndexes, but... I am not able to figure it out from the doc or the example. I may use QAbstractItemModel::setIndexWidget(), but... since the content to render is dynamic (depends on the model's data, cf. the doc for QAbstractItemView::setIndexWidget()), and since I have many rows() in my model (ie it would require allocating many QWidgets), it is clearly not the correct solution... I think the correct way to achieve this is using a QItemDelegate. Am I wrong ? But how ? From that point, I see two possibilities : POSSIBILITY 1 : In MyItemDelegate::paint(), "emulate" the widget, ie draw the widget by using a QStylePainter, without alocating a widget dynamically in memory. However, in that case, how may I emulate the correct behavior for the widget, eg : - highlight the buttons when they are entered, or pushed - etc. ? POSSIBILITY 2 : When the QModelIndex is "not interactive", use the POSSIBILITY 1 mean. Now, when the mouse enters a QModelIndex (ie : the modelindex's widget may be under the mouse), make the widget interactive by doing the following : 1/ start editing the QModelIndex by calling QAbstractItemModel::edit(). 2/ In MyItemDelegate::createEditor(), allocate the needed QWidget, and return it. Now, for example, if the widget is a QPushButton, it is correctly displayed and behaves correctly. Problems : 1/ this requires allocating a QWidget each time the mouse moves to a new QModelIndex 2/ there is no leave(QModelIndex) signal in QAbstractItemView, so... how should I close and delete the editor ? I am quite sure there are some example arround that let the ItemDelegate emulate some QWidgets... Would be grateful if anyone could post it, or provide some hints ! Best- Nicolas -- [ signature omitted ]
On 07.12.06 14:24:20, Nicolas Castagne wrote: > Now, when the mouse enters a QModelIndex (ie : the modelindex's widget may > be under the mouse), make the widget interactive by doing the following : > 1/ start editing the QModelIndex by calling QAbstractItemModel::edit(). > 2/ In MyItemDelegate::createEditor(), allocate the needed QWidget, and > return it. > > Now, for example, if the widget is a QPushButton, it is correctly displayed > and behaves correctly. > Problems : > 1/ this requires allocating a QWidget each time the mouse moves to a new > QModelIndex > 2/ there is no leave(QModelIndex) signal in QAbstractItemView, so... how > should I close and delete the editor ? Could you clarify wether you want that widget yo be displayed _always_ or just when the user edits the item? If its just for editing you won't have a problem with "too many widgets", the widgets will be deleted once the editing is done. In case you always want to display a widget: What exactly should that widget do? Pushbuttons could work, about progress bars I'm not so sure. I mean seeing 20 different progress bars on the screen is distracting, emitting dataChanged for a few hundred (or thousand) indexes will also probably not perform very well. Andreas -- [ signature omitted ]
Hi Andreas, > Could you clarify wether you want that widget yo be displayed _always_ > or just when the user edits the item? The widget should, indeed, be displayed _always_, and it should be interactive, if it is an interactive widget, when the mouse is over it (ie : as a any interactive QWidget does). That's why I have problems with the "too many widgets" implicated by QAbstractItemView::setIndexWidget. Now, I mainly need Buttons, you are right. I am, in fact, quite close to the required behavior with the following : 1/ in MyItemDelegate::paint, do a QPixmap::grabWidget() and render it 2/ let the QModelIndex be editable in the model (QAbstractItemModel::flags()) 3/ connect the signal QAbstractItemView::entered() to the slot QAbstractItemView::edit() 4/ in MyItemDelegate::createEditor(), allocate the needed widget and returns it However, I still have some problems I am working on. My main question now is : am going toward a correct solution ? If yes, I may post later on a sample code, to let pple know and to detail the remaining problems. Now, concerning : > In case you always want to display a widget: What exactly should that > widget do? Pushbuttons could work, about progress bars I'm not so sure. > I mean seeing 20 different progress bars on the screen is distracting, > emitting dataChanged for a few hundred (or thousand) indexes will also > probably not perform very well. Each rows corresponds with a threaded processing. Only a few can be active at a moment. The progressbar is available only for these rows. The rows are updated only on a per-second basis : not so costly in fact. Though, I mainly need interactive buttons, as said previously. But, more generally, I am looking for a generic mean I may reuse in other model/view I am about to design. I am quite sure there is one, thanks to this huuuuuuuuuuuuuuuuge Qt library :=) Best- Nicolas Andreas Pakulat wrote: > On 07.12.06 14:24:20, Nicolas Castagne wrote: >> Now, when the mouse enters a QModelIndex (ie : the modelindex's widget >> may be under the mouse), make the widget interactive by doing the >> following : 1/ start editing the QModelIndex by calling >> QAbstractItemModel::edit(). 2/ In MyItemDelegate::createEditor(), >> allocate the needed QWidget, and return it. >> >> Now, for example, if the widget is a QPushButton, it is correctly >> displayed and behaves correctly. >> Problems : >> 1/ this requires allocating a QWidget each time the mouse moves to a new >> QModelIndex >> 2/ there is no leave(QModelIndex) signal in QAbstractItemView, so... how >> should I close and delete the editor ? > > Could you clarify wether you want that widget yo be displayed _always_ > or just when the user edits the item? > > If its just for editing you won't have a problem with "too many > widgets", the widgets will be deleted once the editing is done. > > In case you always want to display a widget: What exactly should that > widget do? Pushbuttons could work, about progress bars I'm not so sure. > I mean seeing 20 different progress bars on the screen is distracting, > emitting dataChanged for a few hundred (or thousand) indexes will also > probably not perform very well. > > Andreas > -- [ signature omitted ]
On 07.12.06 18:16:31, Nicolas Castagne wrote: > Hi Andreas, > > > Could you clarify wether you want that widget yo be displayed _always_ > > or just when the user edits the item? > > The widget should, indeed, be displayed _always_, > and it should be interactive, if it is an interactive widget, > when the mouse is over it (ie : as a any interactive QWidget does). > > That's why I have problems with the "too many widgets" implicated by > QAbstractItemView::setIndexWidget. I think this is the time I would start to think about subclassing one of the Q*View classes (I guess QTableView for you) and hook into the scrolling. That way you could only create widgets for the indexes that are currently visible, and if a widget goes "out of sight" delete the widgets for it (or even reuse them!). Andreas -- [ signature omitted ]
Nicolas, The problem with showing actual widgets "always" is that isn't not scalable. A 1000x10 table is 10000 widgets. Not to mention Windows has a hard system wide limit of ~32K objects. So what you really want is 10,000 fake widgets drawn with one real widget created to edit a cell. A user cannot physically edit more than one field at a time. If done right the switching from fake to real widgets is transparent because the pixels line up exactly. Here is what you want to do: 1)In paint() Create a QStyleOptions for the widget you want to draw Fill out the structure. Get a pointer to the platform style and call something like style->drawControl(CE_PushButton, opts, painter, 0); 2) In createEditor Return a newly allocated "real" widget like: return new QPushButton; The style code is the exact same code that the widget uses to draw itself, so the look is exactly the same. You can now paint thousands of "widgets" and still edit transparently with a "real" widget. --Justin Nicolas Castagne wrote: > Hi Andreas, > > >> Could you clarify wether you want that widget yo be displayed _always_ >> or just when the user edits the item? >> > > The widget should, indeed, be displayed _always_, > and it should be interactive, if it is an interactive widget, > when the mouse is over it (ie : as a any interactive QWidget does). > > That's why I have problems with the "too many widgets" implicated by > QAbstractItemView::setIndexWidget. > > Now, I mainly need Buttons, you are right. > > > I am, in fact, quite close to the required behavior with the following : > > 1/ in MyItemDelegate::paint, do a QPixmap::grabWidget() and render it > > 2/ let the QModelIndex be editable in the model > (QAbstractItemModel::flags()) > > 3/ connect the signal QAbstractItemView::entered() to the slot > QAbstractItemView::edit() > > 4/ in MyItemDelegate::createEditor(), allocate the needed widget and returns > it > > > > However, I still have some problems I am working on. > > My main question now is : am going toward a correct solution ? > > If yes, I may post later on a sample code, to let pple know and to detail > the remaining problems. > > > > > Now, concerning : > >> In case you always want to display a widget: What exactly should that >> widget do? Pushbuttons could work, about progress bars I'm not so sure. >> I mean seeing 20 different progress bars on the screen is distracting, >> emitting dataChanged for a few hundred (or thousand) indexes will also >> probably not perform very well. >> > > Each rows corresponds with a threaded processing. > Only a few can be active at a moment. > The progressbar is available only for these rows. > The rows are updated only on a per-second basis : not so costly in fact. > > > Though, I mainly need interactive buttons, as said previously. > > But, more generally, I am looking for a generic mean I may reuse in other > model/view I am about to design. > I am quite sure there is one, thanks to this huuuuuuuuuuuuuuuuge Qt > library :=) > > Best- > Nicolas > > > Andreas Pakulat wrote: > > >> On 07.12.06 14:24:20, Nicolas Castagne wrote: >> >>> Now, when the mouse enters a QModelIndex (ie : the modelindex's widget >>> may be under the mouse), make the widget interactive by doing the >>> following : 1/ start editing the QModelIndex by calling >>> QAbstractItemModel::edit(). 2/ In MyItemDelegate::createEditor(), >>> allocate the needed QWidget, and return it. >>> >>> Now, for example, if the widget is a QPushButton, it is correctly >>> displayed and behaves correctly. >>> Problems : >>> 1/ this requires allocating a QWidget each time the mouse moves to a new >>> QModelIndex >>> 2/ there is no leave(QModelIndex) signal in QAbstractItemView, so... how >>> should I close and delete the editor ? >>> >> Could you clarify wether you want that widget yo be displayed _always_ >> or just when the user edits the item? >> >> If its just for editing you won't have a problem with "too many >> widgets", the widgets will be deleted once the editing is done. >> >> In case you always want to display a widget: What exactly should that >> widget do? Pushbuttons could work, about progress bars I'm not so sure. >> I mean seeing 20 different progress bars on the screen is distracting, >> emitting dataChanged for a few hundred (or thousand) indexes will also >> probably not perform very well. >> >> Andreas >> >> > > -- > To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body. > List archive and information: http://lists.trolltech.com/qt-interest/ >
begin:vcard
begin:vcard fn:Justin Noel n:Noel;Justin org:ICS;Engineering adr:;;54B Middlesex Trpk;Bedford;MA;01730;USA email;internet:justin@xxxxxxx title:Sr. Consulting Engineer / Certified Qt Instructor tel;work:(617) 621-0060 url:http://www.ics.com version:2.1 end:vcard
Thx you both for your answer. Andreas, I ll think about your porposal closely tomorrow ! Justin : you got precisely what I was thinking about ! Now, two refined problems I am into are : PB 1 : the true QWidget to be used is not the "edited widget" in the sense of the view. Especially, the widget should be "not fake" but "true" when the mose is over the QModelIndex. The view does not provide a mean trigger editing when the "mouse is over". Hence, I have to set up one. The best I found so far is : connecting the signal QAbstractItemView::entered() to the slot QAbstractItemView::edit() But it has some drawbacks... PB 2 : dynamic allocation Since my "true" QWidget is about to be displayed often (each time the mouse is over it), I consider it would be much better to let MyItemDelegate possess the widget (as an attribute) and return it in createEditor without the need to alocate it. However, QItemDelegate is not designed to do this. Especially, it seems that Qt silently delete the editor widget once editing is finished. Is there a mean to avoid this ? I think I will be able to post a sample code by tomorrow. Best- Nicolas Justin Noel wrote: > Nicolas, > > The problem with showing actual widgets "always" is that isn't not > scalable. A 1000x10 table is 10000 widgets. Not to mention Windows has > a hard system wide limit of ~32K objects. So what you really want is > 10,000 fake widgets drawn with one real widget created to edit a cell. > A user cannot physically edit more than one field at a time. If done > right the switching from fake to real widgets is transparent because > the pixels line up exactly. Here is what you want to do: > > 1)In paint() > Create a QStyleOptions for the widget you want to draw > Fill out the structure. > Get a pointer to the platform style and call something like > style->drawControl(CE_PushButton, opts, painter, 0); > > 2) In createEditor > Return a newly allocated "real" widget like: > return new QPushButton; > > The style code is the exact same code that the widget uses to draw > itself, so the look is exactly the same. You can now paint thousands of > "widgets" and still edit transparently with a "real" widget. > > --Justin > > Nicolas Castagne wrote: >> Hi Andreas, >> >> >>> Could you clarify wether you want that widget yo be displayed _always_ >>> or just when the user edits the item? >>> >> >> The widget should, indeed, be displayed _always_, >> and it should be interactive, if it is an interactive widget, >> when the mouse is over it (ie : as a any interactive QWidget does). >> >> That's why I have problems with the "too many widgets" implicated by >> QAbstractItemView::setIndexWidget. >> >> Now, I mainly need Buttons, you are right. >> >> >> I am, in fact, quite close to the required behavior with the following : >> >> 1/ in MyItemDelegate::paint, do a QPixmap::grabWidget() and render it >> >> 2/ let the QModelIndex be editable in the model >> (QAbstractItemModel::flags()) >> >> 3/ connect the signal QAbstractItemView::entered() to the slot >> QAbstractItemView::edit() >> >> 4/ in MyItemDelegate::createEditor(), allocate the needed widget and >> returns it >> >> >> >> However, I still have some problems I am working on. >> >> My main question now is : am going toward a correct solution ? >> >> If yes, I may post later on a sample code, to let pple know and to detail >> the remaining problems. >> >> >> >> >> Now, concerning : >> >>> In case you always want to display a widget: What exactly should that >>> widget do? Pushbuttons could work, about progress bars I'm not so sure. >>> I mean seeing 20 different progress bars on the screen is distracting, >>> emitting dataChanged for a few hundred (or thousand) indexes will also >>> probably not perform very well. >>> >> >> Each rows corresponds with a threaded processing. >> Only a few can be active at a moment. >> The progressbar is available only for these rows. >> The rows are updated only on a per-second basis : not so costly in fact. >> >> >> Though, I mainly need interactive buttons, as said previously. >> >> But, more generally, I am looking for a generic mean I may reuse in other >> model/view I am about to design. >> I am quite sure there is one, thanks to this huuuuuuuuuuuuuuuuge Qt >> library :=) >> >> Best- >> Nicolas >> >> >> Andreas Pakulat wrote: >> >> >>> On 07.12.06 14:24:20, Nicolas Castagne wrote: >>> >>>> Now, when the mouse enters a QModelIndex (ie : the modelindex's widget >>>> may be under the mouse), make the widget interactive by doing the >>>> following : 1/ start editing the QModelIndex by calling >>>> QAbstractItemModel::edit(). 2/ In MyItemDelegate::createEditor(), >>>> allocate the needed QWidget, and return it. >>>> >>>> Now, for example, if the widget is a QPushButton, it is correctly >>>> displayed and behaves correctly. >>>> Problems : >>>> 1/ this requires allocating a QWidget each time the mouse moves to a >>>> new QModelIndex >>>> 2/ there is no leave(QModelIndex) signal in QAbstractItemView, so... >>>> how should I close and delete the editor ? >>>> >>> Could you clarify wether you want that widget yo be displayed _always_ >>> or just when the user edits the item? >>> >>> If its just for editing you won't have a problem with "too many >>> widgets", the widgets will be deleted once the editing is done. >>> >>> In case you always want to display a widget: What exactly should that >>> widget do? Pushbuttons could work, about progress bars I'm not so sure. >>> I mean seeing 20 different progress bars on the screen is distracting, >>> emitting dataChanged for a few hundred (or thousand) indexes will also >>> probably not perform very well. >>> >>> Andreas >>> >>> >> >> -- >> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with >> "unsubscribe" in the subject or the body. List archive and information: >> http://lists.trolltech.com/qt-interest/ >> -- [ signature omitted ]
Hi folks, As "promised", I enclose in this post a sample code featuring a View displaying "virtual" interactive QWidgets. As far as I checked, no bug in this code. And I did not notice slow down. But... I am not sure it is the best solution to achieve the specs. So, ANY comment, advice, etc. welcomed ! In my code, all the rendering of widget are made by drawing allocated widget. No use of QStylePainter. Though, one need only a single allocated widget per column - see MyItemDelegate. Note that In the view open a persistent editor to display the interactive, QPushButton (ie : when mouse is over the corresponding index). This is because this "pseudo-editor" may be opened while another index is edited (in row 0 for example), and because the view cannot have mutliple editors opened unless they are "persistent" (AFAIK). Each row in the model corresponds with a "pseudo-process" MyModelRowData which processing is emulated by a QTimer. The model has three colums. Column 0 is the row name. Column 1 is the row's completion percentage. It is renderd through a ProgressBar. Column 2 is the mean to control the state of the row. It is renderd through a PushButton. My own comment on this sample code is : Now that I came to this code, I think that, probably, it would be better (especially more efficient) not to use any allocated widget, but to do ALL the paintings by drawing a "virtual" widget using a QStylePainter. However, drawing should reflect all the usual interactive widget's behavior. I am not sure that this is possible by using the QStyleOptionViewItem options provided in ItemDelegate::paint()... Especially, shall we have in QStyleOptionViewItem "on mouse press", "on mouse over" options, etc ? And what if the widget is not a simple QWidget, but a complex, layouted widget ? Anyhow, it seems a bit painful. "Analysing" the QStyleOptionViewItem in order to build the specific QStyleOption corresponding with the needed widget seems a bit tricky. What do you think ? End of comment. Your turn ! ;=) Best- Nicolas
Attachment:
widgets_in_view.tar
Description: Unix tar archive