为什么我的自定义图形项目在基于 Qt 的 C++ GUI 应用程序中不断重新绘制?

2024-04-22

我的应用程序有一个 QMdiArea,其中显示子窗口,其中包含 QGraphicsView 派生视图 (GfxInteractiveView) 的实例,这些视图又可视化包含自定义 QGraphicsItem 派生项目的场景。

/// An image item which is displayed as the background of a scene.
class GfxImageItem : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT

protected:
    GfxInteractiveImgView *view_;
    QPixmap pixmap_;

    QList<GfxPointItem *> pointItems_;

public:
    GfxImageItem(GfxInteractiveImgView *view);

    // set the pixmap to the image loaded from this path
    bool load(const QString &path);

    // normally not overriden, here just for tracing 
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        QLOG("Painting image"); // homebrew macro for tracing
        QGraphicsPixmapItem::paint(painter, option, widget);
    }
};

/// A generated image drawn at the foreground of a scene. 
class GfxMapItem : public QGraphicsPixmapItem
{

public:
    GfxMapItem(QGraphicsItem *item);

    void regenerateMap();

    // same as GfxMapItem, here just for tracing
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};

到目前为止一切都很好,但我还有另一个项目 GfxPointItem,它是完全自定义的,它的 Paint() 实际上做了一些事情,当我将它添加到场景中时,CPU 使用率在其中一个核心上跳到满负荷all层次结构中的项目进入重绘循环,只要窗口可见或场景中存在自定义项目,该循环就会持续下去。发生这种情况时,看一眼堆栈就可以看出,我的函数没有一个负责调用paint(),事件是在事件循环上生成的。这是 GfxPointItem 的代码:

/// A draggable item representing an analysis point on the map, drawn on top of the map.
class GfxPointItem : public QGraphicsObject
{
    Q_OBJECT

protected:
    GfxImageItem *imgParent_;
    GfxInteractiveImgView *view_;
    int size_, fontSize_;
    QColor color_, oldColor_;
    qreal paintScale_;
    QRectF boundingRect_;
    bool active_, static_;
    QStaticText pointText_, valueText_;

public:
    GfxPointItem(GfxImageItem *parent, GfxInteractiveImgView *view, const QPointF &pos);

    void setActive(bool arg);
    void setStatic(bool arg);
    void setColor(const QColor &color) { color_ = color; update(); }

    virtual QRectF boundingRect() const { return boundingRect_; }
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

signals:
    void changedPos(int index, QPointF newpos);

public slots:
    void setPaintScale(qreal value);
    void setPointText(const QString &text);
    void setValueText(const QString &text);

protected:
    void updateBoundRect();
    void updatePointText();
    QPoint valueTextPos() const;
    QPoint pointTextPos() const;
};


GfxPointItem::GfxPointItem(GfxImageItem *parent, GfxInteractiveImgView *view, const QPointF &pos, int index) : QGraphicsObject(parent),
    imgParent_(parent),
    view_(view),
    index_(index), size_(8), fontSize_(8), 
    color_(Qt::black),
    paintScale_(view->invscale()),
    drawLabel_(true), active_(false), static_(false), floatPrec_(false)
{
    QLOGX("Creating new at " << pos.x() << "," << pos.y() << ", index: " << index);
    setPos(pos);
    updatePointText();
    connect(view, SIGNAL(scaleChanged(qreal)), this, SLOT(setPaintScale(qreal)));
}

/// An inactive point wil not respond to hover events and will not be movable.
void GfxPointItem::setActive(bool arg)
{
    QLOGX("Setting active state: " << arg);
    active_ = arg;
    setAcceptHoverEvents(arg);
    setFlag(QGraphicsItem::ItemIsMovable, arg);
}

/// Set or disable static mode on point. In static mode, the point text is not updated when changing position, so it can retain a constant label.
void GfxPointItem::setStatic(bool arg)
{
    QLOGX("Setting static mode: " << arg);
    static_ = arg;
}

void GfxPointItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QLOGX("Painting point");
    static const int margin = 2;
    setScale(paintScale_);
    QPen pen;
    pen.setWidth(1);
    pen.setColor(color_);
    painter->setPen(pen);

    // paint the centerpoint marker (two crossed lines)
    painter->drawLine(QPointF(-size_, 0), QPointF( size_, 0));
    painter->drawLine(QPointF(0, -size_), QPointF(0,  size_));

    // the label box and the two static text lines inside
    pen.setWidth(0);
    painter->setPen(pen);

    QFont font;
    font.setPointSize(fontSize_);
    painter->setFont(font);

    QBrush brush(Qt::SolidPattern);
    brush.setColor(QColor(255, 255, 127)); // sand yellow
    painter->setBrush(brush);

    // point text size, value text size
    QSizeF pts = pointText_.size(), 
           vts = valueText_.size();

    // point text position, value text position
    QPoint vtp = valueTextPos(),
           ptp = pointTextPos();

    // point id and position label and value indicator label in a rectangular box
    int shift = (valueText_.text().isEmpty()) ? 0 : vts.height();
    QRectF rect(ptp.x()-margin, ptp.y(), std::max(pts.width(), vts.width())+margin, pts.height() + shift);
    painter->drawRect(rect);
    painter->drawStaticText(ptp, pointText_);
    painter->drawStaticText(vtp, valueText_);
}

void GfxPointItem::setPaintScale(qreal value) 
{ 
    QLOGX("Updating scale: " << value);
    paintScale_ = value; 
    update(); 
}

void GfxPointItem::setPointText(const QString &text)
{
    QLOGX("Setting text: " << text);
    pointText_.setText(text);
    updateBoundRect(); 
    update();
}

void GfxPointItem::setValueText(const QString &text) 
{ 
    QLOGX("Setting value text: " << text);
    valueText_.setText(text); 
    updateBoundRect(); 
    update();
}

void GfxPointItem::updateBoundRect()
{
    QLOGX("Updating bounding rect");
    boundingRect_.setRect(- size_, pointTextPos().y(), 
        (2 * size_) + std::max(pointText_.size().width(), valueText_.size().width()), 
        (2 * size_) + pointText_.size().height() + valueText_.size().height());
}

void GfxPointItem::updatePointText()
{
    QLOGX("Updating point text");
    pointText_.setText("P" + QString::number(index_ + 1) + " (" 
        + (floatPrec_ ? QString::number(pos().x()) : QString::number(std::floor(pos().x()))) + "," 
        + (floatPrec_ ? QString::number(pos().y()) : QString::number(std::floor(pos().y()))) + ")");

    updateBoundRect();
    update();
}

void GfxPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QLOGX("Mouse move");
    QPointF p = pos();
    QPointF ep = event->pos();

    QGraphicsItem::mouseMoveEvent(event);

    if (!static_) updatePointText();
    emit changedPos(index_, pos());
}

我不知道为什么事件循环不断重新绘制项目。我什至没有注意到这一点,但我在显示标准 QFileDialog::getExistingDirectory() 时遇到了问题,当带有图形项目的窗口可见时,它甚至无法绘制,因为重绘窃取了主线程远离它,导致冻结。之后,我向绘制函数添加了跟踪语句,并在几秒钟后在日志文件中出现了数万条条目,而应用程序似乎什么也没做。在任务管理器中,当窗口可见时(在 4 核处理器上),CPU 使用率约为 25%,当我关闭它时,CPU 使用率降至 0。

我的代码都没有强制这些重新绘制,那么什么是呢?如何调试事件循环以找到这种行为的根源,这种行为会减慢我的应用程序并导致冻结?

Thanks!

Qt 版本是最新的 5.0.2 二进制包,该应用程序是使用 Visual C++ 2012 for x64 编译的。


在我看来,当打电话时setScale in paint它连接到setPaintScale,然后调用 QWidget 的update函数,然后使该区域无效,当它返回主事件循环时会导致repaint http://qt-project.org/doc/qt-5.0/qtwidgets/qwidget.html#update.

因此,每次调用 Paint 方法时,您最终都会收到 1 个需要绘制的事件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么我的自定义图形项目在基于 Qt 的 C++ GUI 应用程序中不断重新绘制? 的相关文章

  • nUnit Assert.That委托并发问题

    我的代码中遇到了一些暂时的死锁 无法解决它 简单的代码 我无法创建一个简单的调用链来重现代码InvokeChangeEvent Test public async void Test sut InvokeChangeEvent foo fi
  • C++11 类型推导与 const char *

    In GotW 94 http herbsutter com 2013 08 12 gotw 94 solution aaa style almost always auto Herb Sutter 对 经典 C 声明进行了区分 const
  • Boost.Intrusive 和 unordered_map

    我希望使用侵入性的 unordered map 由于某种原因 库中只有一个 unordered set 还有一个侵入式哈希表 但我不确定它是否具有相同的功能 而且它没有相同的接口 我错了吗 我错过了 unordered map 链接吗 如果
  • C# 如何比较两个字符串并指出哪些部分不同

    例如 如果我有 string a personil string b personal 我想得到 string c person i l 然而 它不一定是单个字符 我也可以这样 string a disfuncshunal string b
  • fgetc,检查 EOF

    在书里Linux系统编程我读过一些这样的内容 fgetc返回读取为的字符unsigned char投射到int or EOF在文件末尾或错误 使用时的一个常见错误fgetc is char c if c fgetc EOF 该代码的正确版本
  • 如何通过 C# 检测字符串中的阿拉伯语或波斯语字符?

    我想检测Arabic or Persian字符串中的字符 例如 在字符串中搜索 15 Aspire ES1 533 C4UH 并返回true 并在字符串中搜索 Aspire ES1 533 C4UH 并返回false string patt
  • LogicalOperationStack 与 .Net 4.5 中的异步不兼容吗

    Trace CorrelationManager LogicalOperationStack允许具有嵌套逻辑操作标识符 其中最常见的情况是日志记录 NDC 它是否仍然可以使用async await 这是一个简单的例子 使用LogicalFl
  • 这些比较应该返回什么?

    我有一个使用 string compare string string 对某些值进行排序的应用程序 我不明白的是为什么 1022 比较小于 10 23 而 10 23 比较小于 1024 是否有特定于 值的东西导致了这个结果 string
  • 为什么 Resources.Load 返回 null?

    我的项目有多个精灵 位于 Assets Sprites 中 我想使用 C 脚本加载它们 我已经测试过这个 Sprite myFruit Resources Load
  • 创建新视图时如何初始化视图模型中的属性?

    我有一个应用程序 可以打开一个视图 允许您搜索数据 然而 为了进行搜索 用户必须选择他想要在什么类别下进行搜索 目前 我正在尝试弄清楚如何将所选类别从主视图模型 作为 int 传递到新搜索视图的视图模型 目前我正在尝试在主视图中使用类似的东
  • 使用箭头键滚动可滚动控件

    我正在使用一个ScrollableControl在我的 C 项目中 我想知道如何将箭头键映射到垂直 水平滚动 编辑 我的图片框获得焦点 并且我设法映射滚动键 这里的问题是 当我按下箭头键时 它会滚动一次 然后失去焦点 将其交给滚动查看器旁边
  • C 预处理器“/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp”未通过完整性检查

    在使用 Xcode 11 3 的 macOS Mojave 上 我有一个基于 Autotool 的第三方库 在终端中运行我的构建脚本时构建得很好 但在 Xcode 中运行时失败Run Script步骤为 BuildScript Showin
  • Compact Framework 3.5 上的 System.Data.SQLite 问题

    我在我的紧凑框架应用程序中使用 sqlite 来记录系统中的事件 我也在使用系统 数据 SQLite http sqlite phxsoftware com 该事件具有描述其发生时间的时间戳 我将此时间戳记作为刻度存储在我的表中 除此列外
  • 即使使用前向声明也会出现未定义的类型错误

    我正在阅读循环引用和前向声明 我确实知道在头文件中实现并不是一个好的设计实践 然而我正在尝试并且无法理解这种行为 使用以下代码 包含前向声明 我期望它能够构建 但是我收到此错误 Error 1 error C2027 use of unde
  • 以编程方式将 Word 文件另存为图片

    我想将Word文档的第一页另存为图片 使用 C 有什么方法可以做到这一点 您可以将 Word 文档打印到 XPS 文档 在 WPF Net 3 5 应用程序中打开它 并使用 WPF 框架的文档和图像功能将第一个内部固定页面对象转换为位图 如
  • 在 C# 中同步闪烁标签

    我创建了一个BlinkingLabel类 源自Forms Label 其中有一个Forms Timer这允许我启用和禁用闪烁效果 我创建了 4 个标签BlinkingLabel类型 我的问题是 如果所有 4 个标签在不同时间闪烁 则闪烁效果
  • 图像处理编程

    我想知道是否有任何方法可以使用某种编程语言检测图像中对象的位置 例如 如果我有一个球的图像 每 100 毫秒更新一次 是否可以通过某些程序使用某些东西来获取球的坐标 看一下OpenCV http opencv willowgarage co
  • 多线程文件写入

    我正在尝试使用多个线程写入大文件的不同部分 就像分段文件下载器所做的那样 我的问题是 执行此操作的安全方法是什么 我是否打开文件进行写入 创建线程 将 Stream 对象传递给每个线程 我不希望发生错误 因为多个线程可能同时访问同一个对象
  • C# StreamReader 使用分隔符保存到数组

    我有一个文本文件 其中包含制表符分隔的数据 我在 C 应用程序中需要的是从文本文件中读取一行并将它们保存到一个数组中 在每个位置将它们分开 t 然后我对下一行做同样的事情 My code StreamReader sr new Stream
  • JSON.NET 序列化 JObject,同时忽略 null 属性

    我有一个JObject它被用作template用于调用 RESTful Web 服务 这JObject通过解析器创建 并且由于它用作模板告诉用户端点架构是什么样子 所以我必须找到一种方法来保留所有属性 这就是为什么我将它们的值默认为null

随机推荐

  • 如何向 Monaco 编辑器添加新的语言语法?

    我添加了我的语言并按照此处的说明进行构建https github com Microsoft monaco languages https github com Microsoft monaco languages npm run prep
  • 选择日期最高的行

    我的表中有一些重复的值 我只想选择那些具有最新 最高日期的值 即 ID Type Name Value Date 1 FRUIT APPLE Imported 2011 03 19 22 08 13 5 FRUIT LEMON Import
  • Promise.all:解析值的顺序

    看着MDN https developer mozilla org en US docs Web JavaScript Reference Global Objects Promise all它看起来像values传递给then Promi
  • C 基本头命令

    我正在尝试为我的编程课从 Linux 重新创建 head 和 tail 命令 我们刚刚开始使用 C 所以我对分配内存和指针的想法很陌生 我想知道为什么这不起作用 include
  • C#:如何将 long 转换为 ulong

    如果我尝试使用 BitConverter 它需要一个字节数组 但我没有 我有一个 Int32 我想将其转换为 UInt32 在 C 中这没有问题 您只需要一个简单的演员阵容即可 由于这样做可能会丢失精度 因此转换是显式的 long x 10
  • 将具有 key=value 对的字符串解析为 JSON

    我的节点应用程序接收以下格式的一系列字符串 a x b y c z 即包含多个空格分隔的字符串key value pairs 将此类字符串转换为以下形式的 JSON 对象的最巧妙方法是什么 a x b y c z 我打赌有一个单行解决方案
  • Spring Boot - 无法从 application.properties 在 xml 中解析属性

    我有一个 Spring Boot 应用程序 My Configuration class使用加载 xml 配置 ImportResource path to xml 其中包含以下行
  • 自动链接:地图如何工作

    我在用TextView 的 android autoLink map 属性转到地图并查找与该文本视图关联的地址 但它的行为很奇怪只找到一些地址 这是我正在尝试的代码
  • 使用 webpack 生成捆绑 TypeScript 定义文件

    我目前正在使用 gulp 来生成我的包的定义文件 如下所示 dtsGenerator default name ngFramework project out Typings raw index d ts 但是 我正在迁移到 webpack
  • 在 Selenium 中捕获 JavaScript 错误

    有没有办法捕获发生的错误DOM in Selenium并且可能与页面中的错误标记相同 举一个简单的例子 假设我试图在一个不存在的 HTML 控件上绑定一个事件 我的浏览器会抛出一个错误 element abcd not found in t
  • pyqt5不显示窗口[重复]

    这个问题在这里已经有答案了 我真的希望有人能帮助我解决这个问题 我正在尝试开始使用pyqt5 并且几乎从我正在学习的课程中复制了这段代码 代码似乎执行没有任何问题 但我应该看到的窗口根本没有出现 我做错了什么 我正在尝试ubuntu 18顺
  • Pycharm交互式控制台不起作用

    我对 python 和 Pycharm 都很陌生 因此 请毫不犹豫地指出我哪里做错了以及如何解决问题 问题是IPython无法像往常一样导入我想要执行的函数 即使 python 文件运行后 我也无法在 IPython 控制台中导入该文件中的
  • 我收到内存异常“System.IO.out of exception”错误

    对于小目录大小 代码工作正常 当目录文件大小很大时 它会给出此错误消息 我的代码 IEnumerable
  • 首选项列表仅显示第一个元素

    我正在开发一个PreferenceActivity与定制Preference意见 我的问题是我创建了一个视图ListView它只显示第一个元素 我发布我的代码和图像 http imageshack us photo my images 54
  • 大括号 {} 替换 Racket 中的“开始”

    是否可以有一个宏 使用大括号 来表示一个语句块 从而替换 begin 关键字 因此 代替 if condition begin statement1 statement2 statement3 statement4 else stateme
  • 协议类型的 inout 变量是否被禁止?

    下面的代码 protocol SomeProtocol class SomeClass SomeProtocol private func doSomethingWith inout someVar SomeProtocol private
  • 同步ScrollView滚动位置 - android

    我的 android 布局中有 2 个 ScrollView 如何同步它们的滚动位置 ScrollView中有一个方法 protected void onScrollChanged int x int y int oldx int oldy
  • 什么是 MVC 框架以及为什么它是必要/有用的?

    我知道 MVC 框架允许您分离业务逻辑 数据库访问和表示 但为什么我们需要一个框架来做到这一点 我们不能将我们的类分开 也许对模型 视图和控制器类使用不同的包 文件夹吗 在我看来 你所说的是 MVC 模式 而不是特定的框架 当然 您可以将所
  • 修复文件“project.pch”已被修改,因为预编译头在 Xcode 中构建错误

    我最近在 info plist 部分中处理我的应用程序 因为我的应用程序将无法在我的测试设备上运行 自构建预编译头以来 文件 project pch 已被修改 需要注意的是 该应用程序在模拟器中运行良好 编辑 现在我收到此错误而不是另一个错
  • 为什么我的自定义图形项目在基于 Qt 的 C++ GUI 应用程序中不断重新绘制?

    我的应用程序有一个 QMdiArea 其中显示子窗口 其中包含 QGraphicsView 派生视图 GfxInteractiveView 的实例 这些视图又可视化包含自定义 QGraphicsItem 派生项目的场景 An image i