如何根据Qt中的状态更改图像源
How to change image source based on state in Qt
我使用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来解决这个问题。
但我仍然很想知道为什么和国家绑定不起作用。
相关文章:
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 平均图像时图像损坏
- 在C++中使用GDAL可以将图像的像素坐标转换为lat,long吗
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- Vulkan验证层不断在VkQueuePresentKHR()上抛出图像布局错误
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 使用FFMPEG将RGB图像序列保存到.mp4时出现问题
- 我不断收到 [错误] ID 返回 1 退出状态错误,但看不到问题所在
- 将RGB图像保存为PPM格式
- 将图像添加到资源文件夹UWP C++
- OSX MetalKit CVMetalTextureCacheCreateTextureFromImage失败,状态:
- 彩色图像的卤化物处理平均值
- 使用导入的图像保存在 QT 中的 QLabel 中,保存 GUI 的状态
- 如何保持我在 Visual Studio SDL 中编写的图像窗口处于打开状态
- 更改树视图状态图像
- 如何根据Qt中的状态更改图像源
- 在 CListCtrl 中为图像添加状态图标