Qt5 paintEvent() 区域太小

Posted

技术标签:

【中文标题】Qt5 paintEvent() 区域太小【英文标题】:Qt5 paintEvent() region too small 【发布时间】:2019-02-18 17:07:19 【问题描述】:

我想实现一个自定义小部件。通过双击将Node 对象添加到拥有的Graph 小部件时,Node::paintEvent 发生是正确的,但是QPaintEvent 的区域是恒定的并且太小,无论我在哪里添加它。指示的边界重绘框始终位于 (0,0),宽度/高度为 (100,30)。

任何想法为什么会这样?

代码

#include <QApplication>
#include <QMainWindow>
#include <QPainter>
#include <QMouseEvent>

#include <iostream>
#include <vector>

#define DEBUG(lvl, x) \
    std::clog << "L" << __LINE__ << ": " << x << "\n";

class Node final : public QWidget

protected:
    void paintEvent (QPaintEvent * event) override 
        DEBUG(0, "Node::paintEvent");
        QPainter painter(this);
        painter.setBrush(QColor(127,127,127));
        painter.drawRect(posX, posY, width, height);
        auto x = event->rect();
        DEBUG(0, "PaintBox:" << x.x() << "::" << x.y() << "::" << x.width() << "::" << x.height());
    
public:
    explicit Node (QWidget * parent = 0): QWidget(parent) 
    int posX0, posY0, width60, height60;
;

class GraphView final : public QWidget

public:
    explicit GraphView (QWidget * parent = 0): QWidget(parent) 
protected:
    void paintEvent (QPaintEvent *) override 
        DEBUG(0, "GraphView::paintEvent");
    

    void mouseDoubleClickEvent (QMouseEvent * event) override 
        DEBUG(0, "mouseDoubleClickEvent");
        auto ptr = new Node(this);
        ptr->posX = event->x();
        ptr->posY = event->y();
        nodes.push_back(ptr);
        ptr->show();
    

    void mousePressEvent (QMouseEvent * event) override 
        DEBUG(0, "mousePressEvent");
        auto ptr = static_cast<Node*>(childAt(event->pos()));
        if (ptr) 
            DEBUG(0, "FOUND X");
        
    
    std::vector<Node*> nodes;
;


int main (int argc, char *argv[])

    QApplication a(argc, argv);

    auto* gv = new GraphView;
    QMainWindow w;
    w.setCentralWidget(gv);
    w.resize(640, 480);
    w.show();

    return a.exec();

双击窗口区域的任意位置会返回:

L34: GraphView::paintEvent
L48: mousePressEvent
L38: mouseDoubleClickEvent
L34: GraphView::paintEvent
L16: Node::paintEvent
L21: PaintBox:0::0::100::30

如果您双击 0,0 到 100,30 之间的区域,则节点会正常显示。

【问题讨论】:

【参考方案1】:

请注意,Qt 已经内置了一个非常好的图形场景小部件。看看Graphics View Framework。它针对数千个项目进行了优化,支持单个场景的多个视图、缩放、剪切、旋转等。


但如果你想自己处理:

绘制事件中的坐标始终是相对于小部件根的。所以(0,0)是小部件的左上角,不管它放在哪里(见coordinate systems)。

当您将子小部件(作为您的节点)直接添加到小部件(而不是使用布局)时,您会将其放置在左上角。它的大小由sizeHint决定。

所以现在,当你点击例如在(200,200),您将添加一个新小部件,并相应地设置其位置成员。这导致在您的GraphView 小部件中具有Node 小部件(0,0),大小为(100,30)。然后在绘制事件中,您在(200,200) 处绘制一个矩形,它在小部件边界之外!

你应该设置几何,以便子部件被放置在 Qt 的坐标系中:

 void GraphView::mouseDoubleClickEvent (QMouseEvent * event) 
    auto ptr = new Node(this);
    ptr->setGeometry(event->x(), event->y(), ptr->width, ptr->height);
    nodes.push_back(ptr);
    ptr->show();

然后根据(0,0) 进行绘图:

void Node::paintEvent (QPaintEvent * event) 
    QPainter painter(this);
    painter.setBrush(QColor(127,127,127));
    painter.drawRect(0, 0, width, height);

【讨论】:

谢谢,如果我想为 Graph Widget 实现缩放/移动功能会怎样?我可以以某种方式将父坐标系移动到左上角以外的其他地方吗? 我强烈建议你使用 QGrahpicsScene / QGraphicsView

以上是关于Qt5 paintEvent() 区域太小的主要内容,如果未能解决你的问题,请参考以下文章

Qt5 paintEvent 传播到子小部件

Qt5,X11,libxcb。滑块和小部件的其他部分太小

在 PyQt5 和 PySide2 中覆盖paintEvent

Qt 的 paintEvent 函数小结

qt5有没有窗体显示前事件

解决“传递给系统调用的数据区域太小”