QT绘图:边线闪烁,且边线的中间有一个实心圆形的矩形

qt 6.7 画一个矩形,要求点击的时候边线闪烁,且两边的边线的中间有一个实心的圆形,用到信号和槽的类需要将头文件和资源文件分开,请提供完整代码,绘制矩形要求使用QGraphicsRectItem

记忆要点:边线的变化靠定周期更新边线颜色

    timer = new QTimer(this);  
    connect(timer, &QTimer::timeout, this, &FlashingRectItem::toggleBorderVisibility);  
}  
  
  
void FlashingRectItem::toggleBorderVisibility() {  
    showBorder = !showBorder;  
    if (showBorder) {  
        setPen(QPen(Qt::black, 2));  
    } else {  
        setPen(QPen(Qt::transparent, 0));  
    }  
    update();  
}  

内容:

在Qt中使用QGraphicsRectItem来绘制矩形,并结合信号和槽来实现边线闪烁和实心圆形的绘制,你需要创建一个基于QGraphicsViewQGraphicsScene的应用程序。下面是一个简化的示例,展示了如何实现你的要求:

1. 头文件 FlashingRectItem.h

#ifndef FLASHINGRECTITEM_H  
#define FLASHINGRECTITEM_H  
  
#include <QGraphicsRectItem>  
#include <QTimer>  
#include <QGraphicsEllipseItem>  
  
class FlashingRectItem : public QObject, public QGraphicsRectItem {  
    Q_OBJECT  
    Q_INTERFACES(QGraphicsItem)  
  
public:  
    FlashingRectItem(QGraphicsItem *parent = nullptr);  
  
protected:  
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override;  
  
private slots:  
    void toggleBorderVisibility();  
  
private:  
    QTimer *timer;  
    bool showBorder;  
    QGraphicsEllipseItem *leftCircle;  
    QGraphicsEllipseItem *rightCircle;  
};  
  
#endif // FLASHINGRECTITEM_H

2. 源文件 FlashingRectItem.cpp

#include "FlashingRectItem.h"  
#include <QGraphicsSceneMouseEvent>  
#include <QPen>  
#include <QBrush>  
  
FlashingRectItem::FlashingRectItem(QGraphicsItem *parent)  
    : QGraphicsRectItem(parent), showBorder(true) {  
    setPen(QPen(Qt::black, 2));  
    setBrush(Qt::NoBrush);  
  
    // Create circles  
    leftCircle = new QGraphicsEllipseItem(this);  
    rightCircle = new QGraphicsEllipseItem(this);  
    updateCirclesPosition();  
  
    timer = new QTimer(this);  
    connect(timer, &QTimer::timeout, this, &FlashingRectItem::toggleBorderVisibility);  
}  
  
void FlashingRectItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {  
    if (event->button() == Qt::LeftButton) {  
        if (!timer->isActive()) {  
            timer->start(500); // 0.5 seconds interval  
        } else {  
            timer->stop();  
        }  
    }  
    QGraphicsRectItem::mousePressEvent(event);  
}  
  
void FlashingRectItem::toggleBorderVisibility() {  
    showBorder = !showBorder;  
    if (showBorder) {  
        setPen(QPen(Qt::black, 2));  
    } else {  
        setPen(QPen(Qt::transparent, 0));  
    }  
    update();  
}  
  
void FlashingRectItem::updateCirclesPosition() {  
    QRectF rect = rect();  
    leftCircle->setRect(-10, -10, 20, 20); // Make circles slightly bigger than the pen width  
    leftCircle->setPos(rect.left() + rect.width() / 4, rect.center().y() - 10);  
    rightCircle->setRect(-10, -10, 20, 20);  
    rightCircle->setPos(rect.right() - rect.width() / 4 - 10, rect.center().y() - 10);  
}  
  
void FlashingRectItem::boundingRect() const {  
    return QRectF(0, 0, 200, 100); // Example size  
}  
  
void FlashingRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {  
    Q_UNUSED(option)  
    Q_UNUSED(widget)  
  
    // Draw circles  
    painter->setBrush(Qt::black);  
    painter->drawEllipse(leftCircle->rect());  
    painter->drawEllipse(rightCircle->rect());  
  
    QGraphicsRectItem::paint(painter, option, widget);  
}

注意:FlashingRectItem 类同时继承了 QObject 和 QGraphicsRectItem,这是为了使用信号和槽机制。QGraphicsRectItem 本身不是从 QObject 继承的,因此不能直接使用信号和槽。

3. 主函数文件 main.cpp  

#include <QApplication>  
#include <QGraphicsView>  
#include <QGraphicsScene>  
#include "FlashingRectItem.h"  
  
int main(int argc, char *argv[]) {  
    QApplication app(argc, argv);  
  
    QGraphicsScene scene;  
    FlashingRectItem *rectItem = new FlashingRectItem();  
    scene.addItem(rectItem);

能把主函数的内容补充完整吗 

当然可以。以下是一个完整的主函数main.cpp,它创建了一个QGraphicsScene和一个QGraphicsView,然后将FlashingRectItem添加到场景中,并显示视图。

#include <QApplication>  
#include <QGraphicsView>  
#include <QGraphicsScene>  
#include "FlashingRectItem.h"  
  
int main(int argc, char *argv[]) {  
    QApplication app(argc, argv);  
  
    // 创建一个QGraphicsScene对象  
    QGraphicsScene scene;  
  
    // 创建一个FlashingRectItem对象,并添加到场景中  
    FlashingRectItem *rectItem = new FlashingRectItem();  
    scene.addItem(rectItem);  
  
    // 创建一个QGraphicsView对象,设置其场景为之前创建的scene  
    QGraphicsView view(&scene);  
  
    // 设置视图的一些基本属性  
    view.setRenderHint(QPainter::Antialiasing);  
    view.setBackgroundBrush(QPixmap(":/images/chessboard.png")); // 假设你有一个棋盘图片作为背景  
    view.setCacheMode(QGraphicsView::CacheBackground);  
    view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);  
    view.setDragMode(QGraphicsView::ScrollHandDrag);  
    view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Flashing Rectangle Example"));  
    view.resize(800, 600);  
    view.show();  
  
    // 运行应用程序  
    return app.exec();  
}

请注意,这段代码假设你有一个名为chessboard.png的图片文件作为背景,并且该文件已经被添加到Qt资源文件(.qrc)中。如果你没有这个图片或者不想使用背景图片,你可以简单地移除或注释掉与背景图片相关的代码行。

此外,QT_TRANSLATE_NOOP宏用于国际化,如果你不需要国际化支持,也可以将其替换为普通的字符串,例如"Flashing Rectangle Example"

如果你还没有创建Qt资源文件,你可以忽略与背景图片相关的设置,或者创建一个新的资源文件,并将所需的图片添加到其中。

确保你的Qt项目文件(.pro)已经正确配置,以包含你的资源文件和FlashingRectItem的源文件和头文件。

这是一个基本的示例,你可以根据自己的需求对视图和场景进行更多的定制。

FlashingRectItem类的头文件中,视乎缺少一些函数的定义 

确实,如果FlashingRectItem类中有一个updateCirclesPosition()成员函数,那么它应该在类的实现文件(.cpp)中被定义。这个函数可能用于更新类中定义的圆形元素(如leftCirclerightCircle)的位置。以下是一个可能的实现示例:

void FlashingRectItem::updateCirclesPosition() {  
    // 假设leftCircle和rightCircle已经被创建并设置为成员变量  
    QRectF rect = this->boundingRect();  
  
    // 更新左侧圆形的位置  
    if (leftCircle) {  
        leftCircle->setPos(rect.left(), rect.center().y() - leftCircle->boundingRect().height() / 2);  
    }  
  
    // 更新右侧圆形的位置  
    if (rightCircle) {  
        rightCircle->setPos(rect.right() - rightCircle->boundingRect().width(), rect.center().y() - rightCircle->boundingRect().height() / 2);  
    }  
}

在这个函数中,我们首先获取当前FlashingRectItem的边界矩形,然后根据这个矩形的位置和尺寸来更新两个圆形元素的位置。左侧圆形被放置在矩形的左侧,而右侧圆形被放置在矩形的右侧,两者都垂直居中对齐。

请注意,这个函数的实现取决于你的具体需求,包括圆形的尺寸和它们应该如何相对于矩形项定位。此外,这个函数应该在矩形项尺寸变化或者需要重新布局时被调用,例如在boundingRect()变化后或者响应某些事件时。

如果你没有在FlashingRectItem类中声明updateCirclesPosition()函数,那么你需要在头文件中添加相应的声明,并在实现文件中添加上述定义。

FlashingRectItem.h中添加声明:

void updateCirclesPosition();

然后,在FlashingRectItem.cpp中添加上述的定义。确保在调用updateCirclesPosition()之前,leftCirclerightCircle已经被正确初始化和设置。

源文件的void FlashingRectItem::boundingRect() const函数的返回值不对 

在Qt中,boundingRect()函数应该返回一个QRectF,它描述了图形项的边界。对于FlashingRectItem类,这个函数应该返回包含整个图形项(包括任何子项,如leftCirclerightCircle)的最小矩形。

以下是一个可能的boundingRect()函数的实现,它考虑了主矩形和两个圆形子项:

QRectF FlashingRectItem::boundingRect() const {  
    // 假设主矩形的尺寸是固定的,或者根据其他逻辑计算得出  
    QRectF mainRect(0, 0, 100, 50); // 示例尺寸,实际应根据需要计算  
  
    QRectF boundingRect = mainRect;  
  
    // 如果存在圆形子项,需要扩展boundingRect以包含它们  
    if (leftCircle) {  
        QRectF leftCircleRect = leftCircle->boundingRect().translated(leftCircle->pos());  
        boundingRect = boundingRect.united(leftCircleRect);  
    }  
  
    if (rightCircle) {  
        QRectF rightCircleRect = rightCircle->boundingRect().translated(rightCircle->pos());  
        boundingRect = boundingRect.united(rightCircleRect);  
    }  
  
    return boundingRect;  
}

在这个例子中,mainRect代表FlashingRectItem主体部分的矩形。如果存在leftCirclerightCircle,它们的边界矩形会被计算并联合到boundingRect中,以确保返回的矩形包含了所有的子项。

请注意,这里的leftCirclerightCircle的位置和尺寸应该是在某处(如在构造函数或某个初始化函数中)已经被设置好的。

此外,如果leftCirclerightCircle的位置是相对于主矩形动态变化的,你可能需要在每次更新圆形位置后重新计算boundingRect

如果你发现boundingRect()的返回值仍然不正确,可能是因为:

  1. 子项的位置或尺寸没有正确设置。
  2. boundingRect()函数中的逻辑有误,没有正确地联合所有子项的矩形。
  3. 子项在场景中的位置与FlashingRectItem的本地坐标系统不一致,可能需要进行适当的坐标转换。

请检查并确保这些因素都被妥善处理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值