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
|
||||
############################################################################
|
||||
|
||||
qsk_add_example(models Window.h Window.cpp main.cpp)
|
||||
qsk_add_example(models MainView.h MainView.cpp main.cpp)
|
||||
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
|
||||
|
||||
#include <QskWindow.h>
|
||||
#include <QskMainView.h>
|
||||
|
||||
class Window : public QskWindow
|
||||
class QskModelObjectBinder;
|
||||
|
||||
class MainView : public QskMainView
|
||||
{
|
||||
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
|
||||
*****************************************************************************/
|
||||
|
||||
#include "Window.h"
|
||||
#include "MainView.h"
|
||||
|
||||
#include <SkinnyShortcut.h>
|
||||
|
||||
#include <QskFocusIndicator.h>
|
||||
#include <QskObjectCounter.h>
|
||||
#include <QskFocusIndicator.h>
|
||||
#include <QskWindow.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
|
@ -22,13 +23,14 @@ int main( int argc, char* argv[] )
|
|||
|
||||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||
|
||||
Window window;
|
||||
QskWindow window;
|
||||
window.resize( 600, 400 );
|
||||
|
||||
auto focusIndicator = new QskFocusIndicator();
|
||||
focusIndicator->setObjectName( "FocusIndicator" );
|
||||
|
||||
window.addItem( focusIndicator );
|
||||
window.addItem( new MainView() );
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
|
|
|
@ -133,8 +133,8 @@ void QskModelObjectBinder::bindObject(
|
|||
|
||||
void QskModelObjectBinder::unbindObject( QObject* object )
|
||||
{
|
||||
auto it = m_data->bindings.find( object );
|
||||
if ( it != m_data->bindings.end() )
|
||||
auto it = m_data->bindings.constFind( object );
|
||||
if ( it != m_data->bindings.constEnd() )
|
||||
{
|
||||
qskEnableConnections( object, this, false );
|
||||
m_data->bindings.erase( it );
|
||||
|
@ -151,6 +151,28 @@ void QskModelObjectBinder::clearBindings()
|
|||
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 )
|
||||
{
|
||||
if ( model == m_data->model )
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <memory>
|
||||
|
||||
class QAbstractItemModel;
|
||||
class QMetaProperty;
|
||||
|
||||
class QSK_EXPORT QskModelObjectBinder : public QObject
|
||||
{
|
||||
|
@ -39,6 +40,9 @@ class QSK_EXPORT QskModelObjectBinder : public QObject
|
|||
|
||||
void unbindObject( QObject* );
|
||||
|
||||
QMetaProperty boundProperty( const QObject* ) const;
|
||||
QObjectList boundObjects() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentRowChanged( int );
|
||||
|
||||
|
|
Loading…
Reference in New Issue