Fortran Coder

查看: 68808|回复: 29
打印 上一主题 下一主题

[绘图界面库] Fortran适合科学计算,同时也能编写图形用户界面!

[复制链接]

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

跳转到指定楼层
楼主
发表于 2014-1-28 17:22:42 | 显示全部楼层 |只看大图 回帖奖励 |倒序浏览 |阅读模式
如题。先举几个例子:

1.菜单、工具栏、状态栏:



2.浮动的工具栏和对话框:



3.调用OpenGL绘制贝塞尔曲面:



通过运行发现,程序的执行效率要比Tcl/TK的高!但是在代码编写的劳动量上要远远逊色于Tcl/TK、Purebasic!
贴图片仅仅用来证明Fortran也能干这些工作,当然很多人会认为这些是编译器的扩展,不足为谈。其实,其他语言何尝不是这样!

分享到:  微信微信
收藏收藏2 点赞点赞1 点踩点踩

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

沙发
 楼主| 发表于 2014-3-2 10:57:55 | 显示全部楼层
老房子 发表于 2014-3-1 19:44
待续了一个多月还是待续!

最近忙,等有空写详细些。见谅啊。

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

板凳
 楼主| 发表于 2014-3-2 21:27:48 | 显示全部楼层
本帖最后由 lm_lxt 于 2014-3-2 21:30 编辑

Fortran语言编写图形界面有下面两种途径:
1.QuickWin(其实,不建议用它!原因是程序编写没有简化多少,同时失去了灵活性。);
2.Win32 API(建议直接上手学习,楼上的例子采用了这种方法);
   参考书籍:《windows程序设计》,Petzold的大作。
   经过学习发现,Fortran在编写界面方面和C/C++没有任何区别!(除了C++的面向对象。)

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

地板
 楼主| 发表于 2014-3-3 03:21:12 | 显示全部楼层
楼上对常见的界面库已经总结了,确实,用于fortran的很少,可能winteracter 是最适合的,可惜收费!

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

5#
 楼主| 发表于 2014-3-3 11:17:43 | 显示全部楼层
fortran编译器对win32 API的接口已经严重老化,比如GDI+都还没有引入,现在的GDI绘制的直线惨不忍睹,除非加入自己的反走样代码。
从intel的编译器看,其发展方向是对fortran最新标准的支持,而相关扩展从CVF继承过来就没有什么变化,最多就是类似在opengl的相关工具库的舍弃上摇摆不定。

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

6#
 楼主| 发表于 2014-3-3 11:28:01 | 显示全部楼层
这段程序仅仅生成一个空白的窗口,如果你彻底理解了,win32编程或许没有想象的那么复杂!

[Fortran] 纯文本查看 复制代码
Module VarGlob
    integer( kind = 4 ) ::  results  ! 存储函数的返回值 
    logical( kind = 4 ) ::  logicalt  ! 存储函数的返回值 
End Module VarGlob

! windowing程序开始执行的地方(操作系统自动识别)
integer function WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'WinMain' :: WinMain
    !DEC$ ENDIF

    USE IFWIN  !包含有用的模块
    USE VarGlob  !有用的数据模块
    Implicit None

    integer( kind = 4 ) ::  hInstance  !定义窗口的实例
    integer( kind = 4 ) ::  hPrevInstance  !定义句柄
    integer( kind = 4 ) ::  nCmdShow  !窗口的显示方式
    integer( kind = 4 ) ::  lpszCmdLine  !指向字符串的指针

    !定义函数接口,注意这一段是必须的
    interface 
    integer*4 function MainWndProc ( hwnd, message, wParam, lParam )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_MainWndProc@16' :: MainWndProc
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'MainWndProc' :: MainWndProc
    !DEC$ ENDIF
    integer( kind = 4 ) ::   hwnd 
    integer( kind = 4 ) ::  message  
    integer( kind = 4 ) ::  wParam
    integer( kind = 4 ) ::   lParam 
    end function  MainWndProc
    end interface

    type (T_WNDCLASS) :: wc  !窗口类结构体  
    type (T_MSG) :: msg   !消息结构体
    integer( kind = 4 ) :: hWnd
    character*100 lpszClassName,lpszAppName

    lpszClassName = "Generic"C   !窗口类名
    lpszAppName = "windowing程序框架"C  !窗口标题

    if(hPrevInstance .eq. 0) then
        wc%lpszClassName = LOC(lpszClassName)  !窗口类名
        wc%lpfnWndProc = LOC(MainWndProc)  !窗口回调函数
        wc%style = IOR(CS_VREDRAW , CS_HREDRAW) !窗口风格
        wc%hInstance = hInstance  !窗口实例
        wc%hIcon = LoadIcon( NULL, IDI_WINLOGO)  !程序图标
        wc%hCursor = LoadCursor( NULL, IDC_CROSS )  !程序光标
        wc%hbrBackground = GetStockObject(BLACK_BRUSH)  !窗口背景颜色
        wc%lpszMenuName = 0  !菜单名
        wc%cbClsExtra = 0  !无附加消息
        wc%cbWndExtra = 0
        results = RegisterClass(wc)  !注册窗口类
    end if

    !创建窗口
    hWnd = CreateWindowEx(0,                       	&  !窗口扩展样式
                 lpszClassName,                 	&  !窗口类名
                 lpszAppName,                  	&  !窗口标题
                 INT(WS_OVERLAPPEDWINDOW),	&  !窗口的风格
                 CW_USEDEFAULT,             	&  !左上角坐标X
                 0,                            	&  !左上角坐标Y
                 CW_USEDEFAULT,                 &  !窗口宽度尺寸
                 0,                             	&  !窗口高度尺寸
                 NULL,                         	&  !父窗口句柄
                 NULL,                     	     &  !主菜单句柄
                 hInstance,                  	     &  !窗口实例句柄
                 NULL  	                        &  !附加信息的指针
                 )

    !显示窗口
    results = ShowWindow( hWnd, SW_SHOWNORMAL) 
    !进入消息循环
    do while( GetMessage (msg, NULL, 0, 0) .NEQV. .FALSE.)
     results = TranslateMessage( msg ) !翻译消息
     results = DispatchMessage( msg ) !将消息传给windows,然后由windows传给回调函数
    end do
    WinMain = msg%wParam
End function WinMain

    
integer function MainWndProc ( hWnd, message, wParam, lParam )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_MainWndProc@16' :: MainWndProc
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'MainWndProc' :: MainWndProc
    !DEC$ ENDIF

    USE IFWIN  !包含有用的模块
    USE VarGlob  !有用的数据模块
    Implicit None

    integer( kind = 4 ) ::   hwnd 
    integer( kind = 4 ) ::  message  
    integer( kind = 4 ) ::  wParam
    integer( kind = 4 ) ::   lParam 

    select case ( message )
         case (WM_DESTROY)
            call PostQuitMessage( 0 )
         case default
            MainWndProc = DefWindowProc( hWnd, message, wParam, lParam )
    end select
end function MainWndProc


运行结果:

                              

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

7#
 楼主| 发表于 2014-3-3 11:43:45 | 显示全部楼层
程序解读:

程序001-004:请翻阅fortran语法书籍,其实就是定义了results 、 logicalt两个变量而已。这两个变量用来存储win32API函数的返回值。因为好多 win32API函数的返回值是没有任何用处的,所以好多时候我们机械式地将其塞入这两个变量就再也不管了。

程序007-083:这段程序看起来很长,总体来讲完成了这样的几个任务:描述窗口的基本特征(如窗口的背景色);创建窗口;显示窗口;捕获事件并送给操作系统(在窗口上单击一次鼠标就是一个“事件”)。

程序086-108:这块代码异常重要!主要是甄别各种事件并作出响应。

好了,请再次阅读上述代码并理解上面的解释性文字。详细的解读待续。

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

8#
 楼主| 发表于 2014-3-3 12:13:53 | 显示全部楼层
08-012:条件编译指令,为了兼容不同架构的机器。
               补上下面的一段解释:
               A Windows Application is a special form of application that has an entry point of a user function named WinMain. On IA-32 architecture systems, WinMain must be a STDCALL-convention function with a decorated name of _WinMain@16; on the Intel® 64 and IA-64 architectures, the name is simply WinMain.

               或者直接跳过它,仅仅知道这是必须的一段代码!

               如果省略它,会出现编译错误:
               1>------ 已启动生成: 项目: WinApp2, 配置: Debug Win32 ------
               1>Compiling with Intel(R) Visual Fortran Compiler XE 13.1.1.171 [IA-32]...
               1>Source1.f90
               1>Linking...
               1>LIBCMTD.lib(wincrt0.obj) : error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCRTStartup 中被引用
               1>Debug\WinApp2.exe : fatal error LNK1120: 1 个无法解析的外部命令

98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

9#
 楼主| 发表于 2014-3-3 20:22:37 | 显示全部楼层
本帖最后由 lm_lxt 于 2014-3-3 20:24 编辑

程序014-016:包含模块,便于调用win32api;
程序018-021:每个入口函数都需要这四个参数,照猫画虎定义就行。具体的含义请阅读相书籍;
程序023-036:函数接口,说明下面将要调用的函数长得什么样子。主要是026-030的代码,031-034行代码可有可无;这块代码的位置有点突兀,如果我按照下面这样整理一下,或许好理解一些:

[Fortran] 纯文本查看 复制代码
Module VarGlob
    integer( kind = 4 ) ::  results  ! 存储函数的返回值 
    logical( kind = 4 ) ::  logicalt  ! 存储函数的返回值 
End Module VarGlob
    
Module VarGlob1    
    !定义函数接口,注意这一段是必须的
    interface 
    integer*4 function MainWndProc ( hwnd, message, wParam, lParam )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_MainWndProc@16' :: MainWndProc
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'MainWndProc' :: MainWndProc
    !DEC$ ENDIF
    integer( kind = 4 ) ::   hwnd 
    integer( kind = 4 ) ::  message  
    integer( kind = 4 ) ::  wParam
    integer( kind = 4 ) ::   lParam 
    end function  MainWndProc
    end interface
End Module VarGlob1

! windowing程序开始执行的地方(操作系统自动识别)
integer function WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'WinMain' :: WinMain
    !DEC$ ENDIF

    USE IFWIN  !包含有用的模块
    USE VarGlob  !有用的数据模块
    USE VarGlob1
    Implicit None

    integer( kind = 4 ) ::  hInstance  !定义窗口的实例
    integer( kind = 4 ) ::  hPrevInstance  !定义句柄
    integer( kind = 4 ) ::  nCmdShow  !窗口的显示方式
    integer( kind = 4 ) ::  lpszCmdLine  !指向字符串的指针

    type (T_WNDCLASS) :: wc  !窗口类结构体  
    type (T_MSG) :: msg   !消息结构体
    integer( kind = 4 ) :: hWnd
    character*100 lpszClassName,lpszAppName

    lpszClassName = "Generic"C   !窗口类名
    lpszAppName = "windowing程序框架"C  !窗口标题

    if(hPrevInstance .eq. 0) then
        wc%lpszClassName = LOC(lpszClassName)  !窗口类名
        wc%lpfnWndProc = LOC(MainWndProc)  !窗口回调函数
        wc%style = IOR(CS_VREDRAW , CS_HREDRAW) !窗口风格
        wc%hInstance = hInstance  !窗口实例
        wc%hIcon = LoadIcon( NULL, IDI_WINLOGO)  !程序图标
        wc%hCursor = LoadCursor( NULL, IDC_CROSS )  !程序光标
        wc%hbrBackground = GetStockObject(BLACK_BRUSH)  !窗口背景颜色
        wc%lpszMenuName = 0  !菜单名
        wc%cbClsExtra = 0  !无附加消息
        wc%cbWndExtra = 0
        results = RegisterClass(wc)  !注册窗口类
    end if

    !创建窗口
    hWnd = CreateWindowEx(0,                       	&  !窗口扩展样式
                 lpszClassName,                 	&  !窗口类名
                 lpszAppName,                  	&  !窗口标题
                 INT(WS_OVERLAPPEDWINDOW),	&  !窗口的风格
                 CW_USEDEFAULT,             	&  !左上角坐标X
                 0,                            	&  !左上角坐标Y
                 CW_USEDEFAULT,                 &  !窗口宽度尺寸
                 0,                             	&  !窗口高度尺寸
                 NULL,                         	&  !父窗口句柄
                 NULL,                     	     &  !主菜单句柄
                 hInstance,                  	     &  !窗口实例句柄
                 NULL  	                        &  !附加信息的指针
                 )

    !显示窗口
    results = ShowWindow( hWnd, SW_SHOWNORMAL) 
    !进入消息循环
    do while( GetMessage (msg, NULL, 0, 0) .NEQV. .FALSE.)
     results = TranslateMessage( msg ) !翻译消息
     results = DispatchMessage( msg ) !将消息传给windows,然后由windows传给回调函数
    end do
    WinMain = msg%wParam
End function WinMain

    
integer function MainWndProc ( hWnd, message, wParam, lParam )
    !DEC$ IF DEFINED(_X86_)
    !DEC$ ATTRIBUTES STDCALL, ALIAS : '_MainWndProc@16' :: MainWndProc
    !DEC$ ELSE
    !DEC$ ATTRIBUTES STDCALL, ALIAS : 'MainWndProc' :: MainWndProc
    !DEC$ ENDIF

    USE IFWIN  !包含有用的模块
    USE VarGlob  !有用的数据模块
    Implicit None

    integer( kind = 4 ) ::   hwnd 
    integer( kind = 4 ) ::  message  
    integer( kind = 4 ) ::  wParam
    integer( kind = 4 ) ::   lParam 

    select case ( message )
         case (WM_DESTROY)
            call PostQuitMessage( 0 )
         case default
            MainWndProc = DefWindowProc( hWnd, message, wParam, lParam )
    end select
end function MainWndProc



98

帖子

5

主题

3

精华

专家

F 币
426 元
贡献
275 点

管理勋章新人勋章

10#
 楼主| 发表于 2014-3-3 20:37:51 | 显示全部楼层
       程序038:定义窗口的骨架(骨架系统早就做好了,至于长什么样的肌肉,如何化妆,就是后面的工作了);
程序047-056:填充肌肉并化妆,最终表现出不同特征的窗口,如背景色不同或者鼠标形状不同等;
       程序057:告诉系统,我们要符合以上条件的窗口,让它做好准备;
       程序061:让系统按照我们的要求制作窗口;
       程序076:让系统显示窗口;

      至此,窗口显示出来了。
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-5-5 06:59

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表