PDA

View Full Version : uni-planar drag'n'drop



georgie
17th May 2006, 07:38
I need to have a double headed slider
i've searched all over for ideas on how to make this by reimplementing qslider, but there just seems to be a bunch of people who have needed this and all have given up and i don't understand the majority of the proposed solutions
my idea tho, was to build my own very simple one from scratch....I would have basically 2 drag'n'drop widgets on top of a background (i don't think the background would be very hard to draw at all)....but the problem is, even if i set the background widget to only accept drops on a narrow, vertical axis....it would still be possible to
1)move the slider very slightly left to right and
2) drag the head left and right even though the drop would not be accepted there - the forbidden cursor would just appear

is there any way to limit the drag and drop functions to only look at the change in y location of the mouse and completely ignore the x movement? so if i drag the slider head to the upper left corner of the screen, it will only move directly upwards....

wysota
17th May 2006, 12:08
This is not the way to go...

I would subclass QSlider, add appropriate methods and reimplement its paintEvent. Unfortunately QSlider used drawComplexControl(QStyle::CC_Slider, ...) to draw the slider but this shouldn't stop you. You should probably use QStyleOptionSlider like QSlider uses it and call drawComplexControl twice -- once for each handle. First time with opt.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle and the other time only with QStyle::SC_SliderHandle.

I implemented the drawing for you. Looks fine for me. What still needs to be implemented is dragging the other handle (reimplement mousePress, mouseMove and maybe mouseRelease for that).

georgie
18th May 2006, 06:28
genius :)
thx
sometimes i look too hard for a solution and end up coming from a completely ridiculous direction :P

georgie
18th May 2006, 14:49
*WARNING* - this solution is a massive hack job....but so far it is kinda doing what i want it to...just not 100%....clicking on the slider to get either of the heads is fine, but there is something wrong with my mouseMoveEvent.....i can't get it to let you drag the heads.....the code i am posting has been added to the soln given by wysota pretty much as-is.....his (oooh...bad assumptions I know....but for the ease of referral i'll go with "he" unless i know otherwise.....) repaint is exactly what I needed


i have not reimplemented mouseReleaseEvent because i can't see how it would help

I have created my own style to allow reimplementation of drawComplexControl (complex is right :P)





//mousePressEvent works OK
void DoubleSlider::mousePressEvent(QMouseEvent *ev)
{
int newPosition = this->pixelPosToRangeValue(ev->pos().y());
emit newPos(newPosition);
bool closerMax = (qAbs((newPosition-this->value()))>qAbs((this->maximum()-newPosition-this->secondVal)));
//find out if the click was closer to the max or min slider head to know which one to move
//this is also useful because it means you cannot get the minimum head to go above the
//maximum one --> in my drawComplexControl I have managed to get the heads drawn in
//different colours
emit closer(closerMax);
if(closerMax)
{
this->secondVal = this->maximum()-newPosition;
}
else
{
this->setValue(newPosition);
}
this->update();

if (this->pressedControl == QStyle::SC_SliderHandle)
setSliderDown(true);
this->snapBackPosition = this->position;
}

//mouseMoveEvent does not seem to do anything :(
void DoubleSlider::mouseMoveEvent(QMouseEvent *ev)
{
if (this->pressedControl != QStyle::SC_SliderHandle || (ev->buttons() & Qt::RightButton)) {
ev->ignore();
return;
}
ev->accept();
int newPosition = this->pixelPosToRangeValue(ev->pos().y());
emit newPos(newPosition);
bool closerMax = (qAbs((newPosition-this->value()))>qAbs((this->maximum()-newPosition-this->secondVal)));
emit closer(closerMax);

QStyleOptionSlider opt = this->getStyleOption();
int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
if (m >= 0) {
QRect r = rect();
r.adjust(-m, -m, m, m);

if (!r.contains(ev->pos()))
newPosition = this->snapBackPosition;
}
if(closerMax)
{
this->secondVal = this->maximum()-newPosition;
}
else
{
this->setValue(newPosition);
}
repaint();
}




if you have any suggestions that would be super
when i have the class of double headed slider worked out nicely - maybe with a flexible style - i'll upload it here because it seems like something a few ppl have wanted in the past and never really sorted out.....

wysota
18th May 2006, 16:02
[B]clicking on the slider to get either of the heads is fine, but there is something wrong with my mouseMoveEvent.....i can't get it to let you drag the heads.....
Because you should store information which head is dragged in the mousePressEvent first and then use that information in mouseMoveEvent to actually drag the handle.


the code i am posting has been added to the soln given by wysota pretty much as-is.....his (oooh...bad assumptions I know....but for the ease of referral i'll go with "he" unless i know otherwise.....)
"he" is fine :)


i have not reimplemented mouseReleaseEvent because i can't see how it would help
You'll need it to mark that the handle has been released.


I have created my own style to allow reimplementation of drawComplexControl (complex is right :P)
Do you really need it? Maybe it's enough to play a little with style options?


if you have any suggestions that would be super
Yeah, I do :)

Things to do in mousePress:
1. check if handle was clicked and store that information in some variable
2. check if groove was clicked and move appropriate slider

Things to do in mouseMove:
1. If a slider handle was clicked in mousePress -- change its position to the value pointed by the current event position
2. ignore the event otherwise

Things to do in mouseRelease:
1. If a slider handle was clicked in mousePress, mark that it's not pressed anymore.


when i have the class of double headed slider worked out nicely - maybe with a flexible style
It shouldn't depend on a style. People use different styles.


- i'll upload it here because it seems like something a few ppl have wanted in the past and never really sorted out.....
Personally I'd probably use two spinboxes instead :)

georgie
19th May 2006, 10:16
"he" is fine :)

haha....I went to one of those psycho girls schools where they churn out little feminist brats and it is hard to break those habits :P


Do you really need it? Maybe it's enough to play a little with style options?

I have very very specific "look and feel" requirements....as far as I can tell it was necessary to deal with drawComplexControl....but i am never one to use the easy option if there is some stupid way of doing it that would work not nearly as well :P


Personally I'd probably use two spinboxes instead :)

I'm sure it isn't that important for most people, but i remember reading at least a couple of threads about people needing this kinda stuff before....maybe it was at QtForum??...and like i said - i have v specific requirements

i've put the double slider code up....there is some stuff in there that is specific to my needs - like it's a strict max/min (you can't drag the one below the one above) etc....but that should be trivial to change if anybody needs it....and it doesn't take much space if nobody needs it