From d155ffcd59dac7e0e77de38c0db405f3015f653c Mon Sep 17 00:00:00 2001 From: Taiko2k Date: Wed, 19 Jan 2022 19:55:21 +1300 Subject: [PATCH] add part 1 --- README.md | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++ blank.png | Bin 0 -> 3893 bytes part1.py | 69 ++++++++++++++++ switch.png | Bin 0 -> 9701 bytes twoitems.png | Bin 0 -> 7498 bytes 5 files changed, 286 insertions(+) create mode 100644 README.md create mode 100644 blank.png create mode 100644 part1.py create mode 100644 switch.png create mode 100644 twoitems.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..3eb8afe --- /dev/null +++ b/README.md @@ -0,0 +1,217 @@ +# Bitchin GTK4 Python tutorial + +Wanna make apps for Linux but not sure how to start with GTK? Frustrated with the style of GTK4 documentation. This guide will hopefully get you started! + +Prerequisite: You have learnt the basics of Python + +## A most basic program + +```python +import gi +gi.require_version('Gtk', '4.0') +from gi.repository import Gtk + +def on_activate(app): + win = Gtk.ApplicationWindow(application=app) + win.present() + +app = Gtk.Application(application_id='com.example.GtkApplication') +app.connect('activate', on_activate) + +app.run(None) + +``` + +This should display a small blank window. + +![A blank GTK window](blank.png) + +Oh btw, you'll want to think of an application id for your app, especially if you're going to distribute it. It should be the reverse of a domain or page you control. If you dont have your own domain you can do like "com.github.me.myproject". + +Right um... lets make that code into classes! Cause doing it functional style is a little awkward in Python. + +Also, **Libawaita** is the new hotness, so lets switch to that! + +Aaand we'll pass the app arguments in. + +Here's what we got now: + +## A better structured basic GTK4 + Adwaita + + +```python +import sys +import gi +gi.require_version('Gtk', '4.0') +gi.require_version('Adw', '1') +from gi.repository import Gtk, Adw + + +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Things will go here + +class MyApp(Adw.Application): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.connect('activate', self.on_activate) + + def on_activate(self, app): + self.win = MainWindow(application=app) + self.win.present() + +app = MyApp(application_id="com.example.GtkApplication") +app.run(sys.argv) + +``` + +Soo we have an instance of an app class and a window which we extend! We run our app and it makes a window! + +Dont worry too much if your Python knowledge isn't strong and the `__init__(self, *args, **kwargs)` stuff is giving you a headache. + +### So! Whats next? + +Well, we want to add something to our window. That would likely be a layout of some sort! + +Most basic layout is a [Box](https://docs.gtk.org/gtk4/class.Box.html). + +Lets add a box to the window! (Where the comment "*things will go here*" is above) + +```python +self.box = Gtk.Box() +self.set_child(self.box) +``` + +We make a new box, and attach it to the window. Simple. If you run the app now you'll see no difference, because there's nothing in the layout yet either. + + +### Add a button! + +One of the most basic widgets is a [Button](https://docs.gtk.org/gtk4/class.Button.html). Let's make one and add it to the layout. + +```python +self.button = Gtk.Button(label="Hello") +self.box1.append(self.button) +``` + +Now our app has a button! (The window will be small now) + +But it does nothing when we click it. Let's connect it to a function! Make a new method that prints hello world, and we connect it! + +Here's our MainWindow so far: + +```python +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.set_child(self.box1) + + self.button = Gtk.Button(label="Hello") + self.box1.append(self.button) + self.button.connect('clicked', self.hello) + + def hello(self, button): + print("Hello world") +``` + +Cool eh? + +By the way the ***Box*** layout lays out widgets in like a vertical or horizontal order. We should set the orientation of the box. See the change: + +```python +self.box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) +``` + +### Quick intermission, lets set some fun stuff + +```python +self.set_default_size(600, 250) +self.set_title("MyApp") +``` + +## More boxes + +You'll notice our button is stenched with the window. Let's add two boxes inside that first box we made. + +```python +self.box1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) +self.box2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) +self.box3 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + +self.button = Gtk.Button(label="Hello") +self.button.connect('clicked', self.hello) + +self.set_child(self.box1) # Horizontal box to window +self.box1.append(self.box2) # Put vert box in that box +self.box1.append(self.box3) # And another one, empty for now + +self.box2.append(self.button) # But button in the first of the two vertial boxes +``` + +Now that's more neat! + +## Add a check button! + +So, we know about a button, next lets add a [Checkbutton](https://docs.gtk.org/gtk4/class.CheckButton.html). + +```python + ... + self.check = Gtk.CheckButton(label="And goodbye?") + self.box2.append(self.check) + + +def hello(self, button): + print("Hello world") + if self.check.get_active(): + print("Goodbye world!") + self.close() +``` + +![Our window so far](twoitems.png) + +When we click the button, we can check the state of the checkbox! + +## Add a switch + +For our switch, we'll want to put our switch in a ***Box***, otherwise it'll look all stretched. + +```python + ... + self.switch_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + + self.switch = Gtk.Switch() + self.switch.set_active(True) # Let's default it to on + self.switch.connect("state-set", self.switch_switched) # Lets trigger a function + + self.switch_box.append(self.switch) + self.box2.append(self.switch_box) + + def switch_switched(self, switch, state): + print(f"The switch has been switched {'on' if state else 'off'}") +``` + +Try it out! + +Our switch is looking rather nondescript, so lets add a label to it! + + +## Add a Label + +A label is like a basic line of text + +```python +self.label = Gtk.Label(label="A switch") +self.switch_box.append(self.switch) +self.switch_box.set_spacing(5) # Add some spacing + +``` + +It should look like this now: + +![Our window including switch and label](switch.png) + + + + diff --git a/blank.png b/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..adbf368def2708ad6c44c97e2a8a809af4616f36 GIT binary patch literal 3893 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 literal 0 HcmV?d00001 diff --git a/part1.py b/part1.py new file mode 100644 index 0000000..f30da99 --- /dev/null +++ b/part1.py @@ -0,0 +1,69 @@ +import sys +import gi + +gi.require_version('Gtk', '4.0') +gi.require_version('Adw', '1') +from gi.repository import Gtk, Adw + + +class MainWindow(Gtk.ApplicationWindow): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.set_default_size(600, 250) + self.set_title("MyApp") + + # Main layout containers + self.box1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.box2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.box3 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + + self.set_child(self.box1) # Horizontal box to window + self.box1.append(self.box2) # Put vert box in that box + self.box1.append(self.box3) # And another one, empty for now + + # Add a button + self.button = Gtk.Button(label="Hello") + self.button.connect('clicked', self.hello) + self.box2.append(self.button) # But button in the first of the two vertical boxes + + # Add a check button + self.check = Gtk.CheckButton(label="And goodbye?") + self.box2.append(self.check) + + # Add a box containing a switch and label + self.switch_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.switch_box.set_spacing(5) + + self.switch = Gtk.Switch() + self.switch.set_active(True) # Let's default it to on + self.switch.connect("state-set", self.switch_switched) # Lets trigger a function on state change + + self.label = Gtk.Label(label="A switch") + + self.switch_box.append(self.switch) + self.switch_box.append(self.label) + self.box2.append(self.switch_box) + + def switch_switched(self, switch, state): + print(f"The switch has been switched {'on' if state else 'off'}") + + def hello(self, button): + print("Hello world") + if self.check.get_active(): + print("Goodbye world!") + self.close() + + +class MyApp(Adw.Application): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.connect('activate', self.on_activate) + + def on_activate(self, app): + self.win = MainWindow(application=app) + self.win.present() + + +app = MyApp(application_id="com.example.GtkApplication") +app.run(sys.argv) diff --git a/switch.png b/switch.png new file mode 100644 index 0000000000000000000000000000000000000000..3394cd765e429eb871610ed75dab60a8bf7f0454 GIT binary patch literal 9701 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 Xz}p^N&zPJB=t3q&7KXSB*B<;IP=a__ literal 0 HcmV?d00001