如何根据Qt中的状态更改图像源

How to change image source based on state in Qt

本文关键字:图像 状态 何根 Qt      更新时间:2023-10-16

我使用qt quick 2.0。网格视图绑定到一个c++模型,如中所述。在gridview的代理中,我使用一个图像来显示一个图标。我尝试使用state属性来更改图像源并将状态绑定到模型。

预期的结果是在发布时,所选的屏幕图像应更改为运行图标。

它所描绘的实际结果没有改变。如果我在ScreenManager::setScreenState中使用setName而不是setState,它将正确显示更改后的屏幕名称。

有更好的解决方案吗?

屏幕.h

class Screen
{
public:
    Screen(QString name, int gridId, bool active = false);
    QString name() const;
    int gridId() const;
    bool active() const;
    QString state() const;
    void setName(QString n);
    void setActive(bool a);
    void setState(QString s);
private:
    QString m_name;
    int m_gridId;
    bool m_active;
    QString m_state;
};

ScreenManager.h

class ScreenManager : public QAbstractListModel
{
    Q_OBJECT
public:
    enum ScreenRoles {
        NameRole = Qt::UserRole + 1,
        GridIDRole,
        ActiveRole,
        StateRole
    };
    ScreenManager();
    void addScreen(const Screen& screen);
    int rowCount(const QModelIndex& parent = QModelIndex()) const;
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
    QModelIndex getIndex(int row, int column = 0,
        const QModelIndex &parent = QModelIndex()) const;
    Q_INVOKABLE int getScreenGridId(int index);
    Q_INVOKABLE bool getScreenActive(int index);
    Q_INVOKABLE void swapScreens(int index1, int index2);
    Q_INVOKABLE void setScreenState(int index, QString s);
    Q_INVOKABLE QString getScreenState(int index);
protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Screen> m_screens;
};

ScreenManager.cpp

#include "ScreenManager.h"
#include "Screen.h"
ScreenManager::ScreenManager()
{
    int index = 0;
    for (;index < 15; index++) {
        addScreen(Screen(QString ("Screen%1").arg(index), index, false));
    }
    m_screens[2].setActive(true);
    m_screens[6].setActive(true);
    m_screens[7].setActive(true);
    m_screens[8].setActive(true);
    m_screens[12].setActive(true);
}
void ScreenManager::addScreen(const Screen& screen)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_screens.append(screen);
    endInsertRows();
}
int ScreenManager::rowCount(const QModelIndex& parent) const {
    Q_UNUSED(parent);
    return m_screens.count();
}
QVariant ScreenManager::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() >= m_screens.count())
        return QVariant();
    const Screen& screen = m_screens[index.row()];
    if (role == NameRole)
        return screen.name();
    else if (role == GridIDRole)
        return screen.gridId();
    else if (role == ActiveRole)
        return screen.active();
    else if (role == StateRole)
        return screen.state();
    return QVariant();
}
QModelIndex ScreenManager::getIndex(int row, int column,
                             const QModelIndex &parent) const
{
    return hasIndex(row, column, parent) ?
                createIndex(row, column, (void*)&m_screens[row])
                : QModelIndex();
}
QHash<int, QByteArray> ScreenManager::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[NameRole] = "name";
    roles[GridIDRole] = "gridId";
    roles[ActiveRole] = "active";
    roles[StateRole] = "state";
    return roles;
}
int ScreenManager::getScreenGridId(int index)
{
    return  m_screens.at(index).gridId();
}
bool ScreenManager::getScreenActive(int index)
{
    return  m_screens.at(index).active();
}
void ScreenManager::swapScreens(int index1, int index2)
{
    int min = index1 < index2 ? index1 : index2;
    int max = index1 > index2 ? index1 : index2;
    m_screens.swap(index1, index2);
    beginMoveRows(QModelIndex(), max, max, QModelIndex(), min);
    endMoveRows();
    if (max - min > 1) {
        beginMoveRows(QModelIndex(), min + 1, min + 1, QModelIndex(), max + 1);
        endMoveRows();
    }
}

void ScreenManager::setScreenState(int index, QString s)
{
    // if use setName, the grid view can show the changed screen name 
    m_screens[index].setState(s);
    dataChanged(getIndex(0), getIndex(rowCount() - 1));
}
 QString ScreenManager::getScreenState(int index)
 {
     return m_screens[index].state();
 }

QML

GridView {
id: gridView
x: 82
y: 113
width: cellWidth * 5
height: cellHeight * 3
clip: true
anchors.bottom: parent.bottom
anchors.bottomMargin: 70
anchors.topMargin: 100
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
flickableDirection: Flickable.HorizontalAndVerticalFlick
cellWidth: 90; cellHeight: 90;
property bool ignoreMovementAnimation: true
MouseArea {
    id: gridViewMouseArea
    hoverEnabled: true
    preventStealing : true
    property int currentGridId: -1
    property int preIndex
    property int index: gridView.indexAt(mouseX, mouseY)
    anchors.fill: parent
    onPressAndHold: {
        currentGridId = screenManager.getScreenGridId(index)
        preIndex = index
        gridView.ignoreMovementAnimation = false
    }
    onReleased: {
        currentGridId = -1
        screenManager.setScreenState(index, "running");
    }
    onPositionChanged: {
        if (currentGridId != -1 && index != -1 && index != preIndex) {
            if (screenManager.getScreenActive(index)) {
                screenManager.swapScreens(preIndex, index)
                preIndex = index
            }
        }
    }
}
model: screenManager
delegate: Component {
    Item {
        id: gridViewDelegate
        width: gridView.cellWidth; height: gridView.cellHeight
        state: state
        states: [
            State {
                name: "running"
                PropertyChanges {
                    target: itemImage
                    source: "qrc:/res/image/screen_icon_running.png"
                }
            },
            State {
                name: "idle"
                PropertyChanges {
                    target: itemImage
                    source: "qrc:/res/image/screen_icon_idle.png"
                }
            }
        ]
        Image {
            id: itemImage
            parent: gridView
            x: gridViewDelegate.x + 5
            y: gridViewDelegate.y + 5
            width: gridViewDelegate.width - 10
            height: gridViewDelegate.height - 10;
            fillMode: Image.PreserveAspectFit
            smooth: true
            source: "qrc:/res/image/screen_icon.png"
            visible: active
            Text {
                text: name
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
            }
            Rectangle {
                anchors.fill: parent;
                border.color: "grey"
                border.width: 6
                color: "transparent"; radius: 5
                visible: itemImage.state === "active"
            }
            // specify the movement's animation for non-active screen icons
            Behavior on x {
                enabled: !gridView.ignoreMovementAnimation && itemImage.state !== "active"
                NumberAnimation { duration: 400; easing.type: Easing.OutBack }
            }
            Behavior on y {
                enabled: !gridView.ignoreMovementAnimation && itemImage.state !== "active"
                NumberAnimation { duration: 400; easing.type: Easing.OutBack }
            }
            // specify the shaking animation for non-active screen icons when hold one icon
            SequentialAnimation on rotation {
                NumberAnimation { to:  2; duration: 60 }
                NumberAnimation { to: -2; duration: 120 }
                NumberAnimation { to:  0; duration: 60 }
                running: gridViewMouseArea.currentGridId != -1 && itemImage.state !== "active"
                loops: Animation.Infinite
                alwaysRunToEnd: true
            }
            // specify the active screen's new position and size
            states: State {
                name: "active"
                when: gridViewMouseArea.currentGridId == gridId
                PropertyChanges {
                    target: itemImage
                    x: gridViewMouseArea.mouseX - width/2
                    y: gridViewMouseArea.mouseY - height/2
                    scale: 0.5
                    z: 10
                }
            }
            // specify the scale speed for the active screen icon
            transitions: Transition {
                NumberAnimation { property: "scale"; duration: 200}
            }
        }
    }
}

}

您有一个命名问题,因为您的项委托中的state属性也知道state。

在我改变后:

roles[StateRole] = "statetest";

在你的c++

和:

state: statetest 

在您的qml中,它是有效的。

或者简单地说:

state: model.state 

在您的qml 中

我通过将图像源绑定到Screen中的另一个属性stateIamge而不是直接绑定到state来解决这个问题。

但我仍然很想知道为什么和国家绑定不起作用。