在Qt中有效地绘制物理上准确的标尺

时间:2014-11-09 13:22:16

标签: c++ qt

我有一个标尺类(称为Graduation),它使用方向来计算应绘制线的位置。像这样:

enter image description here

当方向设置为Qt::Horizontal时,我会line_xpos = precendent_line_xpos + number。然后,如果方向是Qt::Vertical,我会添加到y位置。

我在下面有一些代码,这是我如何使用if...else?:语句执行此操作的示例:

/* std::vector<QLineF> m_lines; */

void Graduation::resizeEvent(QResizeEvent *event)
{   
    qreal newLength = (m_orientation == Qt::Horizontal)
        ? event->size().width()
        : event->size().height();
    qreal oldLength = (m_orientation == Qt::Horizontal)
        ? event->oldSize().width()
        : event->oldSize().height();

    if(newLength != oldLength) {
        if(newLength < oldLength) { /* Delete lines */
            int count = m_lines.size();
            if(count == 0)
                return;

            if(m_orientation == Qt::Horizontal) {
                while(m_lines[count-1].x1() > newLength) {
                    --count;
                }
            } else {
                while(m_lines[count-1].y1() > newLength) {
                    --count;
                }
            }

            m_lines.erase(
                m_lines.begin()+count,
                m_lines.begin()+m_lines.size()
            );
        } else
          /* ... Append lines ... */
    }
}

这是paintEvent,用于显示如何绘制线条:

void Graduation::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    QPainter painter(this);
    painter.setPen(QPen(Qt::black, 0.5));

    for(unsigned int i = 0; i < m_lines.size(); ++i)
        painter.drawLine(m_lines[i]);
}

我想知道我是否可以避免这些条件被检查数千次。我对可以用来避免的代码模式感兴趣(尽管最好只计算一次行位置并只绘制可见的内容)

1 个答案:

答案 0 :(得分:8)

好的,在您发布该图片后,看起来您可以找到更简单有效的解决方案。

你的线条形成了一个可重复的模式,因此,绘制整个事物,手动管理线条以及诸如此类的东西将是一种浪费。您可以创建一个小像素图并仅绘制重复图案的一个部分,如下所示:

pattern

然后根据方向,您可以保持原样或旋转/翻转它。然后,您可以使用QPainter使用Graduation Qt::TexturePattern使用QBrush::setTexture(pixmap)填充QPixmap drawCMPattern(qreal dpi) { qreal dpcm = dpi / 2.54; QPixmap rulerCache(dpcm, dpcm / 2); rulerCache.fill(); qreal dpmm = dpcm / 10; QPainter p(&rulerCache); p.setRenderHint(QPainter::HighQualityAntialiasing); qreal lineWidth = dpmm / 5; p.setPen(QPen(Qt::black, lineWidth)); qreal xpos = lineWidth / 2; for (int i = 0; i < 10; ++i) { if (i == 0) p.drawLine(QLineF(xpos, 0, xpos, rulerCache.height())); else if (i == 5) p.drawLine(QLineF(xpos, 0, xpos, rulerCache.height() / 2)); else p.drawLine(QLineF(xpos, 0, xpos, rulerCache.height() / 4)); xpos += dpmm; } return rulerCache; } 窗口小部件,它将使用模式快速有效地填充整个窗口小部件长度/高度这是多少。

如果要更改标尺的样式或间距,您只需重绘缓存的图案并使用相同的过程更新标尺。

最后但并非最不重要的是,您可以使用Qt提供的布局将标尺捕捉到正确的位置,以便100%自动管理它们,使您当前使用的逻辑变得多余。

好的,这里有一点帮助,另外这将告诉你,你不必每行都有画线,代码很简单,并且会为给定的DPI生成模式片段:

HighQualityAntialiasing

您可能会注意到典型的低DPI台式机显示器上的线条有些模糊,但这是您为物理上的准确而付出的代价&#34; - 你要么是公制完美的,要么像素完美,除非你的DPI与公制单位完美匹配,否则大多数线都必然会出现在像素之间。在高DPI移动设备上,它看起来不会那么糟糕。

或者,如果省略{{1}},则可以获得清晰的线条,但这些线条的距离不会相等。尽管如此,这可能对你有好处,因为对于像Photoshop这样的商业软件来说它显然已经足够了:

PS ruler

然而,PS是棘手的并且在1厘米处具有较少的线,因此差异不像每毫米线具有的那样显着。以下是我的108.79 DPI桌面上代码结果的显示方式:

this code