-
-
Save rsrg/fb62bd09f8b29e7141977ba5331903a5 to your computer and use it in GitHub Desktop.
wxPerl program showing MVC design pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
# An example of trivial wxPerl application using a | |
# Model-View-Controller architecture. | |
# Copyright 2014 Johan Vromans. All rights reserved. | |
# License: Artistic. | |
package Publisher; | |
# Trivial Publish/Subscribe handler. | |
my %subs; | |
sub send_message { | |
my ( $self, $tag, $param ) = @_; | |
next unless $subs{$tag}; | |
foreach ( @{ $subs{$tag} } ) { | |
eval { $_->( $tag, $param ) }; | |
} | |
} | |
sub subscribe { | |
my ( $self, $sub, $tag ) = @_; | |
$subs{$tag} //= []; | |
push( @{ $subs{$tag} }, $sub ); | |
} | |
package Model; | |
# This is where the money^Wdata and logic is. | |
# Nothing GUI oriented here. | |
sub new { | |
my ( $pkg ) = @_; | |
my $self = bless { money => 0 }, $pkg; | |
$self; | |
} | |
sub add_money { | |
my ( $self, $value ) = @_; | |
$self->{money} += $value; | |
# Now tell anyone who cares that the value has been changed. | |
Publisher->send_message( "MONEY CHANGED", $self->{money} ); | |
} | |
sub remove_money { | |
my ( $self, $value) = @_; | |
$self->{money} -= $value; | |
# Now tell anyone who cares that the value has been changed. | |
Publisher->send_message( "MONEY CHANGED", $self->{money} ); | |
} | |
package View; | |
# A GUI element -- a window (Wx::Frame) that shows the current value. | |
use Wx qw( :window :sizer ); | |
use base qw( Wx::Frame ); | |
sub new { | |
my ( $pkg, $parent ) = @_; | |
my $self = $pkg->SUPER::new( $parent, -1, "Main View" ); | |
my $sizer = Wx::BoxSizer->new(wxVERTICAL); | |
my $text = Wx::StaticText->new( $self, -1, "My Money" ); | |
my $ctrl = Wx::TextCtrl->new( $self, -1, "" ); | |
$sizer->Add( $text, 0, wxEXPAND | wxALL ); | |
$sizer->Add( $ctrl, 0, wxEXPAND | wxALL ); | |
$self->{moneyCtrl} = $ctrl; | |
$ctrl->SetEditable(0); | |
$self->SetSizer($sizer); | |
$self; | |
} | |
sub set_money { | |
my ( $self, $money ) = @_; | |
$self->{moneyCtrl}->SetValue($money); | |
} | |
package ChangerWidget; | |
# A GUI element -- a window (Wx::Frame) that allows changing the value. | |
use Wx qw( :window :sizer ); | |
use base qw( Wx::Frame ); | |
sub new { | |
my ( $pkg, $parent ) = @_; | |
my $self = $pkg->SUPER::new ( $parent, -1, "Main View" ); | |
my $sizer = Wx::BoxSizer->new(wxVERTICAL); | |
$self->{add} = Wx::Button->new( $self, -1, "Add Money" ); | |
$self->{remove} = Wx::Button->new( $self, -1, "Remove Money" ); | |
$sizer->Add( $self->{add}, 0, wxEXPAND | wxALL ); | |
$sizer->Add( $self->{remove}, 0, wxEXPAND | wxALL); | |
$self->SetSizer($sizer); | |
$self; | |
} | |
sub register { | |
my ( $self, $op, $code ) = @_; | |
Wx::Event::EVT_BUTTON( $self, $self->{$op}->GetId, $code ); | |
} | |
package Controller; | |
# This is the controller. | |
# Nothing GUI oriented here. | |
# No business logic, just connecting things. | |
sub new { | |
my ( $pkg, $app ) = @_; | |
my $self = bless {}, $pkg; | |
$self->{model} = Model->new; | |
# Set up the first frame which displays the current Model value. | |
my $view = View->new; | |
$view->set_money( $self->{model}->{money} ); | |
# Set up the second frame which allows the user to modify the Model's value. | |
my $changer = ChangerWidget->new( $view ); | |
# Register our functions to ChangerWidget operations. | |
$changer->register( "add", sub { $self->add_money } ); | |
$changer->register( "remove", sub { $self->remove_money } ); | |
# Subscribe to all "MONEY CHANGED" messages from the Model | |
# to subscribe to ALL messages (topics), omit the second argument below. | |
Publisher->subscribe( sub { money_changed( $self, @_ ) }, "MONEY CHANGED" ); | |
$view->Show(1); | |
$changer->Show(1); | |
$self->{view} = $view; | |
$self; | |
} | |
sub add_money { | |
my ( $self, $evt ) = @_; | |
$self->{model}->add_money(10); | |
} | |
sub remove_money { | |
my ( $self, $evt ) = @_; | |
$self->{model}->remove_money(10); | |
} | |
sub money_changed { | |
my ( $self, $tag, $data ) = @_; | |
# This method is the handler for "MONEY CHANGED" messages, | |
# which Publisher will call as messages are sent from the model. | |
# | |
# We already know the topic is "MONEY CHANGED", but if we | |
# didn't, $tag would tell us. | |
$self->{view}->set_money($data); | |
} | |
package main; | |
# The main program. Fairly standard. | |
no warnings qw( redefine once ); | |
local *Wx::App::OnInit = sub{1}; | |
my $app = Wx::App->new(); | |
Controller->new($app); | |
$app->MainLoop(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment