PDA

View Full Version : To any Qgraphics framework guru... need a solution...



tonnot
29th November 2011, 20:29
Hello and excuse for my todays posts
Finally I cannot do a correct solution for a common problem. Need your help.

I want to have a QGrapchics framework view & edit capabilities for manage big vectorial worlds. I'm testing my program against a world with 100000 item entities.
Ok. The feed of system is fast and also its initial visualization.
The problem was when I want to take control over the paint event. (in example to know when the draw is done)
If I use a paintevent, I have to recall QgraphicsView::paint(). No problem.

The big problem I have is when I want to create a dynamic new element (havin the other 100000 items). In example , a new line. To create this line I do the first click and then, when moving the mouse, as expected, I want to view the line. No problem with this. The problem is that I have a repaint for every item intercepted. In case of drawing a new rectangle the problem grows.

To avoid this, I have tried this trick.
I create a temporal item, not added to the scene. On mouse_move_event I throws an invalidate event for the foreground layer, in which I'm going to draw this temporal item. I expected that exist some 'auto' buffer strategy at itemslayer, but not. I see how I have a paintevent. Ok, to avoid this, I create a pixmap at the begin of my edit process, copying the screen , later at the paintevent, where I know if I'm editing, I make a pixmap copy to later draw the temporal line at drawforeground event. (subclased). I have passing a rect for the whole scene ( I pass full scene rect because if no by any reason, foreground painting is strange) (I know that a right rect, restricted only to the area needed, would be better, but...)

The big problem: I have to 'recall' Graphicsview::paint, because if not the drawforeground is not throwed. But doing this means that the QGraphicscene order a repaint for the items...

This is the code for the paintevent of my class, that extends QGrapchisView.


void A_Gview2D::paintEvent(QPaintEvent *event) {

if (w_temp_item!=0 )
{
QPainter painter(this->viewport());
painter.drawPixmap(0,0,*pixMap_cached1);
QGraphicsView::paintEvent(event);
// This is the big problem
// If I dont use it, I have not drawforeground , If I use it I have drawforeground but before repaint
// all items....
}
else
{
w_qtutil->time_start();
QGraphicsView::paintEvent(event);
w_qtutil->time_stop();
qDebug()<< w_qtutil->time_spent()<<"";
}
}

Mousemove code for a rectangle example:

if (w_click_count==1)
{
w_current_Gitem = new A_GItem(WW::Graph_rectangle, QRect(0,0,0,0), punteroo,0);
w_current_Gitem->w_set_draw_props(1,1,1);
w_current_Gitem->setPos(x,y);
last_point_x=x;last_point_y=y;
w_click_count++;
G_view->w_set_temp_item(w_current_Gitem); // set the temporal item
G_view->w_pixmap_copy(); // copy screen
return;
}
else
{
double center_x=(last_point_x+x) /2;
double center_y=(last_point_y+y) /2;
double ix=W_MATH::my_abs(x-last_point_x)/2;
double iy=W_MATH::my_abs(y-last_point_y)/2;

w_current_Gitem->w_set_rect( QRectF(-ix,-iy,ix*2,iy*2));
w_current_Gitem->setPos(center_x,center_y);

if (w_mouse_action==5) //click
{
w_click_count=0; // done.
G_scene->addItem(w_current_Gitem);
G_view->w_set_temp_item(0);
}
else
{ w_click_count++;
G_scene->invalidate(QRectF(x1,y1,xx,yy), QGraphicsScene::ForegroundLayer);
// x1,y1,xx,yy are the total scene limits.
return;
}

}




I need your help. Thanks

d_stranz
29th November 2011, 21:17
If I understand your description correctly, your problem is that you have a large number of static objects in your scene, and you want to be able to

1) dynamically add and position new items
2) move and resize existing items

without a redraw each time the item is changed.

Maybe this would work:

Create a scene (scene2) and a graphics view (view2) that are only used for editing dynamic objects. The scene2 has the same world coordinates and transformations as your real scene (scene1) and the view2 is the same size and position as the real view (view1). View2 has a transparent background, and sits on top of view1.

When you add a new item, it gets added to scene2 first. Since it is the only item in the scene, it can be moved around and sized without affecting anything else. When the user has stopped interacting with it (loses focus or after some short timeout), the item is removed from scene2 and added to scene1. Scene1 then paints itself once, and you can hide view2 if you want.

When you edit an existing item in scene1, make a copy and put it into scene2. Again, the user can make changes, and since it is the only item in scene2, view2 gets updated instantly. After editing, copy the new size, position, and other attributes to the item in scene1. Scene1 then paints once. (Or, instead of making a copy, move the item from scene1 to scene2, then put it back when done - this means 2 paints of view1 are required).

This is sort of the same idea as rubberband drawing - the rubberband is drawn in a separate widget with transparent background, exactly on top of the view underneath with the complex graphics. There is no need for pixmap or other backing store for the main view, because it is not touched when drawing to the widget that is on top.

tonnot
29th November 2011, 21:53
OK, I already had thought on this strategy. But I had the hope that it can be done applying some of I have explained,
Thanks any way !

d_stranz
29th November 2011, 22:49
Have you tried playing with the QGraphicsView::ViewportUpdateMode flags?

tonnot
30th November 2011, 09:31
Nothing of them work as I need .... (When i have 1000 items there is no problem, but with 100000 ... ).

I have make a suggestions to qt debug traker. Individual callers to drawforegroung, drawbackground and drawitemslayer.

Now you can only use :
QGraphicsView::paintEvent(event); and this throws allways 1:drawbackground 2:drawitemslayer. 3: drawforegroung,

The work can be done, but the actual situacion forces to write more code that it dould be needed..

Thanks again.