继承了QQuickPaintedItem
并包含QwtPlot
的类(为了在QML中使用它):
class QmlQwtPlot : public QQuickPaintedItem
{
Q_OBJECT
public:
QmlQwtPlot(QQuickItem* parent = 0);
~QmlQwtPlot();
void paint(QPainter *painter) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent *event) override;
private:
QwtPlot* qwtPlot;
QwtPlotPanner* panner;
bool isDragging;
QPoint previousPosition;
QwtPlotPicker* picker;
};
例如,通过使用鼠标事件处理和QwtPlotPanner
信号实现平移绘图:
void QmlQwtPlot::mouseMoveEvent(QMouseEvent* event) {
if (isDragging) { // if the mouse button has been pressed
QPoint currentPosition = event->pos();
QPoint diff = currentPosition - previousPosition;
emit panner->panned(diff.x(),diff.y());
previousPosition = event->pos();
update();
}
}
QwtPlotPicker
是一个Qwt库类,可在绘图画布上提供选择。使用QwtPlotPicker
QWidget
效果很好(带有x,y坐标的光标和带光标的交叉线)QQuickPaintedItem
,但它不能与/* QWidget's child constructor (the same is in QQuickPaintedItem's one) */
PlottingWidget::PlottingWidget(QWidget *parent)
: QWidget(parent)
{
// ...
d_picker = new QwtPlotPicker(
QwtPlot::xBottom, QwtPlot::yLeft,
QwtPlotPicker::CrossRubberBand,
QwtPicker::AlwaysOn,
plot->canvas()
);
d_picker->setRubberBandPen( QColor( Qt::red ) );
d_picker->setTrackerPen( QColor( Qt::black ) );
d_picker->setStateMachine( new QwtPickerTrackerMachine() );
// ...
}
一起使用不同的工作原则。
QwtPlotPicker
如何强制QQuickPaintedItem
使用public class MapRipple {
private GoogleMap mGoogleMap;
private LatLng mLatLng, mPrevLatLng;
private BitmapDescriptor mBackgroundImageDescriptor;
private float mTransparency = 0.5f;
private volatile double mDistance = 100;
private int mNumberOfRipples = 1;
private int mFillColor = Color.TRANSPARENT;
private int mStrokeColor = Color.BLACK;
private int mStrokeWidth = 5;
private long mDurationBetweenTwoRipples = 1000;
private long mRippleDuration = 2000;
private ValueAnimator mAnimators[];
private Handler mHandlers[];
private GroundOverlay mGroundOverlays[];
private GradientDrawable mBackground;
private boolean isAnimationRunning = false;
public MapRipple(GoogleMap googleMap, LatLng latLng, Context context) {
mGoogleMap = googleMap;
mLatLng = latLng;
mPrevLatLng = latLng;
mBackground = (GradientDrawable) ContextCompat.getDrawable(context, R.drawable.map_background);
mAnimators = new ValueAnimator[4];
mHandlers = new Handler[4];
mGroundOverlays = new GroundOverlay[4];
}
public MapRipple withTransparency(float transparency) {
mTransparency = transparency;
return this;
}
public MapRipple withDistance(double distance) {
mDistance = distance;
return this;
}
public MapRipple withLatLng(LatLng latLng) {
mPrevLatLng = mLatLng;
mLatLng = latLng;
return this;
}
public MapRipple withNumberOfRipples(int numberOfRipples) {
if (numberOfRipples > 4 || numberOfRipples < 1) {
numberOfRipples = 4;
}
mNumberOfRipples = numberOfRipples;
return this;
}
public MapRipple withFillColor(int fillColor) {
mFillColor = fillColor;
return this;
}
public MapRipple withStrokeColor(int strokeColor) {
mStrokeColor = strokeColor;
return this;
}
@Deprecated
public void withStrokewidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
}
public MapRipple withStrokeWidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
return this;
}
public MapRipple withDurationBetweenTwoRipples(long durationBetweenTwoRipples) {
mDurationBetweenTwoRipples = durationBetweenTwoRipples;
return this;
}
public boolean isAnimationRunning() {
return isAnimationRunning;
}
public MapRipple withRippleDuration(long rippleDuration) {
mRippleDuration = rippleDuration;
return this;
}
private final Runnable mCircleOneRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[0] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(0);
}
};
private final Runnable mCircleTwoRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[1] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(1);
}
};
private final Runnable mCircleThreeRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[2] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(2);
}
};
private final Runnable mCircleFourRunnable = new Runnable() {
@Override
public void run() {
mGroundOverlays[3] = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(mLatLng, (int) mDistance)
.transparency(mTransparency)
.image(mBackgroundImageDescriptor));
startAnimation(3);
}
};
private void startAnimation(final int numberOfRipple) {
ValueAnimator animator = ValueAnimator.ofInt(0, (int) mDistance);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setDuration(mRippleDuration);
animator.setEvaluator(new IntEvaluator());
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animated = (int) valueAnimator.getAnimatedValue();
mGroundOverlays[numberOfRipple].setDimensions(animated);
if (mDistance - animated <= 10) {
if (mLatLng != mPrevLatLng) {
mGroundOverlays[numberOfRipple].setPosition(mLatLng);
}
}
}
});
animator.start();
mAnimators[numberOfRipple] = animator;
}
private void setDrawableAndBitmap() {
mBackground.setColor(mFillColor);
mBackground.setStroke(UiUtil.dpToPx(mStrokeWidth), mStrokeColor);
mBackgroundImageDescriptor = UiUtil.drawableToBitmapDescriptor(mBackground);
}
public void stopRippleMapAnimation() {
if (isAnimationRunning) {
try {
for (int i = 0; i < mNumberOfRipples; i++) {
if (i == 0) {
mHandlers[i].removeCallbacks(mCircleOneRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 1) {
mHandlers[i].removeCallbacks(mCircleTwoRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 2) {
mHandlers[i].removeCallbacks(mCircleThreeRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
if (i == 3) {
mHandlers[i].removeCallbacks(mCircleFourRunnable);
mAnimators[i].cancel();
mGroundOverlays[i].remove();
}
}
} catch (Exception e) {
//no need to handle it
}
}
isAnimationRunning = false;
}
public void startRippleMapAnimation() {
if (!isAnimationRunning) {
setDrawableAndBitmap();
for (int i = 0; i < mNumberOfRipples; i++) {
if (i == 0) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleOneRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 1) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleTwoRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 2) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleThreeRunnable, mDurationBetweenTwoRipples * i);
}
if (i == 3) {
mHandlers[i] = new Handler();
mHandlers[i].postDelayed(mCircleFourRunnable, mDurationBetweenTwoRipples * i);
}
}
}
isAnimationRunning = true;
}
}
?