Hello, I refactored the Tk interface example under the POE Cook Book to demonstrate how I think POE can be used to implement the MVC design for a GUI application. (use of Moose is optional). Basically my (very limited) understanding of MVC design is that there are following key elements to it 1. The Model is in charge of all the data. It does not know any details about the View. It simply notifies all the Views that are observing it of any changes. 2. A View is just that, a view into the model's data. It never save any of the actual data within itself but just attaches to the Model for it. 3. Controller is the View's interface into the Model. View will relay the user inputs/events to controller to request appropriate query/modification of the Model(data).
With this very high level understanding, I refactored the Tk Interface example. Does the code/design below make sense? Looking for your comments/suggestions/critic. BR --- DCP ############################################################################################ #!/usr/bin/perl use strict; use warnings; #---- The View Package package MyView; use Tk; use POE; sub new { my $class = shift; my $model = shift; #--- For this example it is associated with only one Model. #--- but can be extended easily so that it can be associated with multiple models my $self = { "Model" => $model }; bless $self, $class; $self->spawn(); return $self; } sub spawn { my $self = shift; POE::Session->create( inline_states => { _start => \&ui_start, _notify => \&handle_model_change, ev_count => \&ui_ctrl_count, ev_clear => \&ui_ctrl_clear, }, args => [$self], ); } sub attach_model { my ( $self, $model ) = @_; $self->{"Model"} = $model; $model->Register( $self->{"Session"} ) if ( defined $model ); } sub ui_start { my ( $kernel, $session, $heap, $self ) = @_[ KERNEL, SESSION, HEAP, ARG0 ]; $kernel->alias_set("COUNTERDISP"); $self->{"Session"} = "COUNTERDISP"; #--- This is the name which will register with the model #--- Attach the view to the model my $model = $self->{"Model"}; $self->attach_model($model); $heap->{"AppInstance"} = $self; $poe_main_window->Label( -text => "Counter" )->pack; #--- Note actual counter data is not stored in view but comes from Model. $heap->{counter_widget} = $poe_main_window->Label( -text => "SomeValue" )->pack; $poe_main_window->Button( -text => "Clear", -command => $session->postback("ev_clear") )->pack; $kernel->yield("ev_count"); } #--- Model sends a _notify event to all the registered observers. #--- This view uses following function for handling the _notify event sub handle_model_change { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; my $self = $heap->{"AppInstance"}; my $counter = $self->{"Model"}->counter(); #--- Get the relevant data from the model. $heap->{counter_widget}->configure( -text => $counter ); #--- Update view $poe_main_window->update; # Needed on SunOS & MacOS-X } #--- Controller for this view to act upon a user input and request #--- a change to the Model sub ui_ctrl_count { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; my $self = $heap->{"AppInstance"}; #--- Send a request to the Model to increment the count $self->{"Model"}->inc_counter(); $_[KERNEL]->yield("ev_count"); } sub ui_ctrl_clear { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; my $self = $heap->{"AppInstance"}; $self->{"Model"}->reset_counter(); } #---- Tne Model Package package MyModel; use POE; use Moose; use Moose::Util::TypeConstraints; has 'counter' => ( traits => ['Counter'], is => 'rw', isa => 'Num', default => 0, handles => { inc_counter => 'inc', dec_counter => 'dec', reset_counter => 'reset', }, trigger => \&_notify_observers ); has 'Observers' => ( traits => ['Array'], default => sub { [] }, is => 'rw', isa => 'ArrayRef[Str]', handles => { all_Observers => 'elements', add_Observer => 'push', }, ); #--- Method for views to register to this model as observers sub Register { my $self = shift; my $session = shift; $self->add_Observer($session) if ( defined $session ); } #--- Method to notify all the views observing this model of any change sub _notify_observers { my $self = shift; return if ( !defined $self->all_Observers() ); my @List_of_Observers = @{ $self->Observers() }; foreach my $observer (@List_of_Observers) { POE::Kernel->post( $observer, "_notify" ); } } #--- The main app package main; my $SM = new MyModel; my $SV = new MyView($SM); #--- Create a view and attach to the Model POE::Kernel->run(); ############################################################################################