序言
近期针对 wx-c 库进行更新编译,对wxWidgets相关软件和配置方式进行了更多了解和体验。wxWidgets本来叫 wxWindows, 因为名称与微软 windows 太过相近,因此微软律师出面进行了善意和解,wxWindows随即更名为 wxWidgets,早期是在wxBase基本库上逐步扩展的, wxBase 主要解决数据类型、转换、结构等方面的基础工作,组件是在 motif, x11, gtk, 甚至qt上做的,但后来默认的就是gtk了,x11和motif样式确实过于精典。如果在linux平台上只是做界面,gtk界面库已经非常丰富了,但在windows平台上基于本地sdk做的组件肯定看上去更 native, 所以我个人认为 wxWidgets 在 Windows 平台上优势更多一些。无论如何,它还是将平台底层与用户程序隔离开来了,不再像过渡期的 mfc 和 sdk 混在一起,封装比较浅。过度封装的好处可以简化操作,但坏处是离底层越来越远而不断失去深入底层玩味的机会。
wx-c是wxNET的底层,是一套c方式的wxWidgets封装,在它上在又封装了wxNET库,同时wx-c封装后.h又被转换成freebasic的.bi,实际上,wx-c也同样能被其它编译语言使用。FreeBasic有wx-c完整的头文件,但没有相应的libwx-c文件,网上能找到的也只有ELF32格式的 libwx-c-0-9-0-2.so ,很长时间的停更原因不得而知。我的想法是既然有头文件,有wxWidgets和wx-c源代码,就做点工作将它从32位升到64位,让它能在64位系统上继续使用。于是,就走入wxWidgets百有园,获得经历和思考,又于是有了一些新体会。
经历1:在sourceforge下载wx.NET源代码后学习
体会:wx-c 源代码是cxx的,有145个文件和一个wx-c.make文件。直接make -f wx-c.make后错误和提示覆盖了屏幕,这说明加.o都不能生成,更别指望生成.so了。打开make文件和程序源码,最终找到了它是wxWidgets 2.8版本上做的封装,不可能直接使用wxWidgets3.2.4, 因主wxWidgets3.2.4的函数和类与wxWidgets 2.8已经非常不相同了,wx-c要继承的类已经没有了,有些函数也没有了,而它有的与现在的又对应不上,这一百多个文件要是改起来,是不行不行的。但,既然研究了,就更深入一点,于是:
安装 wxformbuilder, codelite, codeblocks ,反正就是 sudo apt install, 在线安装也方便。安装后想创建个wxWidgets应用,看看窗体创建和类继承代码,但是,它们不运行,说是需要wxWidgets 3.0.5 支持。于是,下载wxWidget 3.0.5, 用的gcc是11.4版本。
./configure --enable-unicode --with-gtk=3
make && sudo make install
编译安装顺利,再运行wxformbuilder 3.9, 顺利。放个frame, 放个sizer, 再放上两个button, 查看c++代码,frame类和函数继承就看清了,对比wx-c源代码,做的工作几乎是一样的,其它函数也基本上是对等映射的。因此,在c上会操练wxWidget, 经过wx-c封装后也就会操作,反之亦然,所以它封装的并不是很完全。
经历2:安装libwx-gtk2u.xxx库文件与编译wxGTK2.8.12文件
既然wx-c用的是wxWidgets2.8的库,于是apt search查找libwx-gtk2u相关lib, 本地没有到pkg和debian库上找旧的下载、解压后放到自己的lib路径下,但因缺少 wx-c.o 而不能使用它们,还是要自己编译它们才行。
1. ./configure --enable-unicode --with-gtk=2
2. make
开始编译,警告信息不少,但基本上都是善意的,因此不予采。到了va_copy时,就编译出错进行不下去了。显示原作者编译是没问题的,现在出了问题,说明编译器版本太新。查了一下那个时期的编译器,让现在的编译器兼容到 -std=c99 , -std=c++98 ,将写修改到 make 文件中,然后继续 make。
体会:前期生的.o继续保留,从错误处继续产生新的.o文件,虽然它们编译时的参数不同,但link时不影响。遇上错误修改 Makefile 文件,但不要 make clean 从头编译,那样前期的文件又编译不过去了,逢山开路遇水搭桥直接向前,就没什么问题了。
经历3:对ABI版本不同的处理
考虑到原来有了一些libwx-gtk2u的库文件,于是只将新生成的libwx-c.so又考贝了过去,修改freebasic 自带的 wx-c.bi 中的库引用为 #inclib wx-c ,试运行提示缺少一些libwx-gtk库,那就用刚生成的库按提示信息补进去,于是缺的又考进去了。再运行,提示先考贝进去库的 ABI是1009, 而后考进去的库是 1016
体会:即使文件名相同由于ABI版本不同也不能使用,必须统一到相同ABI版本。即然原来找的那些库是 1009的,那就修改Makefile, 编译时再加上一个参数 -fabi-version=09, 再编译,编译后将缺的那几个库文件考过去,再运行sample程序,顺利运行。其实早该全考过去,不用原考进去的那些库,也就不会遇到 ABI 问题了。
运行Visual_WX-C_Designer, Visual_WX-C_Designer.sh, 或wine Visual_WX-C_Designer.exe
Visual_WX-C_Designer是基于wx-c的Designer, 它的linux版本是 Visual_WX-C_Designer, 那个 Visual_WX-C_Designer.sh 调用的还是linux版本的 Visual_WX-C_Designer, 不同的是加上了库的路径,这样运行的共享库放在本地即可,不用放在/usr/lib或/usr/local/lib里混在一起。
#! /bin/bash
export LD_LIBRARY_PATH="./lib"
./Visual_WX-C_Designer
Visual_WX-C_Designer.exe是Win32版本的设计器,它需要wine支持,因为它非常精简,所以运行起来与linux本地程序没有什么太大不同,但似乎显示效果更好一些。下图左上是linux版本,右下是wine 支持的win32版本,它们都是32位版本的。
生成的代码质量挺好
#Include Once "wx-c/wx.bi"
Declare Function App_OnInit WXCALL ( ) As wxBool
Declare Function App_OnExit WXCALL ( ) As wxInt
Declare Sub button0_event WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
Declare Sub button1_event WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
Declare Sub menuhandler WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
''
'' Translate FBString to wxString
''
Function fbstring_to_wxString( ByVal fbstr As String ) As wxString Ptr
Dim As wxString Ptr ret
ret = wxString_ctorUTF8( fbstr )
Return ret
End Function
''
'' Translate wxString to FBString
''
Function wxString_to_fbstring( ByVal wxstr As wxString Ptr ) As String
Dim As String ret
Dim As Integer i
For i = 0 To wxString_GetLength( wxstr )
If wxString_CharAtUTF16( wxstr, i ) <> 0 Then
ret += Chr( wxString_CharAtUTF16( wxstr, i ) )
EndIf
Next
Return ret
End Function
Dim Shared As wxApp Ptr wx_app
Dim Shared As wxFrame Ptr wx_frame
Dim Shared As wxPanel Ptr wx_panel
Function App_OnInit WXCALL ( ) As wxBool
wx_frame = wxFrame_ctor( )
wxImage_InitAllHandlers( )
wxFrame_Create( wx_frame, WX_NULL, -1, fbstring_to_wxString(( "" )), 427, 340, 705, 498, wxFRAME_DEFAULT_STYLE Or wxCLOSE_BOX Xor wxMAXIMIZE_BOX Xor wxRESIZE_BORDER, WX_NULL )
wx_panel = wxPanel_ctor2( wx_frame, -1, -1, -1, -1, -1, 0, WX_NULL )
'' Application Icon
Dim As wxIcon Ptr wx_icon
Dim As wxBitmap Ptr iconImage
wx_icon = wxIcon_ctor( )
iconImage = wxBitmap_ctor( )
wxBitmap_LoadFile( iconImage, fbstring_to_wxString(( "/home/songyq/myApplication/poseidonFB-freebasic/fblogo.png" )), wxBITMAP_TYPE_PNG )
wxIcon_CopyFromBitmap( wx_icon, iconImage )
wxFrame_SetIcon( wx_frame, wx_icon )
''
'' create widget button0
''
Dim As wxButton Ptr button0
button0 = wxButton_ctor( )
wxButton_Create( button0, wx_panel, -1, fbstring_to_wxString(( "button0" )), 200, 110, 340, 50, 0, 0, 0 )
wxEvtHandler_Proxy( button0, Cast(EventListener, @button0_event) )
wxEvtHandler_Connect( button0, wxEvent_EVT_COMMAND_BUTTON_CLICKED( ), -1, -1, 0 )
''
'' create widget textctrl0
''
Dim As wxTextCtrl Ptr textctrl0
textctrl0 = wxTextCtrl_ctor( )
wxTextCtrl_Create( textctrl0, wx_panel, -1, fbstring_to_wxString(( "textctrl0" )), 100, 230, 340, 50, 0, 0, 0 )
''
'' create widget button1
''
Dim As wxButton Ptr button1
button1 = wxButton_ctor( )
wxButton_Create( button1, wx_panel, -1, fbstring_to_wxString(( "button1" )), 230, 330, 370, 50, 0, 0, 0 )
wxEvtHandler_Proxy( button1, Cast(EventListener, @button1_event) )
wxEvtHandler_Connect( button1, wxEvent_EVT_COMMAND_BUTTON_CLICKED( ), -1, -1, 0 )
'' create menus
Dim As wxMenuBar Ptr wx_menubar
wx_menubar = wxMenuBar_ctor( )
'' menu "&Menu 0"
Dim As wxMenu Ptr wx_menu0
wx_menu0 = wxMenu_ctor( fbstring_to_wxString(( "" )), 0 )
wxMenuBase_AppendCheckItem( wx_menu0, 1, fbstring_to_wxString(( "checkitem0" )), fbstring_to_wxString(( "checkitem0" )) )
wxMenuBase_AppendRadioItem( wx_menu0, 2, fbstring_to_wxString(( "radioitem1" )), fbstring_to_wxString(( "radioitem1" )) )
wxMenuBase_AppendSeparator( wx_menu0 )
'' menu "submenuitem3"
Dim As wxMenu Ptr wx_menu1
wx_menu1 = wxMenu_ctor( fbstring_to_wxString(( "" )), 0 )
wxMenuBase_AppendCheckItem( wx_menu1, 3, fbstring_to_wxString(( "checkitem0" )), fbstring_to_wxString(( "checkitem0" )) )
wxMenuBase_AppendSubMenu( wx_menu0, 4, fbstring_to_wxString(( "submenuitem3" )), wx_menu1, fbstring_to_wxString(( "submenuitem3" )) )
wxMenuBar_Append( wx_menubar, wx_menu0, fbstring_to_wxString(( "&Menu 0" )) )
wxFrame_SetMenuBar(wx_frame, wx_menubar)
wxFrame_CreateToolbar( wx_frame, wxHORIZONTAL Or wxTB_TEXT Or wxTB_FLAT, -1, 0 )
wxToolBar_Realize( wxFrame_GetToolbar( wx_frame ) )
wxEvtHandler_Proxy( wx_frame, Cast(EventListener, @menuhandler) )
wxEvtHandler_Connect( wx_frame, wxEvent_EVT_COMMAND_MENU_SELECTED( ), -1, -1, 0 )
wxWindow_Show( wx_frame, 1 )
wxApp_OnInit( wx_app )
Return 1
End Function
Function App_OnExit WXCALL ( ) As wxInt
Return wxApp_OnExit( wx_app )
End Function
Sub button0_event WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
Select Case wxEvent_GetEventType( event )
Case wxEvent_EVT_COMMAND_BUTTON_CLICKED
''add event handler code here
wxWindow_Destroy(wx_frame)
End Select
End Sub
Sub button1_event WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
Select Case wxEvent_GetEventType( event )
Case wxEvent_EVT_COMMAND_BUTTON_CLICKED
''add event handler code here
End Select
End Sub
Sub menuhandler WXCALL ( ByVal event As wxEvent Ptr, ByVal iListener As wxInt )
Select Case wxEvent_GetId( event )
Case 1
'' add event handler code for selecting check item checkitem0 from menu &Menu 0 goes here
Case 2
'' add event handler code for selecting radio item radioitem1 from menu &Menu 0 goes here
Case 3
'' add event handler code for selecting check item checkitem0 from menu submenuitem3 goes here
End Select
End Sub
''main
wx_app = wxApp_ctor( )
wxApp_RegisterVirtual ( wx_app, @App_OnInit, @App_OnExit )
wxApp_Run( 0, 0 )
基于WX-C的IDE开发环境 wxFBE
它也是32位版本的,支持多语言,我加了中文改了几行没再多修改。
基于wx-c的IDE是32位的,但fbc编译出的程序是64位的,IDE用的库放在本地即可,不用放到操作系统的库路径中。
将生成的wxWidgets 2.8的 64位库和 libwx-c.so放在一起打了个包(wx是wxWidgets 2.8版的配置文件,和lib库文件放在一起,wx文件夹下不同版本的wxWidgets都会在那里面,wx-configure --version=nn 时就会自动为其它程序配置nn版本的wxWidget)
写改写wx-c到wxWidget3.2.4新版本wx-c的话,除了会修改函数,还会涉及到增加新函数,麻烦的是freebasic的头文件也要改,相应的示例程序也要改,开源的32位的设计器也要改(IDE不用改,它使用的设计器是个Visual_WX-C_Designer的plugin, 编译器是 fbc),暂时没有改动它们的想法。由于wxWidget和gtk是多平台的,用wx-c写的程序在三个主流平台上运行应该不会有障碍的。
In case of access failure, below package link may be accessed.