如何使用QGraphicObject实现独占(例如单选按钮)类型行为?

时间:2014-10-01 21:11:24

标签: qt qt4 qt5

我在一段时间后再次使用Qt(第5.3节)。作为一个学习练习,我使用QGraphicView对模块进行原型设计,以便更好地理解如何使用它。

功能很简单:我有几个QGraphicObjects,其功能类似于具有状态和行为的按钮:

  • 关闭 - 图像面板隐藏;默认按钮艺术
  • ON - 图像面板 显示;突出显示按钮艺术

启动时,所有按钮都处于OFF状态

  • 点击按钮将切换状态(非独家)
  • 如果其他按钮已处于ON状态,则必须将其关闭(独占)

一切都是数据驱动的,并在运行时动态创建。


这是我的小小学习练习。我要解决的是一种有效的消息传递机制来处理“单选按钮有时”的独占行为,并向一组对象发送消息而不强烈耦合它们。

  • 我看过signals and slots,但是如果要建立很多连接,那就太乏味了。
  • QSignalMapper看起来好一点
  • QEvent可能是最坚实的方法,但我找不到好的学习例子。

我使这比需要的更复杂但正如我所说,这是一个习惯再次习惯Qt的学习练习。

所以我的问题(最后):是否有一种我忽略的方法或其中一种更好的方法(例如最灵活,可维护,可扩展)。不是寻找代码本身,而是了解如何使用Qt框架编写类似的代码。


这是事物的图像:

enter image description here

2 个答案:

答案 0 :(得分:0)

子类QGraphicsScene

重新实现mousePressEvent并按下鼠标左键。

如果是这样,则通过pos()方法获取鼠标的位置,并通过itemAt()方法获取箭头下的当前图形对象。

尝试将其投射到您需要的对象中,如果成功,则更改背景和其他对象。

将图形对象存储在矢量中,在这种情况下,您可以检查每个对象并确定应关闭哪个对象。

完全正常的例子:

头:

#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H

#include <QGraphicsScene>
#include <QPoint>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
    Q_OBJECT
public:
    explicit GraphicsScene(QObject *parent = 0);

signals:

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);

public slots:
    private:
    QVector<QGraphicsEllipseItem * > vec;

};

#endif // GRAPHICSSCENE_H

CPP:

#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsItem>

GraphicsScene::GraphicsScene(QObject *parent) :
    QGraphicsScene(parent)
{
    //set circles in different positions.
    vec.push_back(addEllipse(0,0,50,50,QPen(Qt::red),QBrush(Qt::blue)));
    vec.push_back(addEllipse(0+100,0+100,50,50,QPen(Qt::red),QBrush(Qt::blue)));
    vec.push_back(addEllipse(0+150,0+150,50,50,QPen(Qt::red),QBrush(Qt::blue)));
}

void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    //qDebug() << "in";
    if (mouseEvent->button() == Qt::LeftButton)
    {
        QGraphicsItem *item = itemAt(mouseEvent->scenePos(), QTransform());
        QGraphicsEllipseItem *ell = qgraphicsitem_cast<QGraphicsEllipseItem *>(item);
        if(ell)
        {
            for(int i = 0; i < vec.size(); i++)
            {
                if(vec.at(i) != ell)
                {
                    vec.at(i)->setBrush(QBrush(Qt::blue));//disable all other bettons
                }
            }
                ell->setBrush(QBrush(Qt::black));//to chosen circle
                qDebug() << "good";

        }
        else
            qDebug() << "not ell" << mouseEvent->scenePos();


    }
}

用法:

GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setScene(scene);

在这种情况下,您的圈子将类似于radioButtons。如果您想要保存所有按钮的状态,可以使用:

for(int i = 0; i < vec.size(); i++)
    vec.at(i)->setData(0,false);

获取状态
if(!ell->data(0).toBool())
//do

答案 1 :(得分:0)

信号和插槽是我在这里使用的方法。但是,您可以创建一个中间的Controller类,而不是将每个按钮连接到其他每个按钮。

Controller类可以聚合,也可以是所有按钮的父级。

创建按钮时,它会将信号连接到控制器以通知其被按下。然后,Controller类中的接收槽负责关闭任何其他按钮。

骨架代码: -

class ButtonController : public QGraphicsObject
{
    public slots:
        void ButtonPressed();

    private:
        QList<MyButton*> m_buttonList;
};

void ButtonController::ButtonPressed()
{
    foreach(MyButton* pButton, m_buttonList)
    {
        if(pButton != sender())
        {
            pButton->Off();
        }
    }
}

在MyButton的构造函数中,假设控制器是父级: -

MyButton::MyButton(ButtonController* parent)
    : QGraphicsObject(parent);
{
   connect(this, &MyButton::pressed(), parent, &ButtonController::ButtonPressed());

   ...
}

或者,控制器可以只保存按钮列表,在这种情况下,您可以执行此操作: -

MyButton::MyButton(QObject* parent, ButtonController* pButtonController)
    : QGraphicsObject(parent);
{
   connect(this, &MyButton::pressed(), pButtonController, &ButtonController::ButtonPressed());

   ...
}

如果无法更改按钮的构造函数,控制器可能只有一个AddButton函数,当按钮被添加到其控件下时,它会创建连接。