How do you keep QPen pixel width the same when zoo

2019-04-26 17:03发布

问题:

I wrote a quick and nasty program to help me visualise an aspect of a project I'm working on. Although I've been working with Qt since 4.1.1, I've never really had the need to use the QGraphics* module.

When I started playing round with the program, I was working on an old computer running Windows XP and Qt4.7.0 and Visual Studio 2008. I've now just copied the file across to my main computer running Windows 8. I've decided to give Qt5 a shot so I've installed QtCreator with Qt5.0.2.

When I compile the exact same code as I created on the Qt4.7.0/XP machine, I get a vastly different result.

This is what I see on my Qt4.7.0 compilation:

and this is what I see on my Qt5.0.2 compilation:

Clearly there's different behaviour in the drawing of each rectangle's border. Also, if I zoom in using the mouse wheel, the rectangle border width gets bigger in the Qt5 compilation but stays the same(about 1 pixel wide) in the Qt4.7 compilation.

How do I change the code so that behaviour in Qt5 is the same as in Qt4.7?

Here's the full code:

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QWheelEvent>

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QVariant>
#include <QSqlError>
#include <QMessageBox>

class ItemData : public QSqlRecord{
public:
    ItemData(QSqlRecord const &rec) : QSqlRecord(rec) {}

    qreal left() const { return value(0).toDouble(); }
    qreal top() const { return value(1).toDouble(); }
    qreal width() const { return value(2).toDouble() - left(); }
    qreal height() const { return value(3).toDouble() - top(); }
    QRectF rect() const { return QRectF(left(), top(), width(), height()); }
    QString barcode() const { return value(4).toString(); }
    QString msaName() const { return value(5).toString(); }
    QString msaDescription() const { return value(6).toString(); }
    QString hsaName() const { return value(7).toString(); }
    QString hsaDescription() const { return value(8).toString(); }
};

class DSAItem : public QGraphicsRectItem{
public:
    DSAItem(ItemData const &data, QGraphicsItem *parent = 0)
        :QGraphicsRectItem(parent) {
            setFlags(QGraphicsItem::ItemIsSelectable);
            setRect(data.rect());
            QString tip = "<p><b>%1</b></p><p><b>MLSA</b><br/>%2<br/>%3</p><p><b>HLSA</b><br/>%4<br/>%5</p>";
            setToolTip(tip.arg(data.barcode(), data.msaName(), data.msaDescription(), data.hsaName(), data.hsaDescription()));
            if(data.barcode() == "1010100101" || data.barcode() == "1010100114"){
                colour = QColor(Qt::red);
            } else {
                colour = QColor(Qt::yellow);
            }
            colour.setAlphaF(.5);
            setBrush(QBrush(colour));
    }

    QVariant itemChange(GraphicsItemChange change, QVariant const &value){
        if (change == QGraphicsItem::ItemSelectedHasChanged){
            QColor c = value.toBool() ? QColor(Qt::green) : colour;
            c.setAlphaF(.5);
            setBrush(QBrush(c));
            update(rect());

        }
        return QGraphicsRectItem::itemChange(change, value);
    }

private:
    QColor colour;
};

class View : public QGraphicsView {
public:
    View(QWidget *parent = 0): QGraphicsView(parent){
        populateScene();
        setScene(&scene);
        rotate(-90);
        scale(1.0, -1.0);
        setDragMode(ScrollHandDrag);
    }

protected:
    void wheelEvent(QWheelEvent *e){
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);

        double scaleFactor = 1.15;
        if (e->delta() > 0){
            scale(scaleFactor, scaleFactor);
        } else {
            scale(1 / scaleFactor, 1 / scaleFactor);
        }
    }

private:
    void populateScene(){
        QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
        //db credentials here

        QString errorMessage;
        bool ok = db.open();
        if (ok){
            QSqlQuery query(db);
            QString sql = //query string here

            if (query.exec(sql)){
                while(query.next()){
                    scene.addItem(new DSAItem(query.record()));
                }
            } else {
                errorMessage = query.lastError().text();
            }
        } else {
            errorMessage = db.lastError().text();
        }

        if (!errorMessage.isEmpty()){
            QMessageBox::critical(0, "Database Error", errorMessage);
        }
    }

private:
    QGraphicsScene scene;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    View view;
    view.show();

    return a.exec();
}

回答1:

The best answer is given by rpsml below this one. But for historical reasons I'll leave this one here.

Setting the width of the pen to zero will make it a "cosmetic" pen with a width of 1.

QPen p = pen();
p.setWidth(0)
setPen(p);


回答2:

This is a bit late but might be helpful.

The proposed solution works fine, but limits the pen widht. An alternative is to use the instruction

p.setCosmetic(true);

According to the Qt reference (http://qt-project.org/doc/qt-5/qpen.html#isCosmetic)

Cosmetic pens are used to draw strokes that have a constant width regardless of any transformations applied to the QPainter they are used with.

And it also explains why setting the width to zero works:

A zero width pen is cosmetic by default; pens with a non-zero width are non-cosmetic.



标签: c++ qt5