在 QwtPlot scaleDraw 中绘制向内刻度

Posted

技术标签:

【中文标题】在 QwtPlot scaleDraw 中绘制向内刻度【英文标题】:Draw inward tick in QwtPlot scaleDraw 【发布时间】:2016-04-13 12:01:02 【问题描述】:

我们如何在向内和向外绘制轴刻度线?我重新实现了 QwtScaleDraw 并用 drawTick 覆盖,但我不知道如何匹配刻度位置并使用

QwtPainter::drawLine(painter,QPointF,QPointF)

我试过了:

inside Plot::drawItems(QPainter *painter, const QRectF &rect, const QwtScaleMap map[axisCnt]) const

const QwtScaleMap ↦
for (j = 0; j < majTicks; j++)

   y = map.transform(majTickList[j]);
  QwtPainter::drawLine(painter, x, y, x + m_majTickLength, y);

但是轴边距与出轴的角不匹配,小偏差即将到来。我在这里截图了:

我完整的向内抽奖

    void CustomScaleDraw::draw(QPainter *painter, const QPalette &palette) const
    


        QwtScaleDraw::draw(painter, palette);


        painter->save();

        QPen pen = painter->pen();
        pen.setColor(palette.color(QPalette::Foreground));
        painter->setPen(pen);

        int majLen = m_pPlotWidget->majorTickLength();
        if (m_majTickStyle >= Both && majLen > 0)
            QList<double> ticks = this->scaleDiv().ticks(QwtScaleDiv::MajorTick);
            for (int i = 0; i < (int)ticks.count(); i++)
                const double v = ticks[i];
                if (this->scaleDiv().contains(v))
                    drawInwardTick(painter, v, majLen);
            
        
    


and 
void CustomScaleDraw::drawInwardTick(QPainter *painter, double value, int len) const



    int pw2 = qMin((int)painter->pen().width(), len) / 2;

    QwtScaleMap scaleMap = this->scaleMap();

    QPointF pos = this->pos();

    int majLen = tickLength(QwtScaleDiv::MajorTick);


    const int clw = m_pPlotWidget->lineWidth();
    const int tval = scaleMap.transform(value);

    bool draw = false;
    if ( orientation() == Qt::Vertical )
        int low = (int)scaleMap.p2() + majLen;
        int high = (int)scaleMap.p1() - majLen;
        if ((tval > low && tval < high) ||
            (tval > high && !m_pPlotWidget->axisEnabled (QwtPlot::xBottom) && !clw) ||
            (tval < low && !m_pPlotWidget->axisEnabled(QwtPlot::xTop) && !clw)) draw = true;
     else 
        int low = (int)scaleMap.p1() + majLen;
        int high = (int)scaleMap.p2() - majLen;
        if ((tval > low && tval < high) ||
            (tval > high && !m_pPlotWidget->axisEnabled(QwtPlot::yRight) && !clw) ||
            (tval < low && !m_pPlotWidget->axisEnabled(QwtPlot::yLeft) && !clw)) draw = true;
    

    if (draw)

        switch(alignment())

            case LeftScale:
            
                QwtPainter::drawLine(painter, pos.x() + pw2, tval, pos.x() + len, tval);

                break;
            
            case RightScale:
            
                QwtPainter::drawLine(painter, pos.x() - pw2, tval, pos.x() - len, tval);
                break;
            
            case BottomScale:
            
                QwtPainter::drawLine(painter, tval, pos.y() - pw2, tval, pos.y() - len);
                break;
            
            case TopScale:
            
                QwtPainter::drawLine(painter, tval, pos.y() + pw2, tval, pos.y() + len);
                break;
            
        
    
//    QwtPainter::setMetricsMap(metricsMap); // restore metrics map

我在 QwtPlot.cpp 中的比例设置

for (int i = 0; i

    if(scale)
    
        scale->setMargin(0);

        //the axis title color must be initialized...
        QwtText title = scale->title();
        title.setColor(Qt::black);
        scale->setTitle(title);

        //...same for axis color
        QPalette pal = scale->palette();
        pal.setColor(QPalette::Foreground, QColor(Qt::black));
        scale->setPalette(pal);

        CustomScaleDraw *sd = new CustomScaleDraw(this);
        sd->setTickLength(QwtScaleDiv::MinorTick, m_minTickLength);
        sd->setTickLength(QwtScaleDiv::MediumTick, m_minTickLength);
        sd->setTickLength(QwtScaleDiv::MajorTick, m_majTickLength);

        setAxisScaleDraw(i,sd);

    

plotLayout()->setAlignCanvasToScales( true );

m_minTickLength = 5; m_majTickLength = 9;

【问题讨论】:

这在我看来像是一个错误,导致舍入有时会转到相邻像素。也就是说,要做的“正确”事情(IMO)是使用QwtPlotScaleItem 创建内部比例。 感谢霍尔特豪斯先生。我是 qwt 的新手,所以我恳请您详细说明重新实现 qwtPlotScaleItem 的内部比例或帮助我提供示例链接。 您以哪个样本为起点?我可以试着举个例子,但我需要一个起点。 非常感谢 Holthaus 先生。我更新了我的帖子,重新实现了 QwtScaleDraw 中的绘图。当 const int tval = scaleMap.transform(value); 我使用了一个简单的 qwtplot 示例并覆盖了 qwtscaleDraw,画布设置为 m_pCanvas = new QwtPlotCanvas(); m_pCanvas->setFrameShadow(QwtPlot::Plain); m_pCanvas->setLineWidth(0); m_pCanvas->setPalette(Qt::white); m_pCanvas->setContentsMargins(0,0,0,0); setCanvas(m_pCanvas);和轴是默认的。 【参考方案1】:

您可以通过向图中添加额外的刻度项来实现向内刻度的效果,这些刻度项的对齐属性与它们的位置通常需要的对齐属性相反

这需要方式的代码比自定义画家少,而且您没有对齐问题。

输出

代码

#include <qapplication.h>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_layout.h>
#include <qwt_symbol.h>
#include <qwt_legend.h>
#include <qwt_scale_widget.h>
#include <qwt_plot_scaleitem.h>

int main( int argc, char **argv )

    // Enable high-DPI scaling with Qt 5.6+
#if (QT_VERSION >= QT_VERSION_CHECK(5,6,0))
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QApplication a( argc, argv );

    QwtPlot plot;
    plot.setTitle( "Plot Demo" );
    plot.canvas()->setContentsMargins(0, 0, 0, 0);
    plot.setStyleSheet("QwtPlot border: 0; ");
    plot.canvas()->setStyleSheet("QwtPlotCanvas border: none; margin: 1; background-color: white;");
    plot.plotLayout()->setCanvasMargin(0);

    plot.enableAxis(QwtPlot::yLeft);
    plot.enableAxis(QwtPlot::yRight);
    plot.enableAxis(QwtPlot::xBottom);
    plot.enableAxis(QwtPlot::xTop);

    plot.setAxisScale( QwtPlot::yLeft, 0.0, 1000.0 );
    plot.setAxisScale(QwtPlot::yRight, 0.0, 1000.0);
    plot.setAxisScale(QwtPlot::xBottom, 0.0, 1000.0);
    plot.setAxisScale(QwtPlot::xTop, 0.0, 1000.0);

    plot.axisWidget(QwtPlot::yLeft)->setMargin(0);
    plot.axisWidget(QwtPlot::yLeft)->setSpacing(0);
    plot.axisWidget(QwtPlot::yRight)->setMargin(0);
    plot.axisWidget(QwtPlot::xBottom)->setMargin(0);
    plot.axisWidget(QwtPlot::xTop)->setMargin(0);

    // create inward pointing ticks, and disable their labels
    // notice the alignment is *opposite* to the position.
    // in production code, don't hardcode the positions obviously.
    QwtPlotScaleItem *yLeftScaleItem = new QwtPlotScaleItem(QwtScaleDraw::RightScale, 0);
    yLeftScaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false);
    yLeftScaleItem->attach(&plot);

    QwtPlotScaleItem *yRightScaleItem = new QwtPlotScaleItem(QwtScaleDraw::LeftScale, 1000);
    yRightScaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false);
    yRightScaleItem->attach(&plot);

    QwtPlotScaleItem *xBottomScaleItem = new QwtPlotScaleItem(QwtScaleDraw::TopScale, 0);
    xBottomScaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false);
    xBottomScaleItem->attach(&plot);

    QwtPlotScaleItem *xTopScaleItem = new QwtPlotScaleItem(QwtScaleDraw::BottomScale, 1000);
    xTopScaleItem->scaleDraw()->enableComponent(QwtAbstractScaleDraw::Labels, false);
    xTopScaleItem->attach(&plot);

    plot.updateCanvasMargins();

    plot.resize( 500, 400 );
    plot.show();

    return a.exec();

【讨论】:

以上是关于在 QwtPlot scaleDraw 中绘制向内刻度的主要内容,如果未能解决你的问题,请参考以下文章

qwtplot:重新绘制时没有情节更新

在 QwtPlot 中使用 QTime 作为 X 轴

PyQwt QwtPlot 慢

Scale Drawable - setImageLevel 是不是规定了比例?

如何使用 Python 在一组点上绘制多边形(部分向内弯曲)边缘?

QwtPlot 显示错误的日期/时间