Design and Develop GUI with Qt5

Qt allows you to develop a multi-platform application, that you can develop a GUI application on one platform and deploy to many others (if you avoid system-specific extra modules). Qt contains modules for creating widgets from elementary ones to OpenGL 3D, which I will discuss later. In addition it contains module with other functionalities an application may need such as SQL, XML, web channels, web views and web sockets.

Qt can be downloaded from https://www.qt.io/ or installed using the UNIX/Linux package installers.

In addition to the QT libraries and header files, there are 3 useful resources:

  • Qt Designer – A GUI tool for the generation of Python and C++ headers from a form graphically designed.
  • Qt Assistant – A reference to the Qt classes, Example, the QMake tutorial, etc.
  • qmake – an easy-to-use utility that creates the Makefile.

In the following sections, I will show how to create a project using the three tools:

Creating the Main Window

Qt Designer is an editor with which GUI designers and developers can communicate. With the designer you can create, save and edit Designer UI Files (*.ui) and create class files from them for Python and C++ programs. The QMake program discussed later can use the “.ui” file to generate a header file from it. The file can be edited by creating top level windows such as widows and dialog, and dragging and dropping widgets into them. You can also access and modify their properties; if you are a developer and have a Desiger UI file, you can find names of object in your program.

Starting:

As you start the QT Designer, the following dialog pops up:

If you don’t see the dialog, choose File->New from the editor’s menu bar, to make the dialog pop up.

Choose your top-level widget from the “templates/forms” menu, and click Create; a window will be created:

Now, from the right-hand Property Editor, you can change some properties, for example: let us change the window title:

Adding widgets and promoting them

Now, you can choose widgets from the left-hand side of the editors and drag-and-drop them into the window:

For example, let us add a push button, and change its QAbstractButton property “text” to “Push me!”.

One of the other properties we can change is the QObject property “objectName”, which will be the name of the appropriate field of class QPushButton in the created class.

By right-clicking inside the widget and choosing “Promote to..” from the context-menu, you can choose to use a class that inherits from the gadget’s class. Don’t forget to define the new class and its constructor and methods.

Previewing

You can view your design by clicking Form->Preview from the editor’s menu bar.

Saving the created class

If you don’t want the Make program to generate a header file, you can save it from the Qt Designer tool.

  1. Choose Form->View C++ Vode/View Python Code from the editor’s menu bar.
    a dialog will open.
  2. Click the “save” icon to save the created header file.

Adding Functionality

This section will describe a little Hello World program – in C++ – that uses a header file created wit QtDesigner. The purpose of the program is to print “Hello, world” to the standard output, when the “Push Me” button is clicked. To add the mouse event handling the class QPushButton has been promoted to Extended Button. This section will describe the program, and will help you train yourself using Qt Assistant.

The main function

To learn what a the main function of a Qt Application with widgets should look like:

  1. Start the Qt Assistant if not started yet.
  2. Click the Contents tab
  3. Click Qt Widgets (highlighted in the following image:

You” see a heading reading “Getting Started Programming with Qt Widgets”. Scroll down and see the contents of a main source line.

In the Hello World program the code is as follows:

 #include "ui_example.h"
 #include <iostream>

 using namespace std;

 ExtendedButton::ExtendedButton(QWidget *parent):QPushButton(parent) {
 }
 void ExtendedButton::mouseReleaseEvent(QMouseEvent *event){
     cout<<"Hello, world!"<<endl;
 }
 int main(int argc, char **argv){
     QApplication a(argc,argv);
     Ui_MainWindow mainObject;
     QMainWindow mainWindow;
     mainObject.setupUi(&mainWindow);
     mainWindow.show();
     return a.exec();
 }

The main file includes the constructor of the class ExtendedButton. Its role is to call the parent’s constructor. Another function implemented is mouseReleaseEvent, which is an event handler. You can learn from Qt Assistant, that the method mouseReleaseEvent is an event handler by clicking Qt Widget->QWidget in the right-hand Contents tab, and then click the link reading “events” under detailed description in the pages contents.

The class ExtendedButton is defined in “extendedbutton.h”. Following is the definition:

#include <QtWidgets/QPushButton>

 class ExtendedButton:public QPushButton {
     public:
         ExtendedButton(QWidget *parent=nullptr);
         void mouseReleaseEvent(QMouseEvent *event);
 };

The main object of the application is defined in “ui_example.h”, the file generated by “Qt Designer”, you better avoid changing it manually if you want to modify the “.ui” file from which it was generated. You’ll see a warning at the beginning. The role of the Class Ui_MainWindow is to contain main window (or central widget) and its underlying widgets as public members. The method setupUi binds them.

Creating the qmake file

“qmake” is an easy-to-use utility that generates a Makefile to be used by the make command to generate binaries, objects, libraries. etc. Qt Assistant includes a Qt Manual. Following is the content of the example’s qmake file named ‘qmake.pro’:

TARGET=executable
SOURCES+=main.cpp
HEADERS+=extendedbutton.h
FORMS+=example.ui
DESTDIR=bin
QT = core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

If you want the Make program to create the main header file, you can include the “.ui” file generated by Qt Designer in a variable named “FORMS”. The “make” program in turn will generate a header file from it with the prefix “ui_” added to the “.ui” file name. For example, from a file named “example.ui” the “make” program will generate a header file named “ui_example.h”. In this case, don’t add “ui_example.h” to the variable “HEADERS”.

If you want to know what to add to QT, go to the <Class Category>->C++ Classes and click the Detailed Description link.If you want to run qmake without command line arguments, call the qmake file ‘qmake.pro’.

Advertisement

Adding Java Classes to Rhino JavaScript

In the post LibreOffice Javascript, I wrote about Rhino Javascript, which is a Javascript interpreter written in Java. This tool has been developed by Mozilla. With this tool you can instantiate Java classes and to access them via Javascript commands ‘importClass’ and ‘importPackage’.

How to ass classes and packages you can load ?

This is not too hard: the ‘rhino’ command is a shell script. In linux, you can find it using the command:

which rhino

You’ll see the response:

/usr/bin/rhino

Then you can look into the file with a text editor or the ‘more’ command, and see that this is a script that performs a Java class. Jar files and classes that a Java programs uses are found in the environment variable ‘CLASSPATH” or after the directive ‘-classpath’. In this script you’ll find that the class path the content of the variable ‘JAVA_CLASSPATH’.

I decided to add the ‘Tidy’ package. In my computer the path of this package is ‘/usr/share/maven-repo/net/sf/jtidy/jtidy/debian/jtidy-debian.jar’, so the script looks like:

#!/bin/sh

JAVA_CMD=”/usr/bin/java”
JAVA_OPTS=””
JAVA_CLASSPATH=”/usr/share/java/js.jar:/usr/share/java/jline.jar:/usr/share/maven-repo/net/sf/jtidy/jtidy/debian/jtidy-debian.jar
JAVA_MAIN=”org.mozilla.javascript.tools.shell.Main”
export LD_LIBRARY_PATH=/home/amity/myWs
##
## Remove bootclasspath overriding for OpenJDK since
## it now use a mangled version of Rhino (in sun.org.mozilla.rhino package)
##
## References:
## <https://bugs.launchpad.net/ubuntu/+source/openjdk-6/+bug/255149&gt;
## <http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=179&gt;
## <http://www.openoffice.org/issues/show_bug.cgi?id=91641&gt;
##

$JAVA_CMD $JAVA_OPTS -classpath $JAVA_CLASSPATH $JAVA_MAIN “$@”

BTW, in Window, environment variables are enclosed by ‘%’ signes. For example: ‘%JAVA_CLASSPATH%’.

The Python Language And Proper Indentation

Hello, and welcome back. I’m new to Python, so this post is not a tutorial; you can find a tutorial here. I need this language in its modules for a course I’m taking on “coursera.org“.

If you are a Linux user, you have probably heard about that language. So, what’s special about Python? One of its feature is that it forces you to use proper indentation. This is good because proper indentation makes your code more readable. In Python you don’t need symbols (usually curly braces)for the beginning and end of a command block.

Let’s look at some examples.

From your command line type ‘python’ and ….

1. Start a statement with an unnecessary space

>>>  print "Beginning with a space"
    print "Beginning with a space"
    ^
IndentationError: unexpected indent
>>>

2. Don’t indent a sub-block

>>> i=7
>>> if i<8:
... print "i<8"
File "<stdin>", line 2
print "i<8"
^
IndentationError: expected an indented block
>>>

3. An ‘if’ block with more than one statement

>>> if i<8:
...   print 'a'
...   print 'b'
...   print 'c'
... 
a
b
c
>>>

4. Nested loops

>>> for i in range(4):
...   for j in range(3):
...     print 'inner loop i=' + str(i)
...     print 'j=' + str(j)
...   print 'outer loop i=' + str(i)
... 
inner loop i=0
j=0
inner loop i=0
j=1
inner loop i=0
j=2
outer loop i=0
inner loop i=1
j=0
inner loop i=1
j=1
inner loop i=1
j=2
outer loop i=1
inner loop i=2
j=0
inner loop i=2
j=1
inner loop i=2
j=2
outer loop i=2
inner loop i=3
j=0
inner loop i=3
j=1
inner loop i=3
j=2
outer loop i=3
>>>

Summary

Proper indentation makes your code more readable. In other languages, such as C, PHP and Perl, readability won’t guarantee correctness, but in Python you are less likely to have bug if you follow rules of readability.

LibreOffice – The Kakuro Cell Macro

This macro is to be run from the Calc program.

How does it work?

When the user starts the macro, a dialog is opened:

The user insets values for the upper and lower triangles, and clicks the submit button.

Then the macro draws two triangles in the cell selected. Each triangle is empty or contains a numeric value.

The program uses 3 main components:

  • The spreadsheet document.
  • dialog.
  • The draw-page part of the document, since graphics are not part of the cell contents. So, you would use a draw page to draw shapes.

The Code

This macro will create the dialog, add controls, and execute the dialog. A callback function will be attached to the submit button, and will draw the triangles.

Imports are not included; A link to the relevant data type will replace the import.


 // Define the triangle type in the cell
 enum TriangleType {
   UPPER, LOWER
 }

 public class KakuroCell {
   public XNameContainer m_xDlgModelNameContainer = null; // Allows to access controls by name.
   public XControlContainer m_xDlgContainer = null;       // The dialog contains controls, such as buttons, input fields, etc.
   public XMultiServiceFactory m_xMSFDialogModel = null;
   public XControl m_xDialogControl = null;
   public XTopWindow m_xTopWindow;
   public XComponentContext m_xContext;
   public XModel m_doc;
   public XSpreadsheetDocument m_spreadSheetDoc;
   public XMultiServiceFactory doc_multiServiceFactory;

      private void createDialog(XMultiComponentFactory _xMCF) {
      try {
          Object oDialogModel = _xMCF.createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", m_xContext);

          // The XMultiServiceFactory of the dialog model is needed to instantiate the controls...
          m_xMSFDialogModel = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, oDialogModel);

          // The named container is used to insert the created controls into...
          m_xDlgModelNameContainer = (XNameContainer) UnoRuntime.queryInterface(XNameContainer.class, oDialogModel);
          String[] sPropertyNames = new String[] {"Height", "Moveable", "Name","PositionX","PositionY", "Step", "TabIndex","Title","Width"};

          Object[] oObjectValues = new Object[] { new Integer(129), Boolean.TRUE, "KakuroDialog", new Integer(95),new Integer(100), new Integer(1), new Short((short) 0), "Kakuro Cell", new Integer(149)};

          setPropertyValues(sPropertyNames, oObjectValues);

          // create the dialog...
          Object oUnoDialog = _xMCF.createInstanceWithContext("com.sun.star.awt.UnoControlDialog", m_xContext);
          m_xDialogControl = (XControl) UnoRuntime.queryInterface(XControl.class, oUnoDialog);

          // The scope of the control container is public...
          m_xDlgContainer = (XControlContainer) UnoRuntime.queryInterface(XControlContainer.class, oUnoDialog);

          m_xTopWindow = (XTopWindow) UnoRuntime.queryInterface(XTopWindow.class, m_xDlgContainer); 

          // link the dialog and its model...
          XControlModel xControlModel = (XControlModel) UnoRuntime.queryInterface(XControlModel.class, oDialogModel);
          m_xDialogControl.setModel(xControlModel);

      } catch (com.sun.star.uno.Exception exception) {
          exception.printStackTrace(System.out);
      }
     } 

      // Define the dialog at the model - keep in mind to pass the property names in alphabetical order!
      public XMultiComponentFactory m_xMCF;
      public XWindowPeer m_xWindowPeer;     // This will ensure a dialog is opened.

      public void setPropertyValues(String[] PropertyNames, Object[] PropertyValues){
      try{
          XMultiPropertySet xMultiPropertySet = (XMultiPropertySet) UnoRuntime.queryInterface(XMultiPropertySet.class, m_xDlgModelNameContainer);
          xMultiPropertySet.setPropertyValues(PropertyNames, PropertyValues);
      } catch (com.sun.star.uno.Exception ex) {
          ex.printStackTrace(System.out);
      }}

      public void insertSubmitButton(String name, String label, short tabIndex, int posX, int posY, int width, int height){
          try {
              Object oSubmitButton = m_xMSFDialogModel.createInstance("com.sun.star.awt.UnoControlButtonModel");
                String[] sPropertyNames= new String[]{ "BackgroundColor", "DefaultButton", "Height", "Label", "Name",   "PositionX", "PositionY", "PushButtonType", "TabIndex", "Toggle",  "Width"};
                Object [] oObjectValues=new Object[]{ new Integer(0x006e7f50), Boolean.FALSE, new Integer(height), label,  name,   new Integer(posX), new Integer(posY), new Short((short)com.sun.star.awt.PushButtonType.STANDARD_value), new Short(tabIndex), Boolean.TRUE, new Integer(width)};
                XMultiPropertySet xSBModelMPSet = (XMultiPropertySet) UnoRuntime.queryInterface(XMultiPropertySet.class, oSubmitButton);
                xSBModelMPSet.setPropertyValues(sPropertyNames, oObjectValues);
                m_xDlgModelNameContainer.insertByName(name, xSBModelMPSet);
                XControl xButtonControl = m_xDlgContainer.getControl(name);
                XButton  xButton = (XButton) UnoRuntime.queryInterface(XButton.class, xButtonControl);
                xButton.addActionListener(new XActionListener() {

                    @Override
                    public void disposing(EventObject evtObj) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void actionPerformed(com.sun.star.awt.ActionEvent evt) {
                        // TODO Auto-generated method stub
                        try {
                          Object src=evt.Source;
                          XControl xControl=UnoRuntime.queryInterface(XXDialogControl.class, src);
                          Object controlModel=xControl.getModel();
                          XPropertySet ctlPropertySet=UnoRuntime.queryInterface(XPropertySet.class, controlModel);
                          String name=(String)ctlPropertySet.getPropertyValue("Name");
                            if (name.equals("Submit")){
                                ctlPropertySet.setPropertyValue("Enabled", Boolean.FALSE);
                                XControl upperCtl=m_xDlgContainer.getControl("UpperValue");
                                XControlModel upperModel = upperCtl.getModel();
                                XPropertySet upperPropertySet = UnoRuntime.queryInterface(XPropertySet.class, upperModel);
                                XControl lowerCtl=m_xDlgContainer.getControl("LowerValue");
                                XControlModel lowerModel = lowerCtl.getModel();
                                XPropertySet lowerPropertySet = UnoRuntime.queryInterface(XPropertySet.class, lowerModel);
                                String upperText = (String)upperPropertySet.getPropertyValue("Text");
                                String lowerText = (String)lowerPropertySet.getPropertyValue("Text");

                                int upperNumericValue = 0;
                                int lowerNumericValue = 0;
                                try {
                                    upperNumericValue=Integer.parseInt(upperText);
                                } catch (NumberFormatException nfe) {
                                    // Leave the numeric value zero
                                }

                                try {
                                    lowerNumericValue=Integer.parseInt(lowerText);
                                } catch (NumberFormatException nfe) {
                                    // Leave the numeric value zero
                                }

                                draw_cell (upperNumericValue, lowerNumericValue);
                                XDialog xDialog = (XDialog) UnoRuntime.queryInterface(XDialog.class, m_xDialogControl);
                                xDialog.endExecute();
                            }
                        } catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }); 
          } catch (Exception e){
             e.printStackTrace();
          }
      }

       // draw_cell - Get the cell's place and size, and draw the 2 triangles over it.
       public void draw_cell (int upperNumericValue, int lowerNumericValue) throws Exception{
          Object xSelection = m_doc.getCurrentSelection();
          XCellRange xCellRange = UnoRuntime.queryInterface(XCellRange.class, xSelection);
          XCell cell=null;
          try {
            cell=xCellRange.getCellByPosition(0, 0);
          } catch (IndexOutOfBoundsException e) {
            // TODO Auto-generated catch block
            throw new Exception("No cells selected.");
          }
          XCellAddressable xCellAddressable=UnoRuntime.queryInterface(XCellAddressable.class, cell);
          CellAddress cellAddress = xCellAddressable.getCellAddress();
          short sheetIx = cellAddress.Sheet;
          XSpreadsheets sheets = m_spreadSheetDoc.getSheets();
          XIndexAccess xIndexAccess = UnoRuntime.queryInterface(XIndexAccess.class, sheets);
          Object currentSheet = xIndexAccess.getByIndex(sheetIx);

          // Get the draw page properties from the spreadsheet
          XDrawPageSupplier xDrawPageSupplier=UnoRuntime.queryInterface(XDrawPageSupplier.class, currentSheet);
          XDrawPage drawPage = xDrawPageSupplier.getDrawPage();
          doc_multiServiceFactory = UnoRuntime.queryInterface(XMultiServiceFactory.class, m_doc);

          XPropertySet cellPropertySet=UnoRuntime.queryInterface(XPropertySet.class, cell);
          // Get the start point and the size of the cell.
          Point pt=(Point)cellPropertySet.getPropertyValue("Position");
          int ptx = pt.X;
          int pty = pt.Y;
          Size sz=(Size)cellPropertySet.getPropertyValue("Size");
          int width = sz.Width;
          int height = sz.Height;
          drawTriangle (drawPage, cell, ptx, pty, width, height, upperNumericValue, TriangleType.UPPER);
          drawTriangle (drawPage, cell, ptx, pty, width, height, lowerNumericValue, TriangleType.LOWER);
      }

      // Draw the triangle according to its coordinates and type, add its numeric value in it.
      private void drawTriangle(XDrawPage drawPage, XCell cell, int ptx, int pty, int width,
            int height, int numericValue, TriangleType triangleType) {
        // TODO Auto-generated method stub
        try {
            Object shapeObj = doc_multiServiceFactory.createInstance("com.sun.star.drawing.ClosedBezierShape");  // This is the type supported for polygons.
            XShape shape=UnoRuntime.queryInterface(XShape.class, shapeObj);
            Point shapePos=new Point(ptx, pty);
            shape.setPosition(shapePos);
            drawPage.add(shape);
            XPropertySet descriptor=UnoRuntime.queryInterface(XPropertySet.class, shape);
            Point[][] points=new Point[1][3];
            points[0][0]=new Point(ptx, pty);
            points[0][1]=triangleType==TriangleType.LOWER ? 
                    /* Yes */ new Point(ptx, pty + height) :
                    /* No  */ new Point(ptx + width, pty);
            points[0][2]=new Point(ptx+width, pty+height);
            PolygonFlags flags[][] = new PolygonFlags[1][3];
            flags[0][0] = flags[0][1] = flags[0][2] = PolygonFlags.NORMAL;      // All points are normal because the shape contains no curves.
            XText shapetext=UnoRuntime.queryInterface(XText.class, shapeObj);
            PolyPolygonBezierCoords coords=new PolyPolygonBezierCoords();
            coords.Flags = flags;
            coords.Coordinates = points;
            descriptor.setPropertyValue("PolyPolygonBezier", coords);
            String shapeString = numericValue!=0 ? Integer.toString(numericValue) : "";
            shapetext.setString(shapeString);
            XPropertySet textPropertySet = UnoRuntime.queryInterface(XPropertySet.class, shapetext);
            textPropertySet.setPropertyValue("CharHeight", 12.0);
            textPropertySet.setPropertyValue("CharColor", new Integer(0xffffff));
            textPropertySet.setPropertyValue("TextHorizontalAdjust", 
                    triangleType == TriangleType.LOWER ? 
                            /* Yes */ TextHorizontalAdjust.LEFT :
                            /* No  */ TextHorizontalAdjust.RIGHT);
            textPropertySet.setPropertyValue("TextVerticalAdjust", 
                    triangleType == TriangleType.LOWER ?
                            /* Yes */ TextVerticalAdjust.BOTTOM :
                            /* No  */ TextVerticalAdjust.TOP);
            textPropertySet.setPropertyValue("CharHeightComplex", 12.0);
            descriptor.setPropertyValue("Visible", true);
            descriptor.setPropertyValue("FillColor", new Integer(0));
            descriptor.setPropertyValue("Anchor", cell);
        } catch (Exception e){
            e.printStackTrace();
        }

    }

    // More dialog controls:
    public void insertNumericField(String name, String label, short tabIndex, int posX, int posY, int width, int height){
          try {
              Object oNumericField = m_xMSFDialogModel.createInstance("com.sun.star.awt.UnoControlEditModel");
                String[] sPropertyNames= new String[]{ "Height", "Name",   "PositionX", "PositionY", "TabIndex", "Width"};
                Object [] oObjectValues=new Object[]{ new Integer(height), name,   new Integer(posX), new Integer(posY), new Short(tabIndex), new Integer(width)};
                XMultiPropertySet xNFModelMPSet = (XMultiPropertySet) UnoRuntime.queryInterface(XMultiPropertySet.class, oNumericField);
                xNFModelMPSet.setPropertyValues(sPropertyNames, oObjectValues);
                m_xDlgModelNameContainer.insertByName(name, xNFModelMPSet);
          } catch (Exception e){
             e.printStackTrace();
          }
      }

      public void insertTextlabel(String name, String label, short tabIndex, int posX, int posY, int width, int height){
          try {
              Object oTextLabel = m_xMSFDialogModel.createInstance("com.sun.star.awt.UnoControlFixedTextModel");
                String[] sPropertyNames= new String[]{ "Height", "Label", "Name",   "PositionX", "PositionY", "TabIndex", "Width", "WritingMode"};
                Object [] oObjectValues=new Object[]{ new Integer(height), label, name,   new Integer(posX), new Integer(posY), new Short(tabIndex), new Integer(width), new Short(com.sun.star.text.WritingMode2.LR_TB)};
                XMultiPropertySet xFTModelMPSet = (XMultiPropertySet) UnoRuntime.queryInterface(XMultiPropertySet.class, oTextLabel);
                xFTModelMPSet.setPropertyValues(sPropertyNames, oObjectValues);
                m_xDlgModelNameContainer.insertByName(name, xFTModelMPSet);
          } catch (Exception e){
              e.printStackTrace();
          }
      }

      public void insertGroupBox (String id, short tabIndex, int posX, int posY, int width, int height){
          try {
            Object oGroupBox=null;
                oGroupBox = m_xMSFDialogModel.createInstance("com.sun.star.awt.UnoControlGroupBoxModel");
            String sName="FrameControl1";
            String[] sPropertyNames= new String[]{ "Height", "Name",   "PositionX", "PositionY", "Width", "WritingMode"};
            Object [] oObjectValues=new Object[]{ new Integer(height), sName,   new Integer(posX), new Integer(posY), new Integer(width), new Short(com.sun.star.text.WritingMode2.LR_TB)};

            XMultiPropertySet xGBModelMPSet = (XMultiPropertySet) UnoRuntime.queryInterface(XMultiPropertySet.class, oGroupBox);
            xGBModelMPSet.setPropertyValues(sPropertyNames, oObjectValues);
            m_xDlgModelNameContainer.insertByName(sName, xGBModelMPSet);
            XPropertySet xGBPSet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, oGroupBox);
            xGBPSet.setPropertyValue("Label", "Kakuro Values");
          } catch (Exception e){
              e.printStackTrace();               
        }
      }

      public short executeDialog() throws Exception{
          XWindow xWindow = (XWindow) UnoRuntime.queryInterface(XWindow.class, m_xDlgContainer);
          // set the dialog invisible until it is executed
          xWindow.setVisible(false);
          Object oToolkit = m_xMCF.createInstanceWithContext("com.sun.star.awt.Toolkit", m_xContext);
          XToolkit xToolkit = (XToolkit) UnoRuntime.queryInterface(XToolkit.class, oToolkit);
          XWindowPeer xWindowParentPeer = xToolkit.getDesktopWindow();
          m_xDialogControl.createPeer(xToolkit, xWindowParentPeer);
          m_xWindowPeer = m_xDialogControl.getPeer();
          XDialog xDialog = (XDialog) UnoRuntime.queryInterface(XDialog.class, m_xDialogControl);
          XComponent xDialogComponent = (XComponent) UnoRuntime.queryInterface(XComponent.class, m_xDialogControl);     
          // the return value contains information about how the dialog has been closed...
          short nReturnValue = xDialog.execute();
          // free the resources...
          xDialogComponent.dispose();
          //xDialogComponent.dispose();
          return nReturnValue;
      }

      // The entry point: this function will be called, when the user runs the macro.
      public  void start(XScriptContext xScriptContext) throws BootstrapException, Exception{
          m_doc=xScriptContext.getDocument();
          m_spreadSheetDoc = UnoRuntime.queryInterface(XSpreadsheetDocument.class, m_doc);
          if (m_spreadSheetDoc == null)
              throw new Exception("Invalid Document Type. Please call from a Calc document.");
          m_xMCF = xScriptContext.getComponentContext().getServiceManager();
          createDialog(m_xMCF);
          insertGroupBox("abc", (short)0, 16, 20, 112, 80);
          insertTextlabel("Label1", "Upper:", (short)-1, 22, 41, 22, 9);
          insertNumericField("UpperValue", "", (short)1, 55, 40, 56, 12);
          insertTextlabel("Label2", "Lower:", (short)-1, 22, 57, 26, 7);
          insertNumericField("LowerValue", "666", (short)2, 55, 56, 56, 12);
          insertSubmitButton("Submit", "Submit", (short)3, 48, 82, 46, 12);

          executeDialog();
      }

}

The Parcel Descriptor

 <?xml version="1.0" encoding="UTF-8"?>
<parcel language="Java" xmlns:parcel="scripting.dtd">
  <script language="Java">
    <locale lang="en">
      <displayname value="Kakuro Cell"/>
      <description>
        Dialog Excercise
      </description>
    </locale>
    <functionname value="KakuroCell.start"/>
    <logicalname value="KakuroCell.start"/>
    <languagedepprops>
        <prop name="classpath" value="kakuro.jar"/>
    </languagedepprops>
  </script>
</parcel>

Making C Programmer-Friendly with GNU Libraries

Does anybody remember how to program in C? Well, its syntax is similar to that of languages such as Java, PHP and others, but C uses a data type named pointer, and an array is a pointer, too. When you define an array, the system allocates enough space for it, but when you use the array nobody keeps you from accessing elements out of that array. You will not get a “Subscript out of range” error with the file’s name and line number. What you’ll get instead is a segmentation fault or another variable’s value will change. Use a debugger to find where it happens.
The library GLib has functions that perform operations on data structures like in modern object oriented languages. For example:
Use GArray, and you can enjoy the function ‘g_array_sort’ that sorts using a user-defined comparison function. This structure also allows you to increase the size of your array without calling ‘realloc’ implicitly.
GSList and GList are the data types of singly-linked and doubly-linked respectively, and a ‘foreach’ functions are defined to perform the same operation on each of their elements.
Other data structures are hash-tables, balanced binary trees, N-ary trees, etc.

An interesting utility is the command line option parser, that will check the validity of values passed via the command line and pass the values to function and global variables defined by the user. In addition, this utility will define the ‘–help’ flag, which will print your program’s command line flags and their use.

Of course, this is not everything you can do with GLib, GLib also supports threads and processes, events, etc.

Read more here.

If you want to distribute products you developed using GLib, you might be interested in the license. GLib is distributed under the Lesser GPL license, which means that you can distribute proprietary and open-source software developed with this library.