You are not logged in.

1

Wednesday, November 16th 2011, 6:21pm

Fixed scale/position QSlider inside QGraphicsScene jumps as scale changes

I'm attempting to create a Slider control in a QGraphicsScene using a QProxyWidget (via addWidget()) and I want the Slider to ignore the transformations AND stay at a fixed location in the QGraphicsView. The slider is intended to control the zooming (scaling) of the QGraphicsView.

I have it working (partially), but as you move the QSlider the position of the knob jumps around to positions other than the position the mouse is pointing too. It returns the correct values and eventually repositions itself under the mouse.

I am subclassing QGraphicsView and connecting the ValueChanged of the slider to a method in that subclass. That method calls scale() on the QGraphcisView. It was generating a recursive loop due to the scaling triggering another ValueChanged() for the slider, so I used blockSignals() on the slider to avoid the recursion. As I said, it works, but the slider knob jumps around as if the position is recalculated during scaling even though I have set the flag of the proxy object for ItemIgnoresTransformations. The code looks a little but like this...

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void MGraphicsView::paintEvent(QPaintEvent *event)
{
	// Prevent the Slider from moving...
	if(m_proxyOverlay) m_proxyOverlay->setPos(mapToScene(0,0));
	QGraphicsView::paintEvent(event);
}


void MGraphicsView::setScene(QGraphicsScene *thescene)
{ 
	// Add the slider once my scene is set...
	if(scene() != thescene && thescene != NULL) {

QGraphicsView::setScene(thescene);

slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 10);
slider->setSingleStep(1);
slider->setFixedSize(200, 20);
slider->setMaximumSize(200, 20);
slider->setMinimumSize(200, 20);

slider->setValue(0);
slider->setStyleSheet("background-color: transparent;");

connect(slider, SIGNAL(valueChanged(int)), this, SLOT(zoomSlider(int)));

m_proxyOverlay = thescene->addWidget(slider);
m_proxyOverlay->setZValue(2);

m_proxyOverlay->setFlag(QGraphicsItem::ItemIsMovable, true);
m_proxyOverlay->setFlag(QGraphicsItem::ItemIgnoresTransformations);
m_proxyOverlay->setPos( mapToScene(0,0) );
	} else {
QGraphicsView::setScene(thescene);
	}
}

void MGraphicsView::zoomSlider(int val)
{
float zoomfactor;

	if(val == 0) {
zoomfactor = 1.0f;
	} else {
zoomfactor = 1.0f + (val * 0.5f);
	}

	// Prevent recursion during scale call...
	slider->blockSignals(true);
resetMatrix();
scale(zoomfactor, zoomfactor);
	slider->blockSignals(false);
}

I've accomplished most of what I desired. The control itself does not move or resize during scaling or scrolling of the View. It properly zooms the scene using the scale() call. However, the knob of the slider jumps around as you drag it as if scaling is being factored into its positioning.

I would be grateful if someone has an idea for avoiding this without writing my own control. Thanks....

2

Thursday, November 17th 2011, 6:10pm

For the moment, I've moved the widget from the Scene to the View as a child widget, but I'm afraid this is going to limit my ability to use GL acceleration in the view. I've read a number of threads suggesting as much, and I am using GL in other places where the drawing performance was the bottleneck. I expect that at some point I'll need that for this view.