I have to make scrollbar with handle of fixed size since its background image becomes ugly when being scaled. I use the following style sheet:
QScrollBar::handle:vertical {
border-image:url(:/images/handle.png);
min-height: 47px;
max-height: 47px;
height: 47px;
width:10px;
}
but it seems like max-height isn't valid property. How to prevent handle scaling?
Little trick, from Qt source code:
myScrollbar.h
class myScrollBar : public QScrollBar
{
Q_OBJECT
public:
myScrollBar(Qt::Orientation orientation, QWidget *parent = 0);
void setSliderLength(int length);
protected:
void paintEvent(QPaintEvent *);
private:
QRect subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, /*const*/ QWidget *widget);
QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect);
int sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown);
private:
int _sliderLength;
};
myScrollbar.cpp
myScrollBar::myScrollBar(Qt::Orientation orientation, QWidget *parent)
: QScrollBar(orientation, parent),
_sliderLength(100)
{
}
void myScrollBar::paintEvent(QPaintEvent *e)
{
qDebug() << "scrollbar paintevent";
//Q_D(QScrollBar);
QScrollBar::paintEvent(e);
QPainter painter(this);
QStyleOptionSlider opt;
initStyleOption(&opt);
opt.subControls = QStyle::SC_All;
QWidget *widget = this;
// if (d->pressedControl) {
// opt.activeSubControls = (QStyle::SubControl)d->pressedControl;
// if (!d->pointerOutsidePressedControl)
// opt.state |= QStyle::State_Sunken;
// } else {
// opt.activeSubControls = (QStyle::SubControl)d->hoverControl;
// }
QPainter *p = &painter;
//style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p, this);
if (const QStyleOptionSlider *scrollbar = &opt) {
// Make a copy here and reset it for each primitive.
QStyleOptionSlider newScrollbar = *scrollbar;
QStyle::State saveFlags = scrollbar->state;
if (scrollbar->subControls & QStyle::SC_ScrollBarSubLine) {
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSubLine, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSubLine))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarSubLine, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarAddLine) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarAddLine, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarAddLine))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarAddLine, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarSubPage) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSubPage, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSubPage))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarSubPage, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarAddPage) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarAddPage, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarAddPage))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarAddPage, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarFirst) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarFirst, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarFirst))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarFirst, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarLast) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
newScrollbar.rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarLast, widget);
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarLast))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarLast, &newScrollbar, p, widget);
}
}
if (scrollbar->subControls & QStyle::SC_ScrollBarSlider) {
newScrollbar.rect = scrollbar->rect;
newScrollbar.state = saveFlags;
QRect rect = subControlRect(QStyle::CC_ScrollBar, &newScrollbar, QStyle::SC_ScrollBarSlider, widget);
newScrollbar.rect = QRect(rect.topLeft(), QSize(rect.width(), 100));
if (newScrollbar.rect.isValid()) {
if (!(scrollbar->activeSubControls & QStyle::SC_ScrollBarSlider))
newScrollbar.state &= ~(QStyle::State_Sunken | QStyle::State_MouseOver);
style()->drawControl(QStyle::CE_ScrollBarSlider, &newScrollbar, p, widget);
if (scrollbar->state & QStyle::State_HasFocus) {
QStyleOptionFocusRect fropt;
fropt.QStyleOption::operator=(newScrollbar);
fropt.rect.setRect(newScrollbar.rect.x() + 2, newScrollbar.rect.y() + 2,
newScrollbar.rect.width() - 5,
newScrollbar.rect.height() - 5);
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, p, widget);
}
}
}
}
}
void myScrollBar::setSliderLength(int length)
{
_sliderLength = length;
}
QRect myScrollBar::subControlRect(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, QStyle::SubControl sc, /*const*/ QWidget *widget)
{
QRect ret;
switch (cc) {
case QStyle::CC_ScrollBar:
if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
const QRect scrollBarRect = scrollbar->rect;
int sbextent = 0;
if (!style()->styleHint(QStyle::SH_ScrollBar_Transient, scrollbar, widget))
sbextent = style()->pixelMetric(QStyle::PM_ScrollBarExtent, scrollbar, widget);
int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
scrollBarRect.width() : scrollBarRect.height()) - (sbextent * 2);
int sliderlen;
// calculate slider length
if (scrollbar->maximum != scrollbar->minimum) {
uint range = scrollbar->maximum - scrollbar->minimum;
sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);
int slidermin = style()->pixelMetric(QStyle::PM_ScrollBarSliderMin, scrollbar, widget);
if (_sliderLength < slidermin || range > INT_MAX / 2)
_sliderLength = slidermin;
if (_sliderLength > maxlen)
_sliderLength = maxlen;
//length of the slider
sliderlen = _sliderLength;
} else {
sliderlen = maxlen;
}
int sliderstart = sbextent + this->sliderPositionFromValue(scrollbar->minimum,
scrollbar->maximum,
scrollbar->sliderPosition,
maxlen - sliderlen,
scrollbar->upsideDown);
switch (sc) {
case QStyle::SC_ScrollBarSubLine: // top/left button
if (scrollbar->orientation == Qt::Horizontal) {
int buttonWidth = qMin(scrollBarRect.width() / 2, sbextent);
ret.setRect(0, 0, buttonWidth, scrollBarRect.height());
} else {
int buttonHeight = qMin(scrollBarRect.height() / 2, sbextent);
ret.setRect(0, 0, scrollBarRect.width(), buttonHeight);
}
break;
case QStyle::SC_ScrollBarAddLine: // bottom/right button
if (scrollbar->orientation == Qt::Horizontal) {
int buttonWidth = qMin(scrollBarRect.width()/2, sbextent);
ret.setRect(scrollBarRect.width() - buttonWidth, 0, buttonWidth, scrollBarRect.height());
} else {
int buttonHeight = qMin(scrollBarRect.height()/2, sbextent);
ret.setRect(0, scrollBarRect.height() - buttonHeight, scrollBarRect.width(), buttonHeight);
}
break;
case QStyle::SC_ScrollBarSubPage: // between top/left button and slider
if (scrollbar->orientation == Qt::Horizontal)
ret.setRect(sbextent, 0, sliderstart - sbextent, scrollBarRect.height());
else
ret.setRect(0, sbextent, scrollBarRect.width(), sliderstart - sbextent);
break;
case QStyle::SC_ScrollBarAddPage: // between bottom/right button and slider
if (scrollbar->orientation == Qt::Horizontal)
ret.setRect(sliderstart + sliderlen, 0,
maxlen - sliderstart - sliderlen + sbextent, scrollBarRect.height());
else
ret.setRect(0, sliderstart + sliderlen, scrollBarRect.width(),
maxlen - sliderstart - sliderlen + sbextent);
break;
case QStyle::SC_ScrollBarGroove:
if (scrollbar->orientation == Qt::Horizontal)
ret.setRect(sbextent, 0, scrollBarRect.width() - sbextent * 2,
scrollBarRect.height());
else
ret.setRect(0, sbextent, scrollBarRect.width(),
scrollBarRect.height() - sbextent * 2);
break;
case QStyle::SC_ScrollBarSlider:
if (scrollbar->orientation == Qt::Horizontal)
ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height());
else
ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen);
break;
default:
break;
}
ret = visualRect(scrollbar->direction, scrollBarRect, ret);
}
return ret;
}
}
QRect myScrollBar::visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
{
if (direction == Qt::LeftToRight)
return logicalRect;
QRect rect = logicalRect;
rect.translate(2 * (boundingRect.right() - logicalRect.right()) +
logicalRect.width() - boundingRect.width(), 0);
return rect;
}
int myScrollBar::sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown)
{
if (span <= 0 || logicalValue < min || max <= min)
return 0;
if (logicalValue > max)
return upsideDown ? span : min;
uint range = max - min;
uint p = upsideDown ? max - logicalValue : logicalValue - min;
if (range > (uint)INT_MAX/4096) {
double dpos = (double(p))/(double(range)/span);
return int(dpos);
} else if (range > (uint)span) {
return (2 * p * span + range) / (2*range);
} else {
uint div = span / range;
uint mod = span % range;
return p * div + (2 * p * mod + range) / (2 * range);
}
// equiv. to (p * span) / range + 0.5
// no overflow because of this implicit assumption:
// span <= 4096
}
eg:
myScrollBar *bar = new myScrollBar(Qt::Vertical, ui->treeWidget);
ui->treeWidget->setVerticalScrollBar(bar);
Use
this jquery plugin http://jscrollpane.kelvinluck.com/
Related
So I've been making this program for our final project. It's a stopwatch and I added a ticking animation that ticks every second. The only problem I have is after I push the stop button,it doesn't go back to its original position. Here's the code :
#include "dialog.h"
#include "ui_dialog.h"
#include <QTimer>
#include <QPainter>
#include <QMessageBox>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(update()));
connect(timer,SIGNAL(timeout()),this,SLOT(tick()));
sec = 0;
sec2 = 0;
sec3 = 0;
setUpdatesEnabled(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_start_clicked()
{
timer->start(10);
}
void Dialog::on_stop_clicked()
{
sec = 0;
sec2 = 0;
sec3 = 0;
timer->stop();
ui->label->setNum(sec);
ui->label_2->setNum(sec2);
ui->label_3->setNum(sec3);
}
void Dialog::on_record_clicked()
{
if(sec == 0 && sec2 == 0 && sec3 == 0) {
QMessageBox msgbox;
msgbox.setText("Cannot record a zero");
msgbox.exec();
}
else
ui->listWidget->addItem(
ui->label_3->text() + ":" + ui->label_2->text()
+ ":" + ui->label->text());
}
void Dialog::on_clear_clicked()
{
ui->listWidget->clear();
}
void Dialog::tick()
{
sec++;
sec2++;
sec3++;
float x = sec * 0.01;
int y = sec2 / 6000;
int z = sec3 / 360000;
ui->label->setNum(x);
if(x == 60) {
sec = 0;
}
ui->label_2->setNum(y);
if(y == 60) {
sec2 = 0;
}
ui->label_3->setNum(z);
}
void Dialog::paintEvent(QPaintEvent *event)
{
QColor minuteColor(0, 127, 127, 191);
int side = qMin(width(), height());
painter = new QPainter(this);
painter->setRenderHint(QPainter::Antialiasing);
painter->translate(width() / 2, height() / 2);
painter->scale(side /350.0, side / 350.0);
painter->setPen(QPen(minuteColor));
painter->drawArc(QRect(-95, -95, 190, 190),90 * 16, 360 * 16);
painter->setPen(minuteColor);
for (int j = 0; j < 60; j++) {
painter->drawLine(92, 0, 96, 0);
painter->rotate(6.0);
}
painter->setPen(QPen(QColor(127, 0, 127,191),5));
painter->rotate(6.0 * sec * 0.01);
painter->drawLine(0, -92, 0, -96);
}
I have an arc inherited from QGraphicsItem, which is making use of virtual clone() to allow the editing operations i.e cut, copy and paste. When the arc is pasted/cloned it is displaced from the correct positions (using the context menu position). Here is my Arc class as well as the clone() function:
#include "arc.h"
#include "qmath.h"
#include <QPen>
#include <QPainterPath>
Arc::Arc(int i, QPointF point1, QPointF point2, QPointF point3)
{
id = i;
p1 = point1;
p2 = point2;
p3 = point3;
init();
}
int Arc::type() const
{
// Enable the use of qgraphicsitem_cast with arc item.
return Type;
}
Arc::Arc(QPointF point1, QPointF point2, QPointF point3)
{
p1 = point1;
p2 = point2;
p3 = point3;
p1 = QPointF(0,0);
p2 = QPointF(0,1);
p3 = QPointF(1,1);
init();
}
// Calculates startangle and spanangle
void Arc::init()
{
lineBC = QLineF(p2, p3);
lineAC = QLineF(p1, p3);
lineBA = QLineF(p2, p1);
rad = qAbs(lineBC.length()/(2 * qSin(qDegreesToRadians
(lineAC.angleTo(lineBA)))));
bisectorBC = QLineF(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
bisectorBA = QLineF(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
bisectorBA.intersect(bisectorBC, ¢er);
circle = QRectF(center.x() - rad, center.y() - rad, rad * 2, rad * 2);
lineOA = QLineF(center, p1);
lineOB = QLineF(center, p2);
lineOC = QLineF(center, p3);
startAngle = lineOA.angle();
spanAngle = lineOA.angleTo(lineOC);
/**
* Make sure that the span angle covers all three points with the
* second point in the middle
*/
if (qAbs(spanAngle) < qAbs(lineOA.angleTo(lineOB)) ||
qAbs(spanAngle) < qAbs(lineOB.angleTo(lineOC)))
{
// swap the end point and invert the spanAngle
startAngle = lineOC.angle();
spanAngle = 360 - spanAngle;
}
int w = 10;
boundingRectTemp = circle.adjusted(-w, -w, w, w);
}
QRectF Arc::boundingRect() const
{
// outer most edges
return boundingRectTemp;
}
void Arc::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QPen paintpen;
painter->setRenderHint(QPainter::Antialiasing);
paintpen.setWidth(1);
// Draw arc
if (isSelected())
{
// sets brush for end points
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
painter->drawEllipse(p1, 2, 2);
painter->drawEllipse(p2, 2, 2);
painter->drawEllipse(p3, 2, 2);
// sets pen for arc path
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
}
else
{
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawEllipse(p1, 2, 2);
painter->drawEllipse(p2, 2, 2);
painter->drawEllipse(p3, 2, 2);
}
QPainterPath path;
path.arcMoveTo(circle, startAngle);
path.arcTo(circle, startAngle, spanAngle);
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
getEntity *Arc::clone()
{
Arc *a = new Arc;
a->p1 = p1;
a->p2 = p2;
a->p3 = p3;
a->lineAC = AC;
a->lineBA = lineBA;
a->lineBC = lineBC;
a->lineOA = lineOA;
a->lineOB = lineOB;
a->lineOC = lineOC;
a->bisectorBA = bisectorBA;
a->bisectorBC = bisectorBC;
a->center = center;
a->circle = circle;
a->startAngle = startAngle;
a->spanAngle = spanAngle;
return a;
}
#ifndef GETENTITY_H
#define GETENTITY_H
#include <QGraphicsItem>
class getEntity : public QObject, public QGraphicsItem
{
public:
getEntity(QObject *parent = 0) : QObject(parent) {}
virtual ~getEntity() {}
virtual getEntity *clone(int i)
{
return 0;
}
int id;
};
#endif // GENTITY_H
There is a parent child relationship between two items. The child item which is a QGraphicsPixmapItem(image) was receiving all the events independently when rendered on the scene. But when I make a QGraphicsLineItem as its parent and rendered the image wrt parent item, I am unable to receive any event for the child. Please help, why is it happening?
My image item has events like hoverEnterEvent(), hoverLeaveEvent(), mouseMoveEvent() etc. Should all the events which are implemented in child item have a definition in parent too?
My parent does not have hoverEnterEvent() & hoverLeaveEvent(). I have also installed event filter on the child item. The parent item should receive all the events but it is not receiving any event at all. The important point to note is that I have rendered the image item wrt parent coordinate system. does it impact in any way. Please find the attached image.
Please find the child image item code below:
PersonSizeGraphicsItem::PersonSizeGraphicsItem(const QPixmap &pixmap, QGraphicsItem* parent_graphics_item, QGraphicsScene *scene)
:QGraphicsPixmapItem(pixmap, parent_graphics_item, scene),
parent_item(parent_graphics_item)
{
this->setParentItem(parent_item);
this->setFlag(QGraphicsItem::ItemIsMovable, true);
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
this->setFlag(QGraphicsItem::ItemIsFocusable, true);
this->setFocus(Qt::MouseFocusReason);
this->setAcceptHoverEvents(true);
//this->setScale(0.5);
rect_left_condition = false;
rect_right_condition = false;
rect_top_condition = false;
rect_bottom_condition = false;
rect_resize_occurred = false;
this->source_image = this->pixmap().toImage();
image_rect = QRect();
initializeImageRect();
}
PersonSizeGraphicsItem::~PersonSizeGraphicsItem()
{
}
int PersonSizeGraphicsItem::type() const
{
return item_type;
}
void PersonSizeGraphicsItem::initializeImageRect()
{
update();
}
void PersonSizeGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
const QPointF event_scene_pos = event->scenePos();
QPolygonF poly_rect = this->mapToParent(this->boundingRect());
qreal width = poly_rect.boundingRect().width();
qreal height = poly_rect.boundingRect().height();
// coordinates of item's bounding rect in scene coorinates.
QPointF _p1 = poly_rect.boundingRect().topLeft(); // (X,Y)
QPointF _p2 = poly_rect.boundingRect().topRight(); // (X + width,Y)
QPointF _p3 = poly_rect.boundingRect().bottomRight(); //(X+width, Y+height)
QPointF _p4 = poly_rect.boundingRect().bottomLeft(); //(X,Y+ height)
rect_left_condition = ( event_scene_pos.x() > ( _p1.x() - 5 ) && event_scene_pos.x() < ( _p1.x() + 5 ) );
rect_right_condition = ( event_scene_pos.x() > ( _p3.x() - 5 ) && event_scene_pos.x() < ( _p3.x() + 5 ) );
rect_top_condition = ( event_scene_pos.y() > ( _p1.y() - 5 ) && event_scene_pos.y() < ( _p1.y() + 5 ) );
rect_bottom_condition = ( event_scene_pos.y() > ( _p3.y() - 5 ) && event_scene_pos.y() < ( _p3.y() + 5 ) );
if( rect_left_condition || rect_right_condition )
{
this->setCursor(Qt::SizeHorCursor);
return;
}
if( rect_top_condition || rect_bottom_condition )
{
this->setCursor(Qt::SizeVerCursor);
return;
}
}
void PersonSizeGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
const QPointF event_scene_pos = event->scenePos();
QPolygonF poly_rect = this->mapToParent(this->boundingRect());
qreal width = poly_rect.boundingRect().width();
qreal height = poly_rect.boundingRect().height();
// coordinates of item's bounding rect in scene coorinates.
QPointF _p1 = poly_rect.boundingRect().topLeft(); // (X,Y)
QPointF _p2 = poly_rect.boundingRect().topRight(); // (X + width,Y)
QPointF _p3 = poly_rect.boundingRect().bottomRight(); //(X+width, Y+height)
QPointF _p4 = poly_rect.boundingRect().bottomLeft(); //(X,Y+ height)
bool horizontal_condition = (event_scene_pos.x() > ( _p1.x()+ 8)) && (event_scene_pos.x() < (_p3.x() -8) );
bool vertical_condition = (event_scene_pos.y() > ( _p1.y()+ 8)) && (event_scene_pos.y() < (_p3.y() -8) );
if( horizontal_condition && vertical_condition )
{
this->setCursor(Qt::SizeAllCursor);
}
}
void PersonSizeGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
this->setCursor(Qt::ArrowCursor);
rect_left_condition = false;
rect_right_condition = false;
rect_top_condition = false;
rect_bottom_condition = false;
QGraphicsItem::hoverLeaveEvent(event);
}
/*----------------------------------------------------------------------------------------------------*/
/* Purpose: method called when mouse is pressed on the graphics item */
/*--------------------------------------------------------------------------------------------------- */
void PersonSizeGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if( this->cursor().shape() == Qt::SizeAllCursor )
{
QMimeData * mimeData = new QMimeData;
PersonSizeGraphicsItem * item = this;
QByteArray byteArray(reinterpret_cast<char*>(&item),sizeof(PersonSizeGraphicsItem*));
mimeData->setData("Item",byteArray);
// start the event
QDrag * drag = new QDrag(event->widget());
drag->setMimeData(mimeData);
drag->exec();
// dragStart = event->pos();
event->accept();
}
}
void PersonSizeGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
const QPointF event_pos = event->pos();
const QPointF event_scene_pos = event->scenePos();
QPoint current_top_left = image_rect.topLeft();
QPoint current_bottom_right = image_rect.bottomRight();
if((event->scenePos().x() > this->scene()->width()) || (event->scenePos().y() > this->scene()->height())
|| (event->scenePos().x() < 0) || (event->scenePos().y() < 0) )
{
return;
}
if( this->cursor().shape() == Qt::SizeHorCursor )
{
if(rect_right_condition)
{
image_rect = QRect( current_top_left, QPoint( event->pos().x(), current_bottom_right.y()) );
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
}
if(rect_left_condition)
{
//image_rect = QRect( QPoint(event_pos.x(), 0), current_bottom_right );
image_rect = QRect( QPoint(event_pos.x(), current_top_left.y()), current_bottom_right );
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
}
}
if( this->cursor().shape() == Qt::SizeVerCursor )
{
if(rect_bottom_condition)
{
image_rect = QRect(current_top_left, QPoint(current_bottom_right.x(), event->pos().y()));
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
}
if(rect_top_condition)
{
image_rect = QRect(QPoint(current_top_left.x(), event_pos.y()), current_bottom_right);
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
/* QPoint new_top_left = image_rect.topLeft();
QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
this->setPos(mapped_topLeft); */
rect_resize_occurred = true;
}
}
this->update();
}
void PersonSizeGraphicsItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
CustomGraphicsLineItem* parent_line_item = dynamic_cast<CustomGraphicsLineItem *>(parent_item);
if(parent_line_item == NULL)
{
return;
}
painter->setRenderHint(QPainter::Antialiasing);
QLineF parent_line = parent_line_item->line();
QLineF normal_vector_line = parent_line.normalVector();
normal_vector_line.setLength(20.0);
QPointF first_line_base_point = parent_line.pointAt(0.5);
QPointF _p1 = first_line_base_point -(normal_vector_line.p1()-normal_vector_line.p2());
QPointF _p2 = first_line_base_point +(normal_vector_line.p1()-normal_vector_line.p2());
QLineF rect_line_one = normal_vector_line;
rect_line_one.setP1(_p1);
rect_line_one.setP2(_p2);
qDebug() << "rect_line_one p1:" << rect_line_one.p1();
qDebug() << "rect_line_one p2:" << rect_line_one.p2();
QRectF image_rect( rect_line_one.p1(), QSize(30, 60));
painter->drawImage(image_rect, source_image);
}
QRectF PersonSizeGraphicsItem:: boundingRect() const
{
qreal extra = 0.0;
QRect rect = image_rect;
return QRectF(rect.topLeft(), QSizeF(rect.width(), rect.height()))
.normalized()
.adjusted(-extra, -extra, extra, extra);
}
QPainterPath PersonSizeGraphicsItem::shape() const
{
const int adjustment = 0.0;
QPainterPath path;
QRectF rect = boundingRect();
path.addRect(rect.adjusted(-adjustment, -adjustment, adjustment, adjustment));
return path;
}
I have a png image which is displayed on the graphics scene as a QGraphicsPixmapItem.
The image is rectangular in shape. I need to resize the png image every time it is dragged by a mouse move event on any side of the rectangle ie, from left,right,top or bottom.
Currently I am able to resize the image only when dragged from right and bottom sides only. Image resizing fails when dragged from left and top side. Please let me know the mistakes in my code below. Here Resizing is based on original image file which is of maximum size, but the initial image displayed on the scene itself is a scaled down version of source image.
The partial code is posted below, I have not shown hoverEnterEvent() implementation:
PersonSizeGraphicsItem::PersonSizeGraphicsItem(const QPixmap &pixmap, QGraphicsScene *scene)
:QGraphicsPixmapItem(pixmap, 0, scene)
{
this->setFlag(QGraphicsItem::ItemIsMovable, true);
this->setFlag(QGraphicsItem::ItemIsSelectable, true);
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
this->setFlag(QGraphicsItem::ItemIsFocusable, true);
this->setFocus(Qt::MouseFocusReason);
this->setAcceptHoverEvents(true);
//this->setScale(0.5);
rect_left_condition = false;
rect_right_condition = false;
rect_top_condition = false;
rect_bottom_condition = false;
rect_resize_occurred = false;
image_rect = QRect();
image_rect = this->pixmap().toImage().rect();
}
PersonSizeGraphicsItem::~PersonSizeGraphicsItem()
{
}
int PersonSizeGraphicsItem::type() const
{
return item_type;
}
void PersonSizeGraphicsItem::setSourceImage(const QImage& source_image)
{
this->source_image = source_image;
}
void PersonSizeGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
const QPointF event_pos = event->pos();
const QPointF event_scene_pos = event->scenePos();
QPoint current_top_left = image_rect.topLeft();
QPoint current_bottom_right = image_rect.bottomRight();
if((event->scenePos().x() > this->scene()->width()) || (event->scenePos().y() > this->scene()->height())
|| (event->scenePos().x() < 0) || (event->scenePos().y() < 0) )
{
return;
}
if( this->cursor().shape() == Qt::SizeHorCursor )
{
if(rect_right_condition)
{
image_rect = QRect( current_top_left, QPoint( event->pos().x(), current_bottom_right.y()) );
rect_resize_occurred = true;
}
if(rect_left_condition)
{
image_rect = QRect( QPoint(event_pos.x(), 0), current_bottom_right );
QPoint new_top_left = image_rect.topLeft();
QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
this->setPos(mapped_topLeft);
rect_resize_occurred = true;
//qDebug() << "new rectangle top left:" << this->pixmap().rect().topLeft();
}
}
if( this->cursor().shape() == Qt::SizeVerCursor )
{
if(rect_bottom_condition)
{
image_rect = QRect(current_top_left, QPoint(current_bottom_right.x(), event->pos().y()));
rect_resize_occurred = true;
}
if(rect_top_condition)
{
image_rect = QRect(QPoint(0, event_pos.y()), current_bottom_right);
QPoint new_top_left = image_rect.topLeft();
QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
this->setPos(mapped_topLeft);
qDebug() << "new rectangle top left###:" << this->pixmap().rect().topLeft();
rect_resize_occurred = true;
}
}
this->update();
}
void PersonSizeGraphicsItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(image_rect, source_image);
}
QRectF PersonSizeGraphicsItem:: boundingRect() const
{
qreal extra = 0.0;
QRect rect = image_rect;
return QRectF(rect.topLeft(), QSizeF(rect.width(), rect.height()))
.normalized()
.adjusted(-extra, -extra, extra, extra);
}
I tried the following code to resize the rectangle and it works. In the earlier version of mouseMoveEvent(), I always tried to smehow set the topLeft coordinates to (0,0) each time after resize is done.
In the new version, I let the topLeft coordinates remain where they are and not bother to set the topLeft to (0,0) after each resize. Once the resize is done, the topLeft is never set to origin here in local coordinates.
void PersonSizeGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
const QPointF event_pos = event->pos();
const QPointF event_scene_pos = event->scenePos();
QPoint current_top_left = image_rect.topLeft();
QPoint current_bottom_right = image_rect.bottomRight();
if((event->scenePos().x() > this->scene()->width()) || (event->scenePos().y() > this->scene()->height())
|| (event->scenePos().x() < 0) || (event->scenePos().y() < 0) )
{
return;
}
if( this->cursor().shape() == Qt::SizeHorCursor )
{
if(rect_right_condition)
{
image_rect = QRect( current_top_left, QPoint( event->pos().x(), current_bottom_right.y()) );
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
}
if(rect_left_condition)
{
//image_rect = QRect( QPoint(event_pos.x(), 0), current_bottom_right );
image_rect = QRect( QPoint(event_pos.x(), current_top_left.y()), current_bottom_right );
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
/* QPoint new_top_left = image_rect.topLeft();
QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
this->setPos(mapped_topLeft); */
//qDebug() << "new rectangle top left:" << this->pixmap().rect().topLeft();
}
}
if( this->cursor().shape() == Qt::SizeVerCursor )
{
if(rect_bottom_condition)
{
image_rect = QRect(current_top_left, QPoint(current_bottom_right.x(), event->pos().y()));
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
rect_resize_occurred = true;
}
if(rect_top_condition)
{
//image_rect = QRect(QPoint(0, event_pos.y()), current_bottom_right);
image_rect = QRect(QPoint(current_top_left.x(), event_pos.y()), current_bottom_right);
if( image_rect.width() <=8 || image_rect.height() <=24 )
{
return;
}
/* QPoint new_top_left = image_rect.topLeft();
QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
this->setPos(mapped_topLeft); */
rect_resize_occurred = true;
}
}
this->update();
}
I'm having a dilemma with this code and have no clue what to do. I'm pretty new to processing. This is a project from this link...
http://blog.makezine.com/2012/08/10/build-a-touchless-3d-tracking-interface-with-everyday-materials/
any help is massively appreciated... Thanks in advance
import processing.serial.*;
import processing.opengl.*;
Serial serial;
int serialPort = 1;
int sen = 3; // sensors
int div = 3; // board sub divisions
Normalize n[] = new Normalize[sen];
MomentumAverage cama[] = new MomentumAverage[sen];
MomentumAverage axyz[] = new MomentumAverage[sen];
float[] nxyz = new float[sen];
int[] ixyz = new int[sen];
float w = 256; // board size
boolean[] flip = {
false, true, false};
int player = 0;
boolean moves[][][][];
PFont font;
void setup() {
size(800, 600, P3D);
frameRate(25);
font = loadFont("TrebuchetMS-Italic-20.vlw");
textFont(font);
textMode(SCREEN);
println(Serial.list());
serial = new Serial(this, Serial.list()[serialPort], 115200);
for(int i = 0; i < sen; i++) {
n[i] = new Normalize();
cama[i] = new MomentumAverage(.01);
axyz[i] = new MomentumAverage(.15);
}
reset();
}
void draw() {
updateSerial();
drawBoard();
}
void updateSerial() {
String cur = serial.readStringUntil('\n');
if(cur != null) {
String[] parts = split(cur, " ");
if(parts.length == sensors) {
float[] xyz = new float[sen];
for(int i = 0; i < sen; i++)
xyz[i] = float(parts[i]);
if(mousePressed && mouseButton == LEFT)
for(int i = 0; i < sen; i++)
n[i].note(xyz[i]);
nxyz = new float[sen];
for(int i = 0; i < sen; i++) {
float raw = n[i].choose(xyz[i]);
nxyz[i] = flip[i] ? 1 - raw : raw;
cama[i].note(nxyz[i]);
axyz[i].note(nxyz[i]);
ixyz[i] = getPosition(axyz[i].avg);
}
}
}
}
float cutoff = .2;
int getPosition(float x) {
if(div == 3) {
if(x < cutoff)
return 0;
if(x < 1 - cutoff)
return 1;
else
return 2;
}
else {
return x == 1 ? div - 1 : (int) x * div;
}
}
void drawBoard() {
background(255);
float h = w / 2;
camera(
h + (cama[0].avg - cama[2].avg) * h,
h + (cama[1].avg - 1) * height / 2,
w * 2,
h, h, h,
0, 1, 0);
pushMatrix();
noStroke();
fill(0, 40);
translate(w/2, w/2, w/2);
rotateY(-HALF_PI/2);
box(w);
popMatrix();
float sw = w / div;
translate(h, sw / 2, 0);
rotateY(-HALF_PI/2);
pushMatrix();
float sd = sw * (div - 1);
translate(
axyz[0].avg * sd,
axyz[1].avg * sd,
axyz[2].avg * sd);
fill(255, 160, 0);
noStroke();
sphere(18);
popMatrix();
for(int z = 0; z < div; z++) {
for(int y = 0; y < div; y++) {
for(int x = 0; x < div; x++) {
pushMatrix();
translate(x * sw, y * sw, z * sw);
noStroke();
if(moves[0][x][y][z])
fill(255, 0, 0, 200);
else if(moves[1][x][y][z])
fill(0, 0, 255, 200);
else if(
x == ixyz[0] &&
y == ixyz[1] &&
z == ixyz[2])
if(player == 0)
fill(255, 0, 0, 200);
else
fill(0, 0, 255, 200);
else
fill(0, 100);
box(sw / 3);
popMatrix();
}
}
}
fill(0);
if(mousePressed && mouseButton == LEFT)
msg("defining boundaries");
}
void keyPressed() {
if(key == TAB) {
moves[player][ixyz[0]][ixyz[1]][ixyz[2]] = true;
player = player == 0 ? 1 : 0;
}
}
void mousePressed() {
if(mouseButton == RIGHT)
reset();
}
void reset() {
moves = new boolean[2][div][div][div];
for(int i = 0; i < sen; i++) {
n[i].reset();
cama[i].reset();
axyz[i].reset();
}
}
void msg(String msg) {
text(msg, 10, height - 10);
}
You are missing a class, in fact, more than one. Go back to the github and download, or copy and paste, all three codes, placing each one in a new tab named same name of the class (well this is not required, but is a good practice). The TicTacToe3D.pde is the main code. To make a new tab choose "new tab" from the arrow menu in Processing IDE (just below the standard button at the right). The code should run. WIll need an Arduino though to really get it working.