QskModelObjectBinder API improved, models example polished
This commit is contained in:
parent
7b4db3afc1
commit
0a651782ba
|
@ -3,5 +3,5 @@
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
qsk_add_example(models Window.h Window.cpp main.cpp)
|
qsk_add_example(models MainView.h MainView.cpp main.cpp)
|
||||||
target_link_libraries(models)
|
target_link_libraries(models)
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) The authors
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "MainView.h"
|
||||||
|
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskPushButton.h>
|
||||||
|
#include <QskTextLabel.h>
|
||||||
|
#include <QskTextInput.h>
|
||||||
|
#include <QskSpinBox.h>
|
||||||
|
#include <QskSeparator.h>
|
||||||
|
#include <QskFontRole.h>
|
||||||
|
#include <QskModelObjectBinder.h>
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class TitleLabel : public QskTextLabel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TitleLabel( const QString& text, QQuickItem* parent = nullptr )
|
||||||
|
: QskTextLabel( text, parent )
|
||||||
|
{
|
||||||
|
setFontRole( QskFontRole::Title );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpinBox : public QskSpinBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpinBox( QQuickItem* parent = nullptr )
|
||||||
|
: QskSpinBox( -100.0, 100.0, 1.0, parent )
|
||||||
|
{
|
||||||
|
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Header : public QskLinearBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Header( QQuickItem* parent = nullptr )
|
||||||
|
: QskLinearBox( Qt::Horizontal, parent )
|
||||||
|
{
|
||||||
|
initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Fixed );
|
||||||
|
|
||||||
|
setPaddingHint( QskBox::Panel, 5 );
|
||||||
|
|
||||||
|
setPanel( true );
|
||||||
|
|
||||||
|
auto rowButton = new QskPushButton( "Toggle Row" );
|
||||||
|
auto submitButton = new QskPushButton( "Submit Changes" );
|
||||||
|
|
||||||
|
connect( rowButton, &QskPushButton::clicked,
|
||||||
|
this, &Header::rowClicked );
|
||||||
|
|
||||||
|
connect( submitButton, &QskPushButton::clicked,
|
||||||
|
this, &Header::submitClicked );
|
||||||
|
|
||||||
|
addItem( rowButton );
|
||||||
|
addItem( submitButton );
|
||||||
|
addStretch( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void rowClicked();
|
||||||
|
void submitClicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Model : public QStandardItemModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Model( QObject* parent = nullptr )
|
||||||
|
: QStandardItemModel( 2, 2, parent )
|
||||||
|
{
|
||||||
|
initValue( 0, 0, 1.0 );
|
||||||
|
initValue( 0, 1, "HELLO" );
|
||||||
|
|
||||||
|
initValue( 1, 0, 2.0 );
|
||||||
|
initValue( 1, 1, "WORLD" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initValue( int row, int col, const QVariant& value )
|
||||||
|
{
|
||||||
|
setData( index( row, col ), value, Qt::EditRole );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DisplayBox : public QskLinearBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DisplayBox( QQuickItem* parent = nullptr )
|
||||||
|
: QskLinearBox( Qt::Horizontal, parent )
|
||||||
|
{
|
||||||
|
setMargins( 10, 0, 10, 0 );
|
||||||
|
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Fixed );
|
||||||
|
|
||||||
|
addItem( new SpinBox() );
|
||||||
|
addItem( new QskTextInput() );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelBox : public QskLinearBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelBox( QAbstractItemModel* model )
|
||||||
|
: QskLinearBox( Qt::Horizontal, model->columnCount() )
|
||||||
|
, m_model( model )
|
||||||
|
{
|
||||||
|
setMargins( 10, 0, 10, 0 );
|
||||||
|
setExtraSpacingAt( Qt::BottomEdge );
|
||||||
|
|
||||||
|
for ( int row = 0; row < model->rowCount(); row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < model->columnCount(); col++ )
|
||||||
|
{
|
||||||
|
const auto value = model->data(
|
||||||
|
model->index( row, col ), Qt::EditRole );
|
||||||
|
|
||||||
|
if ( value.userType() == QVariant::Double )
|
||||||
|
{
|
||||||
|
auto spinBox = new SpinBox( this );
|
||||||
|
connect( spinBox, &QskSpinBox::valueChanged,
|
||||||
|
this, &ModelBox::updateModel );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto textInput = new QskTextInput( this );
|
||||||
|
connect( textInput, &QskTextInput::textChanged,
|
||||||
|
this, &ModelBox::updateModel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay();
|
||||||
|
|
||||||
|
connect( m_model, &Model::dataChanged, this, &ModelBox::updateDisplay );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateModel()
|
||||||
|
{
|
||||||
|
if ( auto item = qobject_cast< const QQuickItem* >( sender() ) )
|
||||||
|
{
|
||||||
|
const int index = indexOf( item );
|
||||||
|
|
||||||
|
const auto modelIndex = m_model->index(
|
||||||
|
index / dimension(), index % dimension() );
|
||||||
|
|
||||||
|
const auto property = item->metaObject()->userProperty();
|
||||||
|
m_model->setData( modelIndex, property.read( item ), Qt::EditRole );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDisplay() const
|
||||||
|
{
|
||||||
|
for ( int row = 0; row < m_model->rowCount(); row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < m_model->columnCount(); col++ )
|
||||||
|
{
|
||||||
|
const auto index = m_model->index( row, col );
|
||||||
|
|
||||||
|
if ( auto item = itemAtIndex( row * dimension() + col ) )
|
||||||
|
{
|
||||||
|
const auto property = item->metaObject()->userProperty();
|
||||||
|
property.write( item, m_model->data( index, Qt::EditRole ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointer< QAbstractItemModel > m_model;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MainView::MainView( QQuickItem* parent )
|
||||||
|
: QskMainView( parent )
|
||||||
|
{
|
||||||
|
m_binder = new QskModelObjectBinder( new Model( this ), this );
|
||||||
|
|
||||||
|
auto header = new Header();
|
||||||
|
|
||||||
|
auto displayBox = new DisplayBox();
|
||||||
|
for ( int i = 0; i < displayBox->elementCount(); i++ )
|
||||||
|
m_binder->bindObject( displayBox->itemAtIndex( i ), i );
|
||||||
|
|
||||||
|
auto box = new QskLinearBox( Qt::Vertical );
|
||||||
|
|
||||||
|
box->addItem( new TitleLabel( "Editor:" ) );
|
||||||
|
box->addItem( displayBox );
|
||||||
|
box->addItem( new QskSeparator() );
|
||||||
|
box->addItem( new TitleLabel( "Model:" ) );
|
||||||
|
box->addItem( new ModelBox( m_binder->model() ) );
|
||||||
|
|
||||||
|
setHeader( header );
|
||||||
|
setBody( box );
|
||||||
|
|
||||||
|
connect( header, &Header::rowClicked,
|
||||||
|
this, &MainView::toogleRow );
|
||||||
|
|
||||||
|
connect( header, &Header::submitClicked,
|
||||||
|
m_binder, &QskModelObjectBinder::submit );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainView::toogleRow()
|
||||||
|
{
|
||||||
|
m_binder->setCurrentRow( m_binder->currentRow() == 0 ? 1 : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "MainView.moc"
|
|
@ -5,10 +5,17 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QskWindow.h>
|
#include <QskMainView.h>
|
||||||
|
|
||||||
class Window : public QskWindow
|
class QskModelObjectBinder;
|
||||||
|
|
||||||
|
class MainView : public QskMainView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Window();
|
MainView( QQuickItem* = nullptr );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void toogleRow();
|
||||||
|
|
||||||
|
QskModelObjectBinder* m_binder;
|
||||||
};
|
};
|
|
@ -1,128 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) The authors
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "Window.h"
|
|
||||||
|
|
||||||
#include <QskLinearBox.h>
|
|
||||||
#include <QskPushButton.h>
|
|
||||||
#include <QskTextInput.h>
|
|
||||||
#include <QskSpinBox.h>
|
|
||||||
#include <QskModelObjectBinder.h>
|
|
||||||
|
|
||||||
#include <QStandardItemModel>
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
class Model : public QStandardItemModel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Model( QObject* parent = nullptr )
|
|
||||||
: QStandardItemModel( 2, 2, parent )
|
|
||||||
{
|
|
||||||
initValue( 0, 0, 1 );
|
|
||||||
initValue( 0, 1, "HELLO" );
|
|
||||||
|
|
||||||
initValue( 1, 0, 2 );
|
|
||||||
initValue( 1, 1, "WORLD" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void dump() const
|
|
||||||
{
|
|
||||||
qDebug() << "Model";
|
|
||||||
for ( int row = 0; row < rowCount(); row++ )
|
|
||||||
{
|
|
||||||
for ( int col = 0; col < columnCount(); col++ )
|
|
||||||
{
|
|
||||||
qDebug() << '\t' << row << col
|
|
||||||
<< data( index( row, col ), Qt::EditRole );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void initValue( int row, int col, const QVariant& value )
|
|
||||||
{
|
|
||||||
setData( index( row, col ), value, Qt::EditRole );
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class View : public QskLinearBox
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
View( QQuickItem* parent = nullptr )
|
|
||||||
: QskLinearBox( Qt::Vertical, parent )
|
|
||||||
{
|
|
||||||
setPanel( true );
|
|
||||||
|
|
||||||
auto model = new Model( this );
|
|
||||||
|
|
||||||
auto textInput = new QskTextInput();
|
|
||||||
auto spinBox = new QskSpinBox( -100.0, +100.0, 1.0 );
|
|
||||||
|
|
||||||
m_binder = new QskModelObjectBinder( model, this );
|
|
||||||
m_binder->bindObject( spinBox, 0 );
|
|
||||||
m_binder->bindObject( textInput, 1 );
|
|
||||||
|
|
||||||
auto hBox = new QskLinearBox( Qt::Horizontal );
|
|
||||||
hBox->setSection( QskAspect::Header );
|
|
||||||
hBox->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
|
|
||||||
|
|
||||||
{
|
|
||||||
auto rowButton = new QskPushButton( "Toggle Row", hBox );
|
|
||||||
auto counterButton = new QskPushButton( "Invert Counter", hBox );
|
|
||||||
auto submitButton = new QskPushButton( "Submit Changes", hBox );
|
|
||||||
|
|
||||||
connect( rowButton, &QskPushButton::clicked,
|
|
||||||
this, &View::toogleRow );
|
|
||||||
|
|
||||||
connect( counterButton, &QskPushButton::clicked,
|
|
||||||
this, &View::invertCounter );
|
|
||||||
|
|
||||||
connect( submitButton, &QskPushButton::clicked,
|
|
||||||
this, &View::updateModel );
|
|
||||||
|
|
||||||
hBox->addStretch( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
addItem( hBox );
|
|
||||||
addSpacer( 5 );
|
|
||||||
addItem( spinBox );
|
|
||||||
addItem( textInput );
|
|
||||||
addStretch( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void toogleRow()
|
|
||||||
{
|
|
||||||
m_binder->setCurrentRow( m_binder->currentRow() == 0 ? 1 : 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateModel()
|
|
||||||
{
|
|
||||||
m_binder->submit();
|
|
||||||
|
|
||||||
const auto model = dynamic_cast< const Model* >( m_binder->model() );
|
|
||||||
model->dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
void invertCounter()
|
|
||||||
{
|
|
||||||
auto model = m_binder->model();
|
|
||||||
|
|
||||||
const auto index = model->index( m_binder->currentRow(), 0 );
|
|
||||||
|
|
||||||
auto value = model->data( index, Qt::EditRole );
|
|
||||||
model->setData( index, -value.toDouble(), Qt::EditRole );
|
|
||||||
}
|
|
||||||
|
|
||||||
QskModelObjectBinder* m_binder;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Window::Window()
|
|
||||||
{
|
|
||||||
addItem( new View() );
|
|
||||||
}
|
|
|
@ -3,12 +3,13 @@
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "Window.h"
|
#include "MainView.h"
|
||||||
|
|
||||||
#include <SkinnyShortcut.h>
|
#include <SkinnyShortcut.h>
|
||||||
|
|
||||||
#include <QskFocusIndicator.h>
|
|
||||||
#include <QskObjectCounter.h>
|
#include <QskObjectCounter.h>
|
||||||
|
#include <QskFocusIndicator.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
|
@ -22,13 +23,14 @@ int main( int argc, char* argv[] )
|
||||||
|
|
||||||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||||
|
|
||||||
Window window;
|
QskWindow window;
|
||||||
window.resize( 600, 400 );
|
window.resize( 600, 400 );
|
||||||
|
|
||||||
auto focusIndicator = new QskFocusIndicator();
|
auto focusIndicator = new QskFocusIndicator();
|
||||||
focusIndicator->setObjectName( "FocusIndicator" );
|
focusIndicator->setObjectName( "FocusIndicator" );
|
||||||
|
|
||||||
window.addItem( focusIndicator );
|
window.addItem( focusIndicator );
|
||||||
|
window.addItem( new MainView() );
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|
|
@ -133,8 +133,8 @@ void QskModelObjectBinder::bindObject(
|
||||||
|
|
||||||
void QskModelObjectBinder::unbindObject( QObject* object )
|
void QskModelObjectBinder::unbindObject( QObject* object )
|
||||||
{
|
{
|
||||||
auto it = m_data->bindings.find( object );
|
auto it = m_data->bindings.constFind( object );
|
||||||
if ( it != m_data->bindings.end() )
|
if ( it != m_data->bindings.constEnd() )
|
||||||
{
|
{
|
||||||
qskEnableConnections( object, this, false );
|
qskEnableConnections( object, this, false );
|
||||||
m_data->bindings.erase( it );
|
m_data->bindings.erase( it );
|
||||||
|
@ -151,6 +151,28 @@ void QskModelObjectBinder::clearBindings()
|
||||||
bindings.clear();
|
bindings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObjectList QskModelObjectBinder::boundObjects() const
|
||||||
|
{
|
||||||
|
auto& bindings = m_data->bindings;
|
||||||
|
|
||||||
|
QObjectList objects;
|
||||||
|
objects.reserve( bindings.count() );
|
||||||
|
|
||||||
|
for ( auto it = bindings.constBegin(); it != bindings.constEnd(); ++it )
|
||||||
|
objects += it.key();
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaProperty QskModelObjectBinder::boundProperty( const QObject* object ) const
|
||||||
|
{
|
||||||
|
auto it = m_data->bindings.constFind( const_cast< QObject* >( object ) );
|
||||||
|
if ( it != m_data->bindings.constEnd() )
|
||||||
|
return it.value().property;
|
||||||
|
|
||||||
|
return QMetaProperty();
|
||||||
|
}
|
||||||
|
|
||||||
void QskModelObjectBinder::setModel( QAbstractItemModel* model )
|
void QskModelObjectBinder::setModel( QAbstractItemModel* model )
|
||||||
{
|
{
|
||||||
if ( model == m_data->model )
|
if ( model == m_data->model )
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class QAbstractItemModel;
|
class QAbstractItemModel;
|
||||||
|
class QMetaProperty;
|
||||||
|
|
||||||
class QSK_EXPORT QskModelObjectBinder : public QObject
|
class QSK_EXPORT QskModelObjectBinder : public QObject
|
||||||
{
|
{
|
||||||
|
@ -39,6 +40,9 @@ class QSK_EXPORT QskModelObjectBinder : public QObject
|
||||||
|
|
||||||
void unbindObject( QObject* );
|
void unbindObject( QObject* );
|
||||||
|
|
||||||
|
QMetaProperty boundProperty( const QObject* ) const;
|
||||||
|
QObjectList boundObjects() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void currentRowChanged( int );
|
void currentRowChanged( int );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue