Difference between revisions of "WxSmith Tutorial & Pointers"

From Code::Blocks
Line 112: Line 112:
 
But I would prefer to put this button below the text. How to do this ?
 
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:
 
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 (over in the properties panel)
+
* 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.
 
* Expand "Cols x Rows" property and change the X value to 1.
 
What have we done ?
 
What have we done ?

Revision as of 05:45, 19 January 2006

"Hello world" Tutorial

Since wxSmith is able to do something already it's high time to write some tutorial on how to use it. At the very beginning I must point - 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. Currently we have only one option to easily create wxWidgets app. Simply select File -> New Project -> wxWidgets Application from menu. If You have compiled wxWidgets using wiki tutorial, select Using wxWidgets DLL in Project Options. Hit Create and save project. If You're running on Windows, You will probably have to change WX_DIR Custom variable. It should point to root wxWidgets directory and it can be changed in Project -> Build Options menu on 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 created panel

In this tutorial we will put out panel over main frame. To do this, just follow me:

  • Open main.cpp file
  • Add #include "helloworldpnl.h" at the begginning of file
  • At the end of MyFrame::MyFrame add 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 bigger font, and let's say, blue font colour. First can be done using previously created wxFlexGridSizer, need just few modifications:

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

Changed properties keep information about columns and rows which should expand when window changes size. Values are integers (zero-based indexes) divided by coma.

Second is also easy:

  • Select wxStaticText from resource browser (or click on it in editor)
  • Find font property and expand it
  • Change Use Font to True
  • Click on font property below - 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 window, our panel changes dynamically, font is bigger and colour has changed :)

WXSMITH8.JPG


How to make button respond

Now we'll add action to our button, let's say it will close program. First thing is to change 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 as many other gui systems - through events. Event is a small peace of informathion saying that something has happened - for example user clicked on button. But we waht to do something when such event happens. To connect event with action we have to create event handler and wxSmith can do it automatically:

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

As You can see, new empty function has been created

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

Here we can write some code and it will be executed when You press button. So, let's add Close() command

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

and see what happens. I click on Close button and... nothing happens. Why ? Because we want to close panel, not whole window. How I know that ? Our event handler is member of HelloWorldPnl class and everything inside event handler will be relative to it and when we call Close() we call this function in wxPanel class. But how to call it inside main frame ? Change the code to

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

GetParent() function will return pointer to parent window - frame. Now it's easy to call Close inside it. But be careful. Our example was easy and we can assume that main frame will be panel's parent. Usually we can not be sure.

Our Hello World application is ready to go :) I hope It wasn't boring. Not bored ? 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 not as intelligent as it looks like ;) 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 and 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");