Название: Отловить клик в нужный сектор
Отправлено: Пантер от Июль 25, 2012, 22:40
Вот код класса: h C++ (Qt) #ifndef SHEDULEINDICATOR_H #define SHEDULEINDICATOR_H #include <QtCore/QMap> #include <QtGui/QWidget> class SheduleIndicator : public QWidget { Q_OBJECT public: explicit SheduleIndicator (QWidget *parent = 0); void setShedule (const QMap <int, bool> &shedule) { shedule_ = shedule; drawImage(); } protected: virtual void showEvent (QShowEvent *); virtual void paintEvent (QPaintEvent *event); private: void drawImage (); private: QMap <int, bool> shedule_; QPixmap image_; }; #endif //SHEDULEINDICATOR_H
cpp C++ (Qt) #include <QtCore/QTimer> #include <QtCore/QTime> #include <QtGui/QPainter> #include <QRadialGradient> #include <QLinearGradient> #include <QConicalGradient> #include "sheduleindicator.h" enum {UpdateInterval = 1000 * 60 * 1}; SheduleIndicator::SheduleIndicator (QWidget *parent) : QWidget (parent) { QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), SLOT (update())); timer->start (UpdateInterval); } void SheduleIndicator::drawImage () { image_ = QPixmap (size ()); image_.fill (Qt::transparent); const int side = qMin (width(), height()); QPainter painter; painter.begin (&image_); painter.setRenderHint (QPainter::Antialiasing); painter.translate (width() / 2, height() / 2); painter.scale (side / 200.0, side / 200.0); const int radius = 65; const int width = 30; const QRect rectangle (-radius, -radius, radius * 2, radius * 2); static const QColor insideColor (Qt::darkGray); static const QColor offColor (QColor (195, 195, 195)); static const QColor onColor (QColor (228, 131, 16)); static const QColor foreGroundColor (QColor (95, 95, 105)); static const QColor digitsColor (QColor (195, 195, 195)); static const QColor edgeColor (QColor (26, 26, 26)); painter.setPen (QPen (edgeColor, 1)); painter.setBrush (Qt::NoBrush); painter.drawEllipse (QPoint (0, 0), radius + width / 2, radius + width / 2); painter.drawEllipse (QPoint (0, 0), radius - width / 2, radius - width / 2); QPen sectionPen; sectionPen.setWidth (width); sectionPen.setCapStyle (Qt::FlatCap); for (int i = 0; i < 24; ++i) { QRadialGradient circle (0, 0, radius + width / 2, 0, 0); circle.setColorAt (0.0, insideColor); circle.setColorAt (0.62, insideColor); circle.setColorAt (0.63, foreGroundColor); circle.setColorAt (shedule_ [i] ? 0.68 : 0.65, shedule_ [i] ? onColor : offColor); circle.setColorAt (shedule_ [i] ? 0.95 : 0.98, shedule_ [i] ? onColor : offColor); circle.setColorAt (1.0, foreGroundColor); sectionPen.setBrush (circle); painter.setPen (sectionPen); painter.drawArc (rectangle, 75 * 16, 15 * 16); painter.rotate (15); } painter.setPen (QPen (foreGroundColor, 1)); for (int i = 0; i < 24; i++) { painter.drawLine (0, radius - width / 2, 0, radius + width / 2); painter.rotate (15); } painter.setBrush (insideColor); painter.setPen (insideColor); painter.drawEllipse (QPoint (0, 0), radius - width / 2 - 1, radius - width / 2 - 1); // Digits const QRectF rectangle1 (-100.0, -100.0, 200.0, 200.0); painter.setPen (digitsColor); painter.drawText (rectangle1, Qt::AlignTop | Qt::AlignHCenter, "0"); painter.drawText (rectangle1, Qt::AlignBottom | Qt::AlignHCenter, "12"); painter.drawText (rectangle1, Qt::AlignLeft | Qt::AlignVCenter, "18"); painter.drawText (rectangle1, Qt::AlignRight | Qt::AlignVCenter, "6 "); painter.end(); } void SheduleIndicator::showEvent (QShowEvent *e) { QWidget::showEvent (e); drawImage(); } void SheduleIndicator::paintEvent (QPaintEvent *) { const int side = qMin (width(), height()); QPainter painter (this); painter.drawPixmap (QPoint (0, 0), image_); painter.setRenderHint (QPainter::Antialiasing); painter.translate (width() / 2, height() / 2); painter.scale (side / 200.0, side / 200.0); static const QPointF p0 (0, 10); static const QPointF p1 (5, 5); static const QPointF p2 (0.5, -70); static const QPointF p3 (-0.5, -70); static const QPointF p4 (-5, 5); static const QPointF hourHand [5] = {p0, p1, p2, p3, p4}; painter.setPen (Qt::NoPen); // Hand painter.save(); const QTime time = QTime::currentTime(); painter.translate (QPoint (-2, 2));; painter.rotate (15.0 * (time.hour() + time.minute() / 60.0)); painter.setBrush (QColor (0x40, 0x40, 0x40, 100)); painter.drawConvexPolygon (hourHand, 5); painter.rotate (-15.0 * (time.hour() + time.minute() / 60.0)); painter.translate (QPoint (2, -2));; painter.rotate (15.0 * (time.hour() + time.minute() / 60.0)); QLinearGradient handGradient (p1, p4); handGradient.setColorAt (0.0, Qt::blue); handGradient.setColorAt (0.5, Qt::darkBlue); handGradient.setColorAt (1.0, Qt::blue); painter.setBrush (handGradient); painter.drawConvexPolygon (hourHand, 5); painter.restore(); // hand pin QRadialGradient handCircle (0, 0, 4, 0, 0); handCircle.setColorAt (0.0, Qt::white); handCircle.setColorAt (1.0, Qt::darkBlue); painter.setBrush (handCircle); painter.drawEllipse (QPoint (0, 0), 4, 4); }
На картинке то, что отображается. Возникла необходимость отследить клик мыши и определить сектор, по которому кликнули. С рисованием и геометрией плохо, посему прошу помощи.
Название: Re: Отловить клик в нужный сектор
Отправлено: pastor от Июль 25, 2012, 22:57
Как вариарт можно попробовоть так: 1) От точки клика строим отрезок к центру и определем его длину. 2) Длина отрезка должна быть меньше\равна радиуса внешней окружности и больше\равна внутренней. 3) Определяем угол наклона отрезка, допустим к оси Х. 4) Полученный угол сравниваем с углами наклона радиусов сектора
Название: Re: Отловить клик в нужный сектор
Отправлено: DmitryM от Июль 26, 2012, 09:48
1. переводишь координаты курсора в полярные координаты с центром в окружности. 2. проверяешь длину радиус-вектора 3. делишь угол на 2*pi/N, где N число секторов, получаешь номер нужного сектора.
Название: Re: Отловить клик в нужный сектор
Отправлено: Igors от Июль 27, 2012, 09:43
C++ (Qt) int GetSector( const QPoint & locMouse, const QPoint & center, int num = 12 ) { QPoint delta = locMouse - center; qreal angle = atan2(-delta.y(), delta.x()); // в экранных координатах y идет вниз, поэтому y с минусом static const qreal PI2 = 3.141592 * 2; if (angle < 0) angle += PI2; return (int) (angle / PI2 * num); }
atan2 возвращает угол с осью X, отсчитываемый против часовой стрелки. Сектор 0 будет "на 3 часа", сектор 1 на 2 часа и.т.д. Если надо перевести в "обычные часы" можно напр так C++ (Qt) sector = ((12 - sector) + 3) % 12;
Название: Re: Отловить клик в нужный сектор
Отправлено: DmitryM от Июль 27, 2012, 10:00
из описание atan2 y Floating point value representing an y-coordinate. x Floating point value representing an x-coordinate. If both arguments passed are zero, a domain error occurs, which sets the global variable ERRNO to the EDOM value.
Название: Re: Отловить клик в нужный сектор
Отправлено: Пантер от Июль 29, 2012, 15:32
Фухх. Сделал. Правда, с точки зрения математики, все плохо (я так думаю), но меня устроило. C++ (Qt) void SheduleIndicator::mousePressEvent (QMouseEvent *e) { if (mode_ != Edit) { return; } const QPoint center (width () / 2, height () / 2); const QPoint point (e->pos ().x ()- center.x (), center.y () - e->pos ().y ()); const int distance = qSqrt (qPow ((center.x () - e->pos ().x ()), 2) + qPow ((center.y () - e->pos ().y ()), 2)); if (distance >= RMin && distance <= RMax) { qreal angle = qAcos (point.y () / qSqrt (qPow (point.x (), 2) + qPow (point.y (), 2))); if (point.x () < 0) { angle = 2 * M_PI - angle; } const int i = angle / (2 * M_PI / 24); shedule_ [i] = !shedule_ [i]; emit sheduleChanged (); drawImage (); repaint (); } }
Название: Re: Отловить клик в нужный сектор
Отправлено: Igors от Июль 29, 2012, 16:23
Фухх. Сделал. Правда, с точки зрения математики, все плохо (я так думаю), Правильно думаете :) А вообще Qt классы очень плохо приспособлены для инженерных расчетов, даже простых
|