Getting started with GTK3 or GTK4 directly

Linux specific forum
User avatar
StarBootics
Enthusiast
Enthusiast
Posts: 715
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Getting started with GTK3 or GTK4 directly

Post by StarBootics »

Hello everyone,

Don't get me wrong I like the way PureBasic handle windows and gadgets creation but I would like to known if any one of you has ever used GTK3 directly to create a program.

I'm searching for how to get started with GTK3 or GTK4 raw API in PureBasic.

Thanks in advance
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
mk-soft
Addict
Addict
Posts: 3191
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Getting started with GTK3 or GTK4 directly

Post by mk-soft »

Most of the GTK3 required functionality is already implemented in Purebasic. So you can also create immediately without the PB internal GUI functions also with GTK.
But then you have to rewrite everything yourself and look at the examples that are programmed in C++.

Example of an OpenFileRequester without PB GUI

Code: Select all

;-TOP

; Modify by mk-soft

EnableExplicit

ImportC ""
  gtk_file_chooser_dialog_new(title.p-utf8, *parent.GtkWidget, action.i, b1.p-utf8, a1.i, b2.p-utf8, a2.i, null);
  gtk_file_filter_set_name(*filter, label.p-utf8);
  gtk_file_filter_add_pattern(*filter,pattern.p-utf8)
  gtk_file_chooser_set_current_folder(*dialog, path.p-utf8)  
EndImport


Procedure.s MyOpenFileRequester(Title.s, Path.s, Pattern.s, PatterPostion, Flags = 0)
  Protected *dialog, *filter, *mem 
  Protected r1.l 
  Protected part.s, label.s, patter.s , index
  Protected FileName.s
  
  *dialog = gtk_file_chooser_dialog_new(Title, 0, #GTK_FILE_CHOOSER_ACTION_OPEN,
                                        #GTK_STOCK_CANCEL,#GTK_RESPONSE_CANCEL,
                                        #GTK_STOCK_OPEN,#GTK_RESPONSE_ACCEPT,
                                        #Null);
  
  gtk_window_set_modal_(*dialog, #True)
  
  gtk_file_chooser_set_current_folder_(*dialog,path)
  
  Repeat
    index + 1
    part = StringField(pattern, index, ";")
    If part = ""
      Break
    EndIf
    *filter = gtk_file_filter_new_()
    label.s = StringField(part, 1, "|")
    patter.s =  StringField(part, 2, "|")
    gtk_file_filter_set_name(*filter, label)
    gtk_file_filter_add_pattern(*filter, patter)
    gtk_file_chooser_add_filter_(*dialog, *filter)
  ForEver
  
  r1 = gtk_dialog_run_(*dialog)
  If r1  = #GTK_RESPONSE_ACCEPT
    *mem = gtk_file_chooser_get_filename_(*dialog);
    filename.s = PeekS(*mem, -1, #PB_UTF8) 
    If *mem 
      g_free_(*mem);
    EndIf
  Else
    FileName = ""
  EndIf 
  
  gtk_widget_destroy_(*dialog) 
  
  ProcedureReturn FileName
  
EndProcedure

gtk_init_(0, 0)

Define file.s = MyOpenFileRequester("Test", "/home", "PB-Files|*.pb;All Files|*", 0 , 0)
Debug file
Das gleiche gilt für Windows mit API ...
My Projects ThreadToGUI / OOP-BaseClass / OOP-BaseClassDispatch / EventDesigner V3
PB v3.30 / v5.70 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace
User avatar
Shardik
Addict
Addict
Posts: 1840
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Getting started with GTK3 or GTK4 directly

Post by Shardik »

The first starting point would be to read the GTK reference
GTK+ Overview > Getting Started with GTK+ > Building applications

There you will find C examples with increasing complexity.

Beginning with GTK3 all examples use GtkApplication. To reduce complexity and in order to run my examples on GTK2 and GTK3 I don't use the recommended way with GtkApplication.

A simple example to display a window in PureBasic using only GTK functions:

Code: Select all

ProcedureC WindowCloseHandler(*Widget.GtkWidget, *Event.GdkEventAny, UserData.I)
  gtk_main_quit_()
EndProcedure

gtk_init_(0, 0)
Window = gtk_window_new_(#GTK_WINDOW_TOPLEVEL)

If Window
  gtk_window_set_default_size_(Window, 200, 110)
  gtk_window_set_title_(Window, "API Window")
  gtk_window_set_position_(Window, #GTK_WIN_POS_NONE)
  gtk_window_move_(Window, 270, 100)
  
  g_signal_connect_(Window, "delete-event", @WindowCloseHandler(), 0)
  g_signal_connect_(Window, "destroy", @WindowCloseHandler(), 0)
  
  gtk_widget_show_(Window)
  gtk_main_()
EndIf

A simple example to display a Window and an image in PureBasic using only GTK functions:

Code: Select all

ProcedureC WindowCloseHandler(*Widget.GtkWidget, *Event.GdkEventAny, UserData.I)
  gtk_main_quit_()
EndProcedure

If LoadImage(0, #PB_Compiler_Home + "examples/sources/Data/Geebee2.bmp")
  gtk_init_(0, 0)
  Window = gtk_window_new_(#GTK_WINDOW_TOPLEVEL)
  
  If Window
    gtk_window_set_default_size_(Window, ImageWidth(0), ImageHeight(0))
    gtk_window_set_title_(Window, "API")
    gtk_window_set_position_(Window, #GTK_WIN_POS_NONE)
    gtk_window_move_(Window, 100, 100)
    
    Layout = gtk_layout_new_(0, 0)
    gtk_container_add_(Window, Layout)
    gtk_widget_show_(Layout)
    
    gtk_layout_put_(Layout, gtk_image_new_from_pixbuf_(ImageID(0)), 0, 0)
    gtk_widget_show_all_(Window)
    
    g_signal_connect_(Window, "delete-event", @WindowCloseHandler(), 0)
    g_signal_connect_(Window, "destroy", @WindowCloseHandler(), 0)
    
    gtk_widget_show_(Window)
    gtk_main_()
  EndIf
EndIf

In order to create complex dialogs, you may use strings or files containing XML to describe the widgets. In this case you need the GtkBuilder, an interface builder which interprets the XML UI. The following example uses XML definitions and GtkBuilder to display a window with a GtkButton. When clicking the button, a PureBasic MessageRequester will be displayed:

Code: Select all

; Converted from C source code:
; https://de.wikibooks.org/wiki/GTK_mit_Builder:_Builder

EnableExplicit

#GUI = "" +
  ~"<interface>" + #CR$ +
  ~"  <object class=\"GtkWindow\" id=\"Window\">" + #CR$ +
  ~"    <property name=\"title\">Demo</property>" + #CR$ +
  ~"    <child>" + #CR$ +
  ~"      <object class=\"GtkButton\" id=\"Button\">" + #CR$ +
  ~"        <property name=\"label\">Click me!</property>" + #CR$ +
  ~"      </object>" + #CR$ +
  ~"    </child>" + #CR$ +
  ~"  </object>" + #CR$ +
  ~"</interface>"

ImportC ""
  gtk_builder_add_from_string(*GtkBuilder, Text.P-UTF8, TextLength.L,
    *Error.GError)
  gtk_builder_get_object(*GtkBuilder, ObjectName.P-UTF8)
  gtk_builder_new()
EndImport

Define Button.I
Define *Error.GError
Define GtkBuilder.I
Define Window.I

ProcedureC WindowDestroyedCallback()
  gtk_main_quit_()
EndProcedure

ProcedureC ButtonClickedCallback(*Widget.GtkWidget, *UserData)
  MessageRequester("Info",
    "Hello world!")
EndProcedure

; ----- Initialize GTK
gtk_init_(0, 0)

; ----- Load XML definition string
GtkBuilder = gtk_builder_new()
gtk_builder_add_from_string(GtkBuilder, #GUI, Len(#GUI), @*Error)

; ----- Get window from XML string
Window = gtk_builder_get_object(GtkBuilder, "Window")

; ----- Connect signal "destroy" to be able to quit GTK event loop
g_signal_connect_(Window, "destroy", @WindowDestroyedCallback(), 0)

; ----- Get button from XML string
Button = gtk_builder_get_object(GtkBuilder, "Button")

; ----- Connect signal "clicked" to button
g_signal_connect_(Button, "clicked", @ButtonClickedCallback(), 0)

; ----- Remove reference to GtkBuilder
g_object_unref_(GtkBuilder)

; ----- Display window defined in XML string
gtk_widget_show_all_(Window)

; ----- Move window to position x = 200 and y = 100
gtk_window_move_(Window, 200, 100)

; ----- Start GTK event loop
gtk_main_()

To ease the use of creating complex dialogs, you may try the user interface designer Glade. For a simple example I have created a ComboBox with Glade. This is the generated XML which I have saved in my home folder as ComboBoxDemo.glade:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
  <requires lib="gtk+" version="3.12"/>
  <object class="GtkWindow" id="Window">
    <property name="can_focus">False</property>
    <property name="title" translatable="yes">ComboBox Demo</property>
    <property name="default_width">220</property>
    <property name="default_height">100</property>
    <child>
      <object class="GtkFixed" id="FixedFrame">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkComboBox" id="ComboBox">
            <property name="width_request">100</property>
            <property name="height_request">30</property>
            <property name="visible">True</property>
            <property name="can_focus">False</property>
          </object>
          <packing>
            <property name="x">60</property>
            <property name="y">30</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>
And this is the example displaying the window and ComboBox generated with Glade:

Code: Select all

; C example for creating a simple Window with Glade:
; https://prognotes.net/2015/06/gtk-3-c-program-using-glade-3/

; C example for adding entries to a GtkComboBox
; http://blog.borovsak.si/2009/04/as-promised-im-back-with-second-part-of.html

EnableExplicit

#G_TYPE_STRING = 16 << 2 ; = 64
#GladeFile = "ComboBoxDemo.glade"

ImportC ""
  gtk_builder_get_object(*GtkBuilder, ObjectName.P-UTF8)
  gtk_builder_new_from_file(Filename.P-UTF8)
EndImport

Define CellRenderer.I
Define ComboBox.I
Define GtkBuilder.I
Define i.I
Define ItemText.GValue
Define Iter.I
Define ListStore.I
Define Window.I

ProcedureC WindowDestroyedCallback()
  gtk_main_quit_()
EndProcedure

; ----- Initialize GTK
gtk_init_(0, 0)

; ----- Load Glade definition file
If FileSize(#GladeFile) < 1
  MessageRequester("Error",
    "Unable to find Glade definition file!")
  End
EndIf

GtkBuilder = gtk_builder_new_from_file(#GladeFile)

; ----- Get Window from Glade definition
Window = gtk_builder_get_object(GtkBuilder, "Window")

; ----- Get ComboBox from Glade definition
ComboBox = gtk_builder_get_object(GtkBuilder, "ComboBox")

; ----- Remove reference to GtkBuilder
g_object_unref_(GtkBuilder)

; ----- Create ListStore and fill it with ComboBox items
ListStore = gtk_list_store_new_(1, #G_TYPE_STRING)
ItemText\g_type = #G_TYPE_STRING

For i = 1 To 7
  g_value_set_string_(@ItemText, "Item " + Str(i))
  gtk_list_store_append_(ListStore, @Iter)
  gtk_list_store_set_value_(ListStore, @Iter, 0, @ItemText)
Next i

; ----- Connect ComboBox with ListStore
gtk_combo_box_set_model_(ComboBox, ListStore)

; ----- Remove reference to ListStore
g_object_unref_(ListStore)

; ----- Create cell renderer and pack it into ComboBox
CellRenderer = gtk_cell_renderer_text_new_()
gtk_cell_layout_pack_start_(ComboBox, CellRenderer, #True)

; ----- Connect renderer to data source
gtk_cell_layout_add_attribute_(ComboBox, CellRenderer, "text", 0)

; ----- Display "Item 4" in ComboBox
gtk_combo_box_set_active_(ComboBox, 3)

; ----- Connect destroy signal to be able to quit GTK event loop
g_signal_connect_(Window, "destroy", @WindowDestroyedCallback(), 0)

; ----- Display window defined in Glade file
gtk_widget_show_(Window)

; ----- Move window to position x = 200 and y = 100
gtk_window_move_(Window, 200, 100)

; ----- Start GTK event loop
gtk_main_()
I have tested all examples successfully on Linux Mint 19.3 x64 'Tricia' with Cinnamon and PB 5.73 x64 with GTK2 and GTK3.
User avatar
StarBootics
Enthusiast
Enthusiast
Posts: 715
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: Getting started with GTK3 or GTK4 directly

Post by StarBootics »

Hello everyone,

Thanks for the replies, very appreciated. I will have a closer look.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
Post Reply