WxSmith Tutorial & Pointers

From Code::Blocks
Revision as of 20:51, 11 April 2006 by Sethjackson (talk | contribs)

"Hello world" Tutorial

Since wxSmith is able to do something already it's high time to write a small tutorial on how to use it. At the very beginning, I must point out that to use wxSmith you MUST have wxWidgets compiled (version 2.6 or later). Build instructions can be found here

WARNING: wxSmith is still unstable. So use it at Your own risk. And there's no undo yet. I warned You ;)

Ok, let's start :)


wxWidgets starts to breathe

wxSmith can be used inside any wxWidgets project. However, we currently have only one option to easily create a wxWidgets app. Simply select File -> New Project -> wxWidgets Application from the menu. If You have compiled wxWidgets using the wiki tutorial, select Using wxWidgets DLL in Project Options. Hit Create and save the project. If you're running on Windows, you probably will have to change the WX_DIR Custom variable. It should point to the root wxWidgets directory and it can be changed in Project -> Build Options menu in the Custom variables tab.

After this step you should be able to produce an app like this:

WXSMITH1.JPG


Let's add some fireworks

Now it's time to fill the empty frame with our "Hello World" message. We will do this by placing a panel over the frame. Select wxSmith -> Add Panel from menu. If you're doing this for the first time in a project, it should display this message box:

WXSMITH2.JPG

Just click Yes, it will bring up a configuration dialog. You can set-up following options here:

  • Class Name - name of class which will contain our panel
  • Header File / Source File - files which will contain the panel's class
  • Xrc File - selecting this option allow you to use a xrc file containing the panel's data

In our tutorial we will use a class named "HelloWorldPnl" (notice that usually when typing a class name, header and source file names are generated automatically). The config dialog should look like this:

WXSMITH3.JPG

Click Create and we have our panel right in the editor

Building window

wxWidgets comes with something called Sizers. But what is this for? If You have been working with java you will remember something called Layout managers. Implementation in wxWidgets differs a little bit but it does almost the same. Ok, but let's put some explanation here: Usually when adding items into windows You must specify the item's position and size. wxWidgets tries to automate this process and it uses sizers for that. They are automatic positioning and sizing window items. Sizers have one big advantage. When You write cross-platform applications, you cannot assume that fonts, buttons, etc. are sized the same from one platform to another. This can even occur on the same platform. When You use sizers, You don't have to worry about that. All sizing is done automatically. And one more thing - sizers can even reposition and resize window items when the window itself changes size. So, let's add some sizers here. But first...


How can I add something ?

In a newly opened editor you will see eight black boxes around something which looks like a button without a label

WXSMITH4.JPG

These black boxes are surrounding a currently selected item. In our case it's a whole panel. Adding new item is simply done by clicking on one of the buttons in the palette at the bottom of the C::B window.

WXSMITH5.JPG

These buttons have small pictures showing what they add. If you're unsure, hold the mouse over the button and, after a moment, you will see the name of the wxWidgets class that the button represents - that's our item.

New items are added relatively to the current selection. You can add new item in one of three ways:

  • Before the currently selected widget
  • After the currently selected widget
  • Into the currently selected widget

You change the insert method via a palette (it should be easy to find ;)). (big buttons, far right) Note that all three insertions settings are not always accessible. For example You cannot add anything into a button. There are also some special situations when You cannot add new item:

  • When an item has sizer inside, it cannot contain anything else. Items can be added into the sizer only
  • When an item has anything but a sizer inside, you cannot add a sizer into it.
  • Spacers (empty fields added into sizers instead of real items) can be added into a sizers only

Always make sure that a valid item is selected and that a valid insertion method is chosen.

Adding items

There are five types of sizers in wxWidgets, four are currently supported inside wxSmith (wxGridBagSizer is not supported yet). If You wish to learn about sizers I propose wxWidgets doccumentation In our sample we will add wxFlexGridSizer. Perform the following:

  • Select panel by clicking on it.
  • Click on the wxFlexGridSizer button (third in Layout row).

You probably noticed that our panel decreased it's sizer. This is because the sizer automatically adjusts to the minimal size of it's parent. And there's an additional red border - it shows where the sizer is located.

Because this is a "Hello World" application, we'll put the text into a newly created sizer. To do this:

  • Select sizer (click somewhere insided red border)
  • Make sure that the Insetion Type is Into
  • Click on the wxStaticText button
  • Click on the newly created text item (should be "Label") and go to properties (The Properties panel is inside the Resources tab at the left of C::B Use the little arrows at the top of the Management panel to find the Resources Panel if its hidden )
  • Change the Label property to "Hello World !!"

And because this text looks so lonely, we'll add another button here:

  • Select the newly created text (now "Hello World !!")
  • Chose the "After" Insertion type
  • Click on the wxButton icon

Ok, now we have this:

WXSMITH6.JPG

But I would prefer to put this button below the text. How to do this ? As I mentioned before, sizers are automatic positioning items and, in our case, the sizer decided to put the widgets in a horizontal row, one next to another. If we want them to be in a vertical colume, we need to change some properties for the sizer:

  • Select wxFlexGridSizer in the resources tree representing the structure of our window (to the left, in the Resources panel)
  • Expand "Cols x Rows" property and change the X value to 1.

What have we done ? We instructed the sizer to create only one column of widgets. Alternatively, we could have set the number of rows (Y) to 2. The effect would have been the same. Setting the values to 0 means that the sizer has to find its values automatically. Ok, let's see what we've done.

Using the created panel

In this tutorial we will put our panel over the main frame. To do this:

  • Open the main.cpp file
  • Add #include "helloworldpnl.h" to the beginning of the file
  • At the end of MyFrame::MyFrame add the statement new HelloWorldPnl(this);
  • Compile and Run

You should see something like this:

WXSMITH7.JPG

But I want it to look better

Let's see. I would like my panel to be more interesting, I want it to change when we resize our window. And I want a bigger font, and let's say, a blue font colour. The first can be done using the previously created wxFlexGridSizer. It needs just a few modifications:

  • Select wxFlexGridSizer from the resource browser
  • Change growable cols property to 0 (zero)
  • Change growable rows property to 0 (zero)

The changed properties keep information about columns and rows which should expand when the window changes size. Values are integers (zero-based indexes) separated by commas.

The second is also easy:

  • Select wxStaticText from the resource browser (or click on it in the editor)
  • Find font property and expand it
  • Change Use Font to True
  • Click on font property below - a button with "..." will appear, click on it
  • Select new font, I used "Times New Roman", Bold, size: 20
  • Find foreground property and expand it
  • Change Use Colour to true
  • In Colour below select Custom, colour dialog will appear
  • Select colour You like :)

Ok, let's compile & run. Now when we resize the window, our panel changes dynamically, the font is bigger and the colour has changed :)

WXSMITH8.JPG

How to make buttons respond

Now we'll add an action to our button. Let's say it will close the program. First, let's change the button label to "Close". This should be pretty easy and I hope You won't have any problems with it. Ok, now let's add some action.

wxWidgets works like many other GUI systems - through events. An event is a small peace of information saying that something has happened - for example, the user clicked on a button. But we want to do something when such and event happens. To connect events with actions we have to create an event handler. wxSmith can do this automatically:

  • Select the button
  • Switch to the Events tab (if you see properties, it's right there)
  • In the line named EVT_BUTTON choose "-- Add new handler --"
  • Change the event handler name to something you like (I will leave it as it is ;)) and click OK

As You can see, a new empty function has been created

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
 {
 }

Here we can write some code that will be executed when you press the button. So, let's add a Close() command

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
 {
   Close();
 }

and see what happens. I click on Close button and... nothing happens. Why ? Because we closed the panel, not the whole window. How do I know that ? Our event handler is a member of the HelloWorldPnl class. Everything inside the event handler pertains to the panel, not the outer window. When we called Close() we called this function in the wxPanel class. But how can we close the main frame? Change the code to:

 void HelloWorldPnl::OnButton1Click(wxCommandEvent& event)
 {
   GetParent()->Close();
 }

The GetParent() function will return a pointer to the parent window - frame. Now Close() is being called on the panels parent, the window. But be careful. Our example was easy and we just assumed that main frame will be the panel's parent. Usually we can not be so sure.

Our Hello World application is ready to go :) I hope It wasn't boring. Not bored ? Then read next chapter ;)

Pointers

Some technical info

Ok, I'll try to explain how wxSmith affects our code, how to work with it, why you shouldn't be worried about losing your code.


Where wxSmith generates its code ?

wxSmith is not as intelligent as it may seem ;) When we say it generates code, it simply replaces whole code pieces without wondering if code is placed in the right position. But the code works. How is it done ?!

When You look into files generated inside wxSmith, you may find some special comments like :

 //(*Headers(HelloWorldPnl)
 //*)

These comments are used by wxSmith to find the place where new code should be applied. Each //(* comment starts automatically generated block of code and //*) closes it. Everything between these comments is regenerated, even if you add something there

The only exception is a block started with the //(*Handlers comment. wxSmith can only add to this block of code. If you want to write your event handler manually, you can put its declaration here.

Code outside the //(* - //*) comments won't be touched.

Loading XRC resources

When using an XRC file, do not forget to initialize the wxXMLResouce Handlers & XRC File. For example in your App::OnInit:

   // Loading XRC resource file (not in a zip file).
   wxXmlResource::Get()->InitAllHandlers();
   wxXmlResource::Get()->Load("<your XRC File name>.xrc");