文章目录
简介
学习Fortran QuickWin应用程序开发,编写了一个带有用户界面的简单的气体物性计算软件,可以称为超级低配版NIST Refprop(功能上比Refprop简单很多:只有氮气一种气体;没有添加绘制曲线的功能)
下面主要介绍QuickWin部分的内容,有关计算的例程和模块由我的小伙伴编写,使用了理想气体状态方程、van der Waals方程和R-K方程,迭代算法采用最简单的Newton迭代法。
With my partner: (1105808579@qq.com)
一、开发环境
IDE: Microsoft Visual Studio 2019 Community编译器: Intel Parallel Studio XE 2020
源代码格式:Fortran 90
二、步骤
2.1 建立QuickWin工程
在VS中创建新项目,语言为Fortran,选择QuickWin Application
(这里命名为Ex01.sln
和 Ex01.vfproj
)
2.2 添加源代码和文件
在解决方案资源管理器的Source Files目录下添加源代码文件
Source1.f90
2.3 添加资源文件
在Resource Files目录下新建资源文件 Resource1.rc
步骤同上
2.4 向 .rc 文件中添加资源
双击打开 .RC 文件,右键“添加资源”,然后选择对话框组件(Dialog)
除对话框外,还可以向 .rc 文件中添加菜单Menu、版本信息Version、位图Bitmap等;
要在对话框组件中插入位图,就需要先向 .rc 文件添加bitmap资源。
添加并配置Version资源,即可设置最终exe的属性-详细信息。
2.5 设计对话框
添加Dialog组件后,进入对话框的编辑界面
Ctrl + Alt + X 打开工具箱,可以将工具箱中的控件直接拖动到对话框里面
F4 打开属性窗口
(上图仅为简单示例)
在这里添加对话框中的按钮、文本框、滚动条等控件,通过工具栏中的工具调整控件的大小、位置和对齐方式,通过属性窗口设置控件显示文本(Caption)、控件ID、边缘粗细、可视性、文本对齐方式等属性。
控件可大致分为两类,一类是有触发回调例程(Callback Subroutine)的,例如按钮、EDIT文本框,另一类则是不能触发回调例程的,如 Static Text 和 Picture Control.
2.6 获取控件ID
每一个控件都有一个唯一ID作为其身份标识,ID和控件是一一对应的。例如,添加的第一个 Static Text 类型控件的ID是IDC_STATIC1,对话框1的控件ID是IDD_DIALOG1。然而这种形式的控件ID无法在程序中被直接识别。因为在保存了 .rc 文件后,每一个ID也被赋予一个与其对应的代码,如本例中IDD_DIALOG1的代码为101,IDC_EDIT1的代码为1000. 在程序中引用控件需要通过控件代码,因此,保存 rc 文件之后,首先打开工程目录下的 resource.h
文件,这是系统生成的一个C++文件,里面包含着控件ID与控件身份标识代码的对应关系。
人为读取之后,用模块的形式写入f90源文件中
(后面需要访问控件的例程都必须包含此模块)
MODULE CONTROLS
integer,parameter::IDD_DIALOG1 = 101
integer,parameter::IDD_EDIT1 = 1000
integer,parameter::IDD_EDIT2 = 1001
integer,parameter::IDD_EDIT3 = 1002
END MODULE CONTROLS
P.S. 本来应该用命令行将resource.h
转化为Fortran能够识别的.fd文件然后直接将其包含在程序中,但多次尝试都无法实现,此时只能手动包含控件信息。
2.7 编写主程序和回调例程
这里附上氮气物性计算软件的源代码:
MODULE CONTROLS !resource.h中的控件ID
integer, parameter :: IDD_DIALOG1 = 101
integer, parameter :: IDD_DIALOG2 = 103
integer, parameter :: IDC_EDIT1 = 1000
integer, parameter :: IDC_EDIT2 = 1001
integer, parameter :: IDC_EDIT3 = 1002
integer, parameter :: IDC_STATIC1 = 1003
integer, parameter :: IDC_STATIC2 = 1004
integer, parameter :: IDC_STATIC3 = 1005
integer, parameter :: IDC_STATIC4 = 1006
END MODULE CONTROLS
MODULE NEWTON !内核算法模块,包含方程
IMPLICIT NONE
REAL,PARAMETER::R=8.314
REAL,PARAMETER::MM=0.028013 !氮气摩尔质量
REAL,PARAMETER::A=0.1361,B=0.0385*0.001 !范德瓦尔方程正系数
REAL,PARAMETER::AK=0.427480*R**2*126.2**2.5/3.39/(1E6),BK=0.08664*R*126.2/3.39/(1E6) !R-K方程正系数
REAL::ML,VM,X
CONTAINS
!范德瓦尔方程求解
REAL FUNCTION VANSOLVE(P,V,T)
IMPLICIT NONE
REAL::P,V,T,X
ML=P*V/(T*R/MM) !理想气体状态方程求解
X=V/(ML/MM)
VM=X-VANDER(P,V,T,X)/DVANDER(P,V,T,X)
DO WHILE(ABS(X-VM)>1E-7)
X=VM
VM=X-VANDER(P,V,T,X)/DVANDER(P,V,T,X)
END DO
VANSOLVE=V/VM*MM
END FUNCTION VANSOLVE
REAL FUNCTION VANDER(P,V,T,X) !范德瓦尔函数
IMPLICIT NONE
REAL P,V,T,X
VANDER=P*X**3-(P*B+R*T)*X**2+A*X-A*B
END FUNCTION VANDER
REAL FUNCTION DVANDER(P,V,T,X) !范德瓦尔导函数
IMPLICIT NONE
REAL::P,V,T,X
DVANDER=3*P*X**2-2*(P*B+R*T)*X+A
END FUNCTION DVANDER
!R-K方程求解
REAL FUNCTION RKSOLVE(P,V,T)
IMPLICIT NONE
REAL::P,V,T
ML=P*V/(T*R/MM) !理想气体状态方程求解
X=V/(ML/MM)
VM=X-RK(P,V,T,X)/DRK(P,V,T,X)
DO WHILE(ABS(X-VM)>1E-7)
X=VM
VM=X-RK(P,V,T,X)/DRK(P,V,T,X)
END DO
RKSOLVE=V/VM*MM
END FUNCTION RKSOLVE
REAL FUNCTION RK(P,V,T,X) !R-K函数
IMPLICIT NONE
REAL::P,V,T,X
RK=P*X**3-R*T*X**2-(P*BK**2+BK*R*T-AK/(T**0.5))*X-AK*BK/(T**0.5)
END FUNCTION RK
REAL FUNCTION DRK(P,V,T,X) !R-K导函数
IMPLICIT NONE
REAL::P,V,T,X
DRK=3*P*X**2-2*R*T*X-P*BK**2-BK*R*T+AK/(T**0.5)
END FUNCTION DRK
END MODULE NEWTON
PROGRAM MAIN
USE IFQWIN !包含QuickWin和常用库
implicit none
integer(kind=4)::results !results保存调用函数之后的返回值
logical(kind=4)::res !res保存调用函数之后返回的LOGICAL型变量
type(qwinfo)::winfo !qwinfo型变量winfo用以储存窗口信息
type(windowconfig)::wc !windowconfig型变量用以储存窗口设置信息
winfo.type = QWIN$MAX !最大化窗口
res = GETWINDOWCONFIG(wc)
results = SETWSIZEQQ (0, winfo)
results = SETEXITQQ (QWIN$EXITPERSIST)
!维持程序运行
do while (.true.)
end do
END PROGRAM MAIN
! 初始化界面尺寸和菜单
LOGICAL(4) FUNCTION INITIALSETTINGS( )
USE IFQWIN
implicit none
integer( kind=4 ) :: results
logical(kind=4)::res
type (qwinfo) :: winfo
external:: Dialoginput,InfoWindow
winfo.w = 520 !设置窗口宽度
winfo.h = 420 !设置窗口高度
winfo.x=650 !设置窗口左上角初始坐标
winfo.y=250
winfo.type = QWIN$SET
results = SetWSizeQQ(QWIN$FRAMEWINDOW, winfo) !设置窗口大小
res = appendmenuqq(1, $MENUENABLED, ' Start 'C,Dialoginput) !设置菜单
res = appendmenuqq(2, $MENUENABLED, ' Info...'C,InfoWindow) !设置Info窗口
INITIALSETTINGS= .true.
END FUNCTION INITIALSETTINGS
! 点击“开始”触发的回调子程序
subroutine Dialoginput(checked)
USE IFWIN !包含Win32 API例程
USE IFLOGM !包含对话框例程
USE CONTROLS !包含控件ID信息
implicit none
integer(kind=4)::results
logical(kind=4)::retlog,checked
type(dialog)::datadlg !一级窗口为datadlg
external:: dialogbasedApply !声明外部例程
! 调用dlgInit函数以初始化对话框
retlog = DLGINIT(IDD_DIALOG1,datadlg)
! 设置按钮“求解”的回调函数
retlog = DlgSetSub(datadlg, IDOK, dialogbasedApply) !IDOK为默认的确定按钮
!IDCANCEL为默认的取消按钮
! 激活对话框
results = DLGMODAL (datadlg)
! 释放占用资源
call dlgUnInit(datadlg)
END subroutine Dialoginput
subroutine InfoWindow(checked)
USE IFWIN !包含Win32 API例程
USE IFLOGM !包含对话框例程
USE CONTROLS !包含控件ID信息
implicit none
integer(kind=4)::results
logical(kind=4)::retlog,checked
type(dialog)::dial !一级窗口为datadlg
! 调用dlgInit函数以初始化对话框
retlog = DLGINIT(IDD_DIALOG2,dial)
! 激活对话框
results = DLGMODAL (dial)
! 释放占用资源
call dlgUnInit(dial)
END subroutine InfoWindow
! 按钮“求解”触发的回调子程序
subroutine dialogbasedApply( dlg, id, callbacktype )
!DEC$ ATTRIBUTES DEFAULT :: dialogbasedApply
USE IFLOGM
USE CONTROLS
USE NEWTON
implicit none
type(dialog) dlg !二级子窗口为dlg
logical*4 results
integer(kind=4)::id, callbacktype,i
real m1,m2,m3,prs,tmp,vol
character(len=30)::str,str1,str2,str3
! 提取编辑框中的数据
results = DlgGet(dlg,IDC_EDIT1,str1)
read(UNIT=str1,FMT=*,iostat=i)tmp
results = DlgGet(dlg,IDC_EDIT2,str2)
read(UNIT=str2,FMT=*,iostat=i)prs
results = DlgGet(dlg,IDC_EDIT3,str3)
read(UNIT=str3,FMT=*,iostat=i)vol
prs=prs*1e6 !MPa->Pa
!调用内核算法函数求解质量
m2=vansolve(prs,vol,tmp)
m3=rksolve(prs,vol,tmp)
m1=ML
!用户非法输入
if(m1<=0.OR.m2<=0.OR.m3<=0)then
m1=0
m2=0
m3=0
end if
!结果写入静态文本框
write(str,*)m1
results = DlgSet(dlg,IDC_STATIC1,str)
write(str,*)m2
results = DlgSet(dlg,IDC_STATIC4,str)
write(str,*)m3
results = DlgSet(dlg,IDC_STATIC2,str)
END subroutine dialogbasedApply
2.8 生成exe
程序界面如下:
参考资料
[1] 周振红,徐进军等. Intel Visual Fortran 应用程序开发. 黄河水利出版社,2006.
[2] 汪华. Intel Visual Fortran 窗口程序设计实例. http://blog.renren.com/blog/254997247/860686026
写在最后
本来是专业基础课的课程作业,只需要编程计算出结果就可以了,当时灵光一闪想到模仿Refprop写一个带有UI的应用程序,于是就做下来了,感觉还挺有趣的。
吐槽一下,原来宇宙最强IDE–VS也有不少bug,还有CSDN什么时候才能支持Fortran语言的代码块😂
另外,Fortran并不擅长于应用程序设计,科学计算才是正道 [狗头] [狗头]