Say hello to wxWidgets 3.0
published at 04.12.2013 14:40 by Jens Weller
Save to Instapaper Pocket
I remember the times, when wxWidgets 3.0 was already talked about, several years ago. Now, its been published in November, though I have to take a look at it. I've been using wxWidgets for years, but moved on to Qt for my own projects. So, lets have a look at wxWidgets 3.0...
First, in the time between me moving to Qt and wxWidgets 3.0 being released, there has been done quite a lot of work at wxWidgets. It still is like Qt an old framework, but 3.0 brings a few new things. First big change is the decision, to make unicode standard, so if you want ANSI, you'll have to build and configure it yourself. Also wxWidgets adopts now templates, yes, they really do. There is now template containers like wxVector<T>, and also Smartpointers as scoped, shared and a weakptr class exist in wxWidgets. The containers seem to share the interface of the STL, so that you'll be able to use STL algorithms on them. Saidly, as I understand, there is no default support for STL containers, wxWidgets tries to stay a framework, that is not related to the C++ Standard. Still, there is an option to enable STL and STL Container support. wxDir::GetAllFiles for example will want a pointer to wxArrayString, there is no overload for, say std::vector<wxString>.
Setup for wxWidgets 3.0
There is no SDK like Qt has, so my adventure with wxWidgets started with downloading and building it. I use a MinGW 4.8 Compiler, which installed with Qt, as for my normal projects I use QtCreator. I wanted to do a small example Project in wxWidgets, so I needed to decide for an IDE. So much I love QtCreator, I decided to go with CodeBlocks, as its having with wxSmith a RAD Editor for wxWidgets. Its a little hard to use, if you're used to the creator, but after a few tries, you figure out which things work how. Doubleclicking a button or anything will add a new event handler for this button instead of changing the text. I still remember how annoyed I was when I first got into QtCreator, that it was editing the text instead of adding a slot for the button. Good old times :)))
So CodeBlocks is the IDE I use for this example Project, there is not yet a new version released, so no build in wxWidgets 3.0 support. But they seem to be working on it. My example project is quite simple: I need to be able to select several directories, that then get packed into a zipfile. Backup is its purpose. And so I also found something, which Qt can't do out of the box, but wxWidgets can. You can edit the CodeBlocks wizard for wxWidgets, to add 3.0 support though. But setting up projects in CodeBlocks can be a bit cumbersome, getting all the libs right...
Next step, build wxWidgets. I did that many times, also I am the author of a german wxWidgets tutorial. easy. Still, it takes quite a while, and also MySys has changed, downloading the old monolithic version though still works for building wxWidgets. Also you'll need to edit the fstab file from MySys in order to set the correct MinGW version. Which I also had to add to CodeBlocks. Building wxWidgets3.0 is quite easy, simply follow the instructions provided in install.txt under docs/msw or docs/gtk. Using MySys under Windows enables you to build with MinGW in unix like shell, using configure & make.
Sample Project
So, as I wrote, I did a small sample project, to play around with "modern" wxWidgets. I've done some work with wxWidgets in the past, so I know most things in the framework quite well, still being used to Qt, I saw that I often had to google for a certain class, to see how to use it. wxWidgets has a convinient class for picking files or directories, wxDirPicker and wxFilePicker. wxSmith even knows about them, so I simply added them to my form. There is a little bit of boilerplate code, which I will not post. wxZipOutputStream I use to create the zip archive, and thats not a even a new class to wxWidgets 3.0. I also decided to use a little bit of C++11, so, here is my code for creating zip archives with wxWidgets:
wxString file = wxFileSelector("Select file to save files to archive",wxEmptyString,wxEmptyString,
wxEmptyString,wxFileSelectorDefaultWildcardStr,wxFD_SAVE); if(file.IsEmpty())
return; wxFFileOutputStream out(file); wxZipOutputStream zip(out,8); for(wxString& file:allfiles) { zip.PutNextEntry(file.Right(file.size() - file.find(wxFileName::GetPathSeparator()))); wxFFileInputStream in(file); zip.Write(in); }
So, wxFileSelector is a helper function for, well selecting a file. Its neither a type nor a macro. If the user clicks cancel, the returned wxString is empty. Then I simply create a hierachy of streams to write into the zip archive, allfiles is a std::vector<wxString>. I'll need to manipulate the filepath a little. Didn't find a way to do it with wxDir/wxFileName, as I need D:/foo/bar/myfile.txt to become foo/bar/myfile.txt, so I simply strip of the first /. Next, how to get the file after the new entry into the archive? I tried to write a method that would return a wxString with the read file input. Not really working for binary files, and a simple filestream does the job a little better. So those few lines fill my archive. There is a little problem with unicode and windows though. Umlauts are not handled properly in the archive, wxWidgets does display them correct, but the archive format can't handle them in the entry data. The files them selves seem not affected. There seems to be a ticket and solution open for this, but I did not yet have the time to apply this. Also not sure how to do this correctly with wxZipOutputStream.
As far as I understand, wxWidgets types are not yet ready for C++11, wxVector has no emplace_back and seems not be moveable. wxScoped/Shared/WeakPtr seem to be modeled after versions from boost. In a recent blog post, wxWidgets is defined as a C++98 library, so while you can compile 3.0 with std=c++11, its not yet supported very well. But C++11 makes your own code easier, so you can use C++11 for your own projects. I did use C++11 lambdas and auto to implement my filter, as I want to be able to filter out certain directories (release and debug directories for example):
auto it = std::remove_if(allfiles.begin(),allfiles.end(),[this](const wxString& file) { wxString t(file); t = t.MakeLower(); for(auto& f:filter) { if(t.Find(f)!= wxNOT_FOUND) return true; } return false; }); allfiles.erase(it,allfiles.end());
So, I have a std::vector<wxString> again, which contains the filters, which I don't want to be in allfiles. Currently I don't do regex, just string based filtering. A pitfall is wxString::find vs. wxString::Find, first returns size_t and is STL like, second one returns int, and works with wxNOT_FOUND (which is a funky name for -1). And after using remove_if to filter my allfile vector, I got to call erase, to get the job done.
Last thing missing is, how to get all the files. As wxWidgets has no models, I went back to my habit of collecting the data I need into STL containers, so dirs is a vector again, containing all selected dirs, which is then searched for every file via wxDir::GetAllFiles, which needs a wxArrayString pointer:
wxArrayString files; std::vector allfiles; for(wxString& dir:dirs) { wxDir::GetAllFiles(dir,&files); for(auto& str:files) { wxFileName fn(str); wxString path = fn.GetFullPath(); allfiles.push_back(path); } files.Clear(); }
Now alternatively, I could have done this a bit better with deriving a class from wxDirTraverser, and applying the filter while searching the directory. This way I wouldn't need to load files first, and then filter.
Lessons learned
So, my short trip back to wxWidgets was fun, but also needed to do a lot of research for various things. Some of them quite easy, a few a little harder. wxWidgets has done a step into the right direction, but in 2013 I'd like to see a bit more C++11 support. This makes it hard to compare wxWidgets 3.0 to say Qt5, wxWidgets feels to me more like a Qt4 contender. Qt has grown a lot more in the last years, but to be fair, has also a lot more man power then wxWidgets. The added STL support for wxContainers and adding Smartpointers is nice. But still, there is no fully STL/C++11 compliant GUI Library yet. Lets hope that C++11 (or, say C++14) comes to wxWidgets before the 4.0 version.
Another change with wxWidgets 3.0 is that the documentation is now based on doxygen, which I think is an improvement on the long run only. Maybe I'm too used to the Qt Documentation, but at least the main classes should have a short example of using them. Also most of the class methods are rather poorly documented. So that clicking on a method of a class in documentation is often a waste of time, especially for the STL like methods. I'd prefer wxWidgets only for smaller projects, as its easily statically linked, and for smaller tools still feels right. Still, I'd prefer QtCreator as an IDE, but maybe the new version of CodeBlocks can change this...
And of course there is much more new stuff in wxWidgets 3.0 then I could have covered, but there is already a very good blog post doing this: the wonderful world of wxWidgets 3.0.
And in case you are interested in the code of my examlpe, you can download it. Its named after my company Code Node, which I need the tool for also. Creating simple backups on the run under Linux and Windows. Its not yet fully done though. A little exercise left for the reader ;)
Join the Meeting C++ patreon community!
This and other posts on Meeting C++ are enabled by my supporters on patreon!