65.9K
CodeProject 正在变化。 阅读更多。
Home

Perl/Tk 使用组合设计模式进行 GUI 建模

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2018年12月14日

CPOL

12分钟阅读

viewsIcon

8838

downloadIcon

90

本文档分为“设计”和“示例”两部分。“设计”部分讨论了通过组合设计模式为命令行实用程序开发 GUI 的通用方法,而“示例”部分则介绍了如何使用上述 GUI 设计公式来开发 DoS 安全工具 DataPool 的 GUI。

目录

  • 1. 引言
  • 2. 设计
    • 2.1 设计细节
      • 2.1.1 组件说明
        • 2.1.1.1 资源文件
        • 2.1.1.2 特定于控件的文件
        • 2.1.1.3 杂项文件
        • 2.1.1.4 主程序
      • 2.2 程序执行
      • 2.3 目标目录结构
        • 2.3.1 具有界面的应用程序
  • 3. 示例 (DataPool DoS 工具)
    • 3.1 关于工具
    • 3.2 关于 GUI 提案
      • 3.2.1 主窗口
        • 3.2.1.1 框架层次结构和元素
        • 3.2.1.2 菜单外观
        • 3.2.1.3 分离的控制台外观
    • 3.3 目标目录结构
    • 3.4 工具安装
    • 3.5 GUI 截图
      • 3.5.1 主窗口 (LINUX & WINDOWS XP)
      • 3.5.2 控制台在新窗口中分离
      • 3.5.3 主窗口中移除可选选项
      • 3.5.4 打开文件进行读取
  • 4. 总结
  • 5. 参考资料

1. 引言

通用图形用户界面 (GUI) 开发方法是一种通过一组预定义的规则(即配置文件)和库来生成图形用户界面的概念。此框架也可用于为某些命令行实用程序生成图形模型。图形规则在配置文件(资源文件)中声明,编辑配置文件(添加/删除/更改 GUI 元素)可以在运行时更改 GUI 的外观和感觉。Perl/Tk 代码应保持不变。

本文档分为“设计”和“示例”两部分。“设计”部分讨论了通过组合设计模式为命令行实用程序开发 GUI 的通用方法,而“示例”部分则介绍了如何使用上述 GUI 设计公式来开发 DoS 安全工具 DataPool 的 GUI。 

2. 设计(章节)

2.1 设计细节

通用 GUI 设计架构分布在四个组件中。

  1. 资源文件 - 包含图形布局声明的文件。通常是分层结构,一个图形元素包含其他元素。例如,一个框架控件可以包含另一个框架控件、一个顶级控件或任何叶子控件(列表框、编辑框、标签等)。
  2. 特定于控件的包 - Perl/Tk 控件类的包装器,用于解释(从资源文件中解析)图形布局,然后使用 Perl/Tk API 动态创建(处理)控件。例如 DtFrame.pm(用于 Frame 控件)、DtToplevel.pm(用于 Toplevel 控件)、DtMenu.pm(用于 Menu 控件)等。Dt 是前缀,以区别于实际的控件类名。
  3. 杂项/实用程序包 - 杂项/库子程序,例如 enablewidget、disablewidget 等...
  4. 主程序 - 调用控件包装器模块来解析资源文件以创建实际控件的中间程序。然后它负责处理事件。
                            ---
                            | |
                            ------------
                            |   Util   |
                            |          |
                            ------------
                                 ^ |
                                 | |
                                 | |
                                 | |
                                 | |
                                 | |
                                 | |
   ---                       --- | |                       ---
   | |                       | | | v                       | |
   ---------- <<create/      ----------- <<read res. to    --------------
   |        | manipulate/    |Widget   |------------------>|  Resource  |
   |  Main  |--------------->|Wrapper  | create widget>>   |(Persistent)|
   |        | destroy        |         |<------------------|            |
   ---------- widgets>>      -----------        <<callback --------------
                                             registration>>
组件图
   <>---------  Aggregation
   <>.........  Composition
    ----------> Dependency                                 
   / \
    |   Generalization
    |                                  
                                        ---------            ----------
                                        | Utils |<>--------|Registry|
                                        ---------            ----------
                                         1|    ^1
                                          |    |
                                          |    |
                                          |    |
                                      1..*v    |1
                                         ----------------
              ..........................>|<<interface>> |<...............
              . ........................>|    shape     |               .
              . .                        ----------------               .
              . .                       / \  / \  / \  / \              .
              . .                        -    -    -    -               .
              . .                        |    |    |    |               .
              . .                        |    |    |    |               .
              . .        -----------------    |    |    |               .
              . .        |             --------    |    -----------     .
              . .        |             |           |              |     .
              . .        |             |           |              |     .
              . .        |             |           |              |     .
   --------   . .    ----------     ------     ---------      -------   .
   |Main  |<>.. ...<>|Toplevel|     |Menu|     |Leaf   |      |Frame|<>.. 
   |Window|          ----------     ------     |Widget |      -------
   --------                                    ---------
类图(组合设计模式)

Shape 类作为所有控件类的基类。Shape 类调用 utils/library 组件类以获取库/实用程序函数。

2.1.1 组件说明

2.1.1.1 资源文件

资源文件包含 GUI 布局的规范,其中控件是图形的基本元素。控件之间存在父子关系。父控件包含子控件,子控件又作为其他子控件的父控件。例如,一个 TopLevel 控件包含菜单、框架,而一个框架可以包含许多叶子控件,如 Button、Radio Button、Entries 等。通常主程序会调用 Toplevel 包装器类的 new 方法,传递资源文件名。Toplevel::new 解析资源文件,如果未指定 Toplevel 名称,则读取资源文件中声明的第一个 toplevel。通常会是 MainWindow(稍后将更改为单独声明 MainWindow)。程序可以读取多个资源文件。

例如,假设 application.res 是一个具有以下布局的资源文件。

    Toplevel_MainWindow {
       Menu_1 {
           [
               [
                   'cascade',
                   '~File',
                   -tearoff=>0,
                   -menuitems=>
                   [               
                       [
                           'command',
                           '~exit',
                           -command=>sub{exit}
                       ]
                   ]
               ]
           ]
       }
       Frame_1 {
           Button_1 {
               -text => 'OK'
               wm:pack
               -side=>'left'
           }
           Button_2 {
               -text=> 'CANCEL',
               -command=>sub {exit}
           }
           -borderwidth=>2,
           -relief=>'groove'
         }
   }

在此,一个 toplevel (Toplevel_MainWindow) 包含 Menus(Menu_1) 和 Frame_1,而 Frame_1 包含叶子控件 Button_1 和 Button_2。布局中控件的父子关系将具有以下外观。

   Toplevel_MainWindow
             |
             |
   -----------
   |         |
   |         |
   Menu_1    Frame_1
             |
             |
             -------------
             |           |
             |           |
             Button_1   Button_2
 
 

   --------------------------
   |                   -[ ]X|
   --------------------------
   | File                   |
   |------------------------|
   |[OK] [Cancel]           |
   --------------------------
图像控制台外观

现在,在 Frame_1 的新子框架 Frame_1_1 中添加一个编辑框,并在 Frame_1_2 中添加 OK 和 CANCEL 按钮。假设新的添加在文件 application1.res 中。application1.res 布局如下

   Toplevel_MainWindow {
       Menu_1 {
           [
               [
                   'cascade',
                   '~File',
                   -tearoff=>0,
                   -menuitems=>
                   [               
                       [
                           'command',
                           '~exit',
                           -command=>sub{exit}
                       ]
                   ]
               ]
           ]
       }
       Frame_1 {
           Frame_1_1 {
               Label {
                   -text=>'Enter your name'
                   wm:pack
                   -side=>'left'
               }
               Entry {
                   wm:pack
                   -side=>'left'
               }
               -borderwidth=>4,
               -relief=>'groove'
           }
           Frame_1_2 {
               Button_1 {
                   -text => 'OK'
                   wm:pack
                   -side=>'left'
               }
               Button_2 {
                   -text=> 'CANCEL',
                   -command=>sub{exit}
                   wm:pack
                   -side=>'left'
               }
               -borderwidth=>4,
               -relief=>'groove'
            }
            -borderwidth=>4,
            -relief=>'groove'
        }
   }

绘制了新的父子层次结构

   Toplevel_MainWindow
           |
           |
   -----------
   |         |
   |         |
   Menu_1    Frame_1
             |
             |
             --------------
             |            |
             |            |
             Frame_1_1    Frame_1_2
             |            |
             |            |
             -------      ----------
             |     |      |        |
             |     |      |        |
             Label Entry  Button_1 Button_2
 
    
 
 
 
     --------------------------
   |                   -[ ]X|
   --------------------------
   | File                   |
   |------------------------|
   |Enter your name [      ]|
   |                        |
   |[OK] [Cancel]           |
   --------------------------
图像控制台外观

一个简单的单窗口聊天 GUI 可以这样绘制,所有用户将共享相同的窗口空间来显示消息。点击一个用户按钮将会在消息显示窗口中显示该用户相关的消息。

   Toplevel_MainWindow {
       Frame_1 {
           Frame_1_1 {
               Button_1 {
                   -text=>'USER A'
                   wm:pack
                   -ipadx=>'10',
                   -fill=>'x',
                   #-expand=>1
               }
               Button_2 {
                   -text=>'USER B'
                   wm:pack
                   -ipadx=>'10',
                   -fill=>'x',
                   #-expand=>1
               }
               Button_3 {
                   -text=>'USER C'
                   wm:pack
                   -ipadx=>'10',
                   -fill=>'x',
                   #-expand=>1
               }
               wm:pack
               -side=>'left',
               -fill=>'both',
               -expand=>1
           }
           Frame_1_3 {
               Button_1 {
                   -text=>'USER D'
                   wm:pack
                   -ipadx=>'10',
                   -fill=>'x',
               }  
               wm:pack
               -side=>'right',
               -fill=>'both',
               -expand=>1
           }
           Frame_1_2 {
               ~Scrolled_1 {
                   'ROText',
                   -scrollbars=>'se',
                   wm:pack
                   -fill=>'both',
                   -expand=>1
               }
               wm:pack
               -side=>'left',
               -fill=>'both',
               -expand=>1
           }
           wm:pack
           -fill=>'both',
           -expand=>1
       }
       Frame_2 {
           Label {
               -text=>'Type message below'
           }
           Frame_2_1 {
               Entry {
                   wm:pack
                   -side=>'left',
                   -fill=>'both',
                   -expand=>1
               }
               Button_2 {
                   -text=>'Cancel'
                   wm:pack
                   -side=>'right'
               }
               Button_1 {
                   -text=>'SEND'
                   wm:pack
                   -side=>'right'
               }
               wm:pack
               -fill=>'both',
               -expand=>1
           }
           wm:pack
           -fill=>'both',
           -expand=>1
       }
   }
   Toplevel_MainWindow
              |
              |
   ------------------------------------------
   |                                        |
   |                                        |
   Frame_2                                  Frame_1
   |                                        |
   |                                        |
   ----------                               ---------------------
   |        |                               |         |         |
   |        |                               |         |         |
   Label    Frame_2_1                       Frame_1_1 Frame_1_2 Frame_1_3
            |                               |         |         |
            |                               |         |         |
            ----------------                |         ROText    Button_1
            |     |        |                |               
            |     |        |                -------------------
            Entry Button_1 Button_2         |        |        |
                                            |        |        |
                                            Button_1 Button_2 Button_3


    ----------------------------------------------------
   |                                             -[ ]X|
   ----------------------------------------------------
   | User A  |                             | User D   |
   | User B  |                             |          |
   | User C  |                             |          |
   |         |                             |          |
   |         |                             |          |
   |         |                             |          |
   |         |                             |          |
   |         |                             |          |
   |         |                             |          |
   |         |                             |          |
   ---------------------------------------------------
   |           Type message below                     |
   |  ---------------------------------               |
   | |                                 |[SEND][Cancel]|
   | |                                 |              |
   |  ---------------------------------               |
    --------------------------------------------------
图像控制台外观

单窗口聊天 GUI

资源文件布局中控件的各个部分。每个控件声明包含三个部分:

  1. 控件属性。这是控件的图形属性,例如颜色、大小等,它将被直接馈送到 Perl 解释器。语法与 Perl/Tk 相同。请参考 Perl/Tk 文档。
  2. 几何管理器属性。这是用于控件在父窗口中的图形位置和布局。它具有“wm:<几何管理器名称>”的语法,后跟属性。常见的几何管理器有 pack、grid、place 和 form。请参考 Perl/Tk 文档。同样,属性将被直接馈送到 Perl/Tk 解释器。
  3. 杂项函数声明。这将在创建控件时被调用。它具有“MISC:”的语法,后跟杂项变量赋值、函数声明和回调声明(例如,用于事件绑定的 bind)。在此部分中进行的所有语句将在控件创建后立即调用。关键字 'this' 表示当前控件实例。

例如,

1       Frame_3_2 {
2           Checkbutton {
3               -text=>"Enable simultanious attack",
4               -variable=>\$IWsimultaniouscheckbutton,
5               -command=>[\&enabledisablewidget,
'$IWsimultaniouscheckbutton',q/getwidget('Toplevel_1.Frame_3.
Frame_3_2.Frame_3_2_1.Entry')/]
6               wm:pack
7               -side=>'left',
8               -anchor=>'center'
9           }
10          Frame_3_2_1 {
11              Entry {
12                  MISC:
13                  disablewidget(this)
14              }
15             
wm:pack
16              -side=>'left'
17          }
18          wm:pack
19          -side=>'left',
20          -fill=>'x',
21          -expand=>1
22          MISC:
23          $DtMenu::IWenablesimultaneousattacks=1;
24      }

在上面的示例中,第 3-5 行是 Checkbutton 的控件属性,第 7-8 行是 checkbutton 的几何管理器属性,第 13 行是在 Entry 控件创建后调用的杂项函数(util sub disablewidget),'this' 关键字用于物理控件引用,第 19-21 行是 Frame_3_2 的控件属性,第 23 行是在 Frame_3_2 控件创建后立即进行的杂项变量赋值。

其他需要注意的点是

  • 这里 pack 是几何管理器,所以使用 'gm:pack' 作为关键字。其他要使用的几何管理器有 Grid、Place 和 Form。
  • 这里的 disablewidget(this); 语句将调用 disablewidget 函数(一个库函数),传递当前控件的实例引用。$DtMenu::IWenablesimultaneousattacks=1; 将把值 1 赋给 $DtMenu 包变量 Iwenablesimultaneousattacks。

以下图示说明了 pack 几何管理器的基本原理。

  Filling rectangle, "-fill=>x"
   fill in horizontal direction
   "-fill=>'both' in both dir.
                   \
                    \
                     \
                      \
   ___________________|____________________________________
   |------------------|-----^---------------------------- |  Drawn Window
   ||              ...v.....|..........                  ||      /
   ||              . ---------------- .                  ||     /
   ||          <-----| Drawn Object |---------->         ||    /
   ||              . ---------------- Anchor 'e'         ||<--
   ||              .........|..........                  ||
   ||                       |                            ||
   |------------------------v---------------------------- |
   |                                               ^      |
   |                                               |      |
   |                                               |      |
   |                                               \      |
   |                                                \     |
   |                                                 \    |
   |                                                  ------- 'Top'
   |                                                      |Allocation
   |                                                      |Rectangle
   |                                                      |default
   |                                                      |geometry
   |                                                      |property
   |                                                      |-side=>'lop'
   --------------------------------------------------------

有关详细描述,请参考 Perl/Tk 手册。 

2.1.1.2 特定于控件的文件

特定于控件的文件充当实际控件的包装器类,并负责控件的创建直到销毁。即 DtToplevel->Toplevel, DtFrame->Frame, DtMenu->Menu 等。如果某个控件的包装器类不可用,则会调用 Shape (Base) 类中的子例程。典型的程序流程是,主程序调用 Toplevel 控件包装器的 new 子例程,传递资源文件进行读取。Toplevel 类 new 子例程会创建主窗口,如果主窗口未创建,则解析资源文件直到找到第一个 Toplevel 布局。Toplevel 声明的代码部分被传递给 Shape::new 以进行递归操作。Base::new 解析 Toplevel 控件代码,一旦找到特定于控件的关键字(例如 Menu、Button、Frame 等),它就会调用特定于控件的包装器的 createwidget 子例程来创建物理控件。然后它调用刚刚创建的控件的 new 子例程,传递特定于该控件的布局代码。不处理 new 子例程的控件包装器类会将此调用再次传递给 Shape::new,因此会递归创建属于当前控件的子控件。这是使用深度优先算法进行的递归操作。

例如,在资源文件声明中

   .
      Toplevel_1{
       Menu_1{
            [
                [
                    'cascade',
                    '~File',
                    -tearoff=>0,
                    -menuitems =>
                    [

主程序将调用“Toplevel”控件包装器类的 new 子例程,Toplevel 包装器类将调用 Menu 资源包装器类。如果 Menu 资源包装器类不可用,则会调用“Shape”基类函数。此过程具有递归性,采用深度优先算法。

DtCheckbutton.pm 包装器在 checkbutton 控件类上的示例

   ////////////////DtCheckbutton.pm/////////////
   1       package DtCheckbutton;
   2       use base qw(DtShape);
   3       sub createwidget {
   4           my ($class,$parentwidget,$widgetclass,$widgetproperty,$wm,$wmdata,$functionlistref)=@_;
   5           my $parentwidgetstring;
   6           $parentwidget=$parentwidget->$widgetclass(eval $widgetproperty)->$wm(eval $wmdata);
   7           $parentwidgetstring='$parentwidget';
   8           foreach my $function(@{$functionlistref}) {
   9               $function=~s/\bthis\b/$parentwidgetstring/g;
   10              eval $function;
   11          }
   12          return $parentwidget;
   13      }
   14
   15      sub AUTOLOAD {
   16          my $program=$AUTOLOAD;
   17          $program=~s/^.*:://;
   18          eval q/DtCheckbutton->SUPER::/.$program.q/(@_)/;
   20      }
   21      1;
   ////////////////DtCheckbutton.pm///////////////

在这里,第 2 行 DtShape 被引用为基类。第 3 行定义了 createwidget 的子例程,第 15 行是 AUTOLOAD 子例程,当函数未声明时(用于资源文件中的 MISC 函数)会被调用。然后它会将函数调用传递给基类(SUPER)类。

   --------> Subroutine call
   ........> Subroutine return
 
                                  ----------
   ------     ---------------     |Resource|    ------------  -----------
   |Main|     |Widget       |     |File    |    |Shape::new|  |Subwidget|
   ------     |(Ex.Toplevel)|     ----------    ------------  -----------
     |        ---------------         |               |             |
     |               |                |               |             |
     |_<<call new sub routine passing file name as argument>>       |
     ||------------->|                |               |             |
     |-              |                |               |             |
     |               |_ <<Read file for first instance of Widget    |
     |               ||-------------->|               |             |
     |               |- decaration>>  |               |             |
     |               |                |               |             |
     |               |_<<Pass widget code from resource file>>      |
     |               ||------------------------------>|             |
     |               |-               |               |             |
     |               |                |               |             |
     |<<call createwidget sub. for actual widget     _|             |
     |               |<------------------------------||             |
     |               |  creation>>    |              -|             |
     |               |                |               |             |
     |               |_ <<returns widget reference, now it will be  |
     |               ||.............................->|             |
     |               |- parent for any subwidget declared in resour.|
     |               |                |               |             |
     |               |                |               |  (1)        |
   <<calls new sub. for all subwidgets found for the parent widget>>|
     |               |                |               |_            |
     |               |                |               ||----------->|
     |               |                |               |-            |
     |               |                |               |             |
     |               |    <<call delegated to Base class new sub>> _|
     |               |                |               |<-----------||
     |               |                |               |            -|
     |               |                |               |             |
              <<call createwidget sub. to create the actual widget>>|
     |               |                |               |_            |
     |               |                |               ||----------->|
     |               |                |               |-            |
     |               |                |               |             |
     |<<return widget ref., now it will be parent to any subwidget _|
     |               |                |               |<...........||
     |               |                 declared in resource file>> -|
     |               |                |               |             |
     |<<repeat from step (1) for other subwidgets of _|             |
     |               |<..............................||             |
     |of the current widget. Depth first recursive>> -|             |
     |               |                |               |             |
     |  <<return>>  _|                |               |             |
     |<.............||                |               |             |
     |              -|                |               |             |
调用流程的序列图

2.1.1.3 杂项文件

杂项文件保留需要通过其他模块(例如资源文件、包装器控件类和主程序)配置/调用的杂项(库)子例程。杂项文件的一个重要属性是将框架相关信息保存在注册表中。MainWindow、Toplevel 窗口资源名称和其他全局信息保存在注册表中。

DtUtils 包(一个杂项包)的导出头。

   //////////////////DtUtils.pm////////////////
   package DtUtils;
   BEGIN {
      use Exporter ();
      our (@ISA,@EXPORT,@EXPORT_OK,%EXPORT_TAGS);
      @ISA=qw(Exporter);
      @EXPORT=qw(enabledisablewidget disablewidget addattacks
         deleteattacks detachconsole attachconsole mainwindow
          toplevelwidgetname getwidget);
      @EXPORT_OK=();
      %EXPORT_TAGS=();
     }
   our @EXPORT_OK;
   .
   .
   ////////////////DtUtils.pm/////////////////

DtUtils.pm 中的 enablewidget 和 disablewidget 子例程

////////////////DtUtils.pm///////////////
   sub disablewidget {
       my $class=shift;
       my $widget=$class;
       $widget=shift if @_;
       my $changecolor=shift if @_;
       my @bindtags;
       if(ref $widget) {
           $widget->configure(-background=>'#BBBBBB') if !defined $changecolor;
           @bindtags=$widget->bindtags;
           if ($bindtags[0]=~/^Tk::/) {
               $widget->bindtags([@bindtags[1,0,2,3]]);
               $widget->bind('<Button>'=>sub{$_[0]->break});
               $widget->bind('<Key>'=>sub{$_[0]->break});
           }
       }
   }
   sub enablewidget {
       my $class=shift;
       my $widget=$class;
       $widget=shift if @_;
       my $changecolor=shift if @_;
       my @bindtags;
       if(ref $widget) {
        $widget->configure(-background=>'grey') if !defined $changecolor;
        @bindtags=$widget->bindtags;
        if ($bindtags[0]!~/^Tk::/) {
            $widget->bindtags([@bindtags[1,0,2,3]]);
            $widget->bind('<Button-1>'=>undef);
        }
       }
   }
 ////////////////////DtUtils.pm///////////////

2.1.1.4 主程序

主程序是引导文件,负责让控件包装器读取资源文件,开始创建物理控件并相应地构建各种事件的事件映射。然后它进入事件主循环。通常主程序调用 Toplevel::new 方法,将资源文件名作为参数传递给它(即 DtTopLevel->new(dtplgui.res)。如果没有参数,则默认使用与主程序同名的资源文件。这里将是 dtplgui.res,因为主程序名为 dtplgui.pl。从 DtTopLevel 包的 new 方法开始,当未指定 Toplevel 时,它将拾取资源文件中的第一个 Toplevel 声明。通常这是主窗口的声明。 

   /////////application.pl, main program.//////////
   1   #!/usr/bin/perl -w
   2   use Tk;
   3   use Tk::ROText;
   4   use lib "../Lib";
   5   use DtToplevel;
   6   use DtMenu;
   7   use DtButton;
   8   use DtScrolled;
   9   use DtCheckbutton;
 
   10  if (@ARGV) {
   11    $mw=DtToplevel->new($ARGV[0]);
   12  } else {
   13      $mw=DtToplevel->new('application.res');
   14  }
   15  $mw->title("Application");
   16  my $iconptr=$mw->Photo(-file=>'image.GIF',-format=>'GIF',-width=>'32',-height=>'32');
   17  $mw->iconimage($iconptr);
   18  MainLoop;
   //////////application.pl//////////////////////

2.2 程序执行

有两种方法可以读取资源文件并启动 GUI。第一种方法是将资源文件名作为命令行参数传递(一次一个文件)。 

示例

application.pl application.res

另一种方法是调用 DtTopLevel::new 方法并传递资源文件名。它还接受要从资源文件中读取并然后生成 Toplevel 的名称。

示例

DtTopLevel->new('application1.res');
DtTopLevel->new($wm,'Toplevel_2');

这里 $wm 是已创建的主窗口引用。

2.3 目标目录结构

源代码分布在 GUIGeneric 目录中。它有两个子目录 Application 和 LIB。Application 包含应用程序特定的文件(button.pm application.pl, application.res 等),而 LIB 包含各种库文件,包括实用程序模块和一些控件模块/包装器(DtCheckbutton.pm, DtMenu.pm, DtScrolled.pm, DtShape.pm, DtToplevel.pm, DtUtils.pm 和 DtRegistry.pm)。

   GUIGeneric(DIR)
      |
      |
      +------------------+
      |                  |
      |                  |
      Application(DIR)   LIB(DIR)
      |                  |
      |                  |
      application.pl     DtCheckbutton.pm
      application.res    DtMenu.pm
                         DtScrolled.pm
                         DtShape.pm
                         DtToplevel.pm
                         DtUtils.pm
                         DtRegistry.pm

LIB 目录可以通过设置 PERL5LIB 环境变量指向 LIB 目录,或在 Perl 脚本本身中使用“use lib”声明来链接到 Application。

示例

在 application.pl 的第 4 行(见最后一段程序)是 'use lib "../Lib"'。

如果需要生成相关的 GUI 接口,则可以设计目录结构以适应各种命令行执行方式。例如,一个应用程序可以通过不同的接口提供多种服务。每个接口支持一组命令行选项/服务。这样,一个应用程序就可以拥有多个命令行执行选项集。应用程序甚至可以从脚本(例如 Shell)或一组脚本执行,其中每个脚本可以执行一组命令行选项/接口或多组命令行选项/接口。或者,可能有很多应用程序,每个应用程序都支持各种接口(一组命令行选项),并且许多脚本(例如 shell)可以通过中间脚本执行应用程序接口。在目录安排方面,如果一个应用程序支持许多接口,则接口特定目录将包含接口特定的文件。例如 Perl 主文件、资源文件、任何自定义控件包装器文件。例如,如果需要编写另一个 GUI 应用程序 Application1,则需要创建一个新的目录 Application1 并将库链接到 LIB。

   GUIGeneric(DIR)  /------------ New Directory
            |      /
            |     |
            ------|--+-----------------------------+
            |     |             |                  |
            |     v             |                  |
            Application1(DIR)   Application(DIR)   LIB(DIR)
            |                   |                  |
            |                   |                  |
            application1.pl     .                  DtCheckbutton.pm
            application1.res    .                  DtMenu.pm
                                                   DtScrolled.pm
                                                   DtShape.pm
                                                   DtToplevel.pm
                                                   DtUtils.pm

2.3.1 具有界面的应用程序

   +-------+
   |       |----------O
   +-------+
单接口应用程序
   +-------+
   |       |----------O
   |       |.
   |       |.
   |       |----------O
   +-------+
多接口应用程序
   +-------+
   |       |----------O
   +-------+
   +-------+
   |       |----------O
   |       |----------O
   +-------+
     .
     .
   +-------+
   |       |----------O
   |       |.
   |       |.
   |       |----------O
   +-------+
具有各种类型的接口集
   +-------+                         ----------
   |       |----------O<-------------|        |
   +-------+                   |---//| Script |
   +-------+                   |   / |        |
   |       |----------O<--------  /  ----------
   |       |----------o           |
   +-------+                      |
     .                            |
     .                            |
   +-------+                      |
   |       |----------o           |
   |       |.                    /
   |       |.                   /
   |       |----------O<-------/
   +-------+
通过脚本调用的应用程序接口
                 .-----
   +-------+     v    |         ----------
   |       |-----O    ----------|Script11|<-\
   +-------+     ^             /----------   |
                 |            /              |
                 ------\     /               |
   +-------+            \   /                |
   |       |-----O<------\--                 \ ---------+
   |       |-----O<-      \     ----------   _\|Script21|<--
   +-------+               -----|Script12|<-/  ---------+   \
     .               \         /|        |<-      .          \ +---------
     .                \       / ----------  \     .           \|ScriptN1|
   +-------+           \     /     .         \    .           /----------
   |       |-----O<-----\---/   ----------    \----------    /
   |       |.            -------|Script1N|<----|Script22|<--/
   |       |.                  /----------     ----------
   |       |-----O<-----------/
   +-------+
脚本调用的脚本

通过脚本调用其他脚本,然后可能在更大程度上发展为图形实用程序,可以列出其他图形实用程序等等。

例如。

脚本调用脚本(二级)

   _______________________________________________
   |                Script21                     |
   -----------------------------------------------
   |File                                     Help|
   |---------------------------------------------|
   |                                             |
   |  ___________    ___________    ___________  |
   |  |         |    |         |    |         |  |
   |  |Script11 |    |Script12 |    |Script13 |  |
   |  |         |    |         |    |         |  |
   |  -----------    -----------    -----------  |
   |                                             |
   |  ___________    ___________                 |
   |  |         |    |         |                 |
   |  |Script14 |    |Script1N |                 |
   |  |         |    |         |                 |
   |  -----------    -----------                 |
   |                                             |
   |                                             |
   |---------------------------------------------|
 
 
   _______________________________________________
   |                Script11                     |
   -----------------------------------------------
   |File                                     Help|
   |---------------------------------------------|
   |               |                             |
   |               |           ..                |
   |               |       .    |   .            |
   |               |     .      |     .          |
   |               |    .       |      .         |
   |               |    .       |-------         |
   |               |     .      |     .          |
   |               |       .    |   .            |
   |               |           ..                |
   |               |                             |
   |               |                  |--|       |
   |               |               |--|  |       |
   |               |            |--|  |  |       |
   |               |         |--|  |  |  |       |
   |               |       --|  |  |  |  |       |
   |               |    --|  |  |  |  |  |       |
   |               |   |__|__|__|__|__|__|       |
   |               |                             |
   |---------------------------------------------|

3. 示例(章节)DataPool 图形用户界面构建

3.1 关于工具

Datapool (http://packetstormsecurity.org/DoS/) 是一种用于测试各种电信/网络产品是否存在潜在 DoS(拒绝服务)攻击漏洞的工具。当前版本的 datapool (3.3) 软件是 Linux 用户的命令行实用程序。命令行实用程序提供的各种选项是

   "Usage: $0 [-i] [source ip] [-v] [logfile] [-p] [portlow-porthigh] "
   "[-s] [-l] [T1|T3|OC3|Modem|Slowass] [-x] [-k] [-a] [-t] [# of attacks]"
   "[-r] [attackname]"
   "Options:"
   "[-p]: Specifies port range to scan.  ex: -p 1-1024"
   "[-x]: "Don't stop till they drop"
   "[-v]: Logs results of scan to file.  ex: -v logfile.log"
   "[-s]: Scan ports only."
   "[-l]: Specifies line speed.  Choose from T1,T3, and Modem."
   "[-i]: Specifies source IP.  ex: -i 127.0.0.1"
   "[-k]: Wait till host is online, then attack."
   "[-a]: Loop attack. (Used with -k and -x can keep a connection dropped.)"
   "[-t]: Number of simultaneous attacks to launch. ex: -t 4"
   "[-r]: Run this attack only. ex: -r onetwothreefour"

3.2 关于 GUI

该工具是 Datapool 命令行应用程序的可能图形用户界面。GUI 采用 Perl/Tk 编写,以便在 Unix/Linux 和 Windows 版本上都具有可移植性。

3.2.1 工具拟议主窗口外观和感觉

3.2.1.1 框架层次结构和元素说明

3.2.1.2 菜单外观

3.2.1.3 分离的控制台外观

3.3 目标目录结构

源代码分布在 DataPool、IO 和 LIB 三个目录中。datapoolgui.sh 和 README 位于当前/主目录中。DataPool 包含 datapool 特定文件(button.pm dtplgui.pl, dtplgui.res 等),而 LIB 包含各种库文件,包括实用程序模块和一些控件模块/包装器(DtCheckbutton.pm, DtMenu.pm, DtScrolled.pm, DtShape.pm, DtToplevel.pm, DtUtils.pm 和 DtRegistry.pm)。IO 包含 Perl CPAN 模块 (IO-Tty-1.08.tar.gz),用于创建行缓冲终端,以便写入伪终端是行缓冲的,控制台窗口中的输出将更快。

3.4 工具安装

工具安装(Red Hat Linux):工具以 zip 文件提供。可以将其解压到任何目录,然后将该目录添加到 shell 的 PATH 环境变量中。解压 IO/Pty/IO-Tty-1.08.tar 并按如下方式运行安装脚本(以安装伪终端),另请参阅提供的 README 文件。

perl Makefile.PL
make
make test
make install

工具的其余安装步骤在软件附带的 README 文件中提供。这是截图
如果未安装 Perl-Tk 和 datapool 命令行包,DataPoolGUI 将无法工作。
Perl-Tk 通常在操作系统 DVD 中提供。
Perl-Tk 也可以从相应的操作系统站点下载。datapool 也可以从互联网下载。
此 DataPoolGUI 版本 1.0.0 是为 datapool3.3 编写的。

为了与 datapool3.3 命令行版本正常工作,请编辑 <安装目录>/DataPoolGUI/DataPool/datapool.sh 以定位 datapool3.3 shell 脚本 datapool.sh。

键入 datapoolgui.sh 以启动 GUI 版本。

Windows 试用版

如果 Windows 上有 Datapool,则可以尝试。如果 Windows 计算机上没有 Perl 解释器,可以从 www.activestate.com 下载。将 zip 文件解压到某个目录。

这里 Pty(伪终端)将无法工作,因为 Windows 不支持。为了尝试 GUI 的外观和感觉,请在不带任何命令行参数的情况下执行 dtplgui.pl。

>>>dtplgui.pl

3.5 GUI 截图

3.5.1 LINUX 主窗口

WINDOWS 上的主窗口

3.5.2 控制台在新窗口中分离

3.5.3 主窗口中移除可选选项

3.5.4 打开文件进行读取

4. 总结

Datapool GUI 是通过组合结构设计模式开发的,用户可以遵循一组规则来生成 GUI。在这里,对于安全工具 Datapool 的用户界面,用户可以获得命令行用户界面提供的所有可能选项。Perl/Tk 实现使得在安装了 Perl/Tk 和 Datapool 的各种操作系统上进行移植成为可能。GUI 的未来版本将包含用于同时发起并行/多攻击的选项,每个攻击在一个单独的控制台中运行。

5. 参考资料

精通 Perl/Tk,Steve Lidie 和 Nancy Walsh。

© . All rights reserved.