<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PySide6 | Jon Macey's WebPages</title><link>https://nccastaff.bournemouth.ac.uk/jmacey/tag/PySide6/</link><atom:link href="https://nccastaff.bournemouth.ac.uk/jmacey/tag/PySide6/index.xml" rel="self" type="application/rss+xml"/><description>PySide6</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><copyright>Jon Macey 2026</copyright><lastBuildDate>Wed, 07 Jan 2026 00:00:00 +0000</lastBuildDate><image><url>https://nccastaff.bournemouth.ac.uk/jmacey/images/icon_hud717fbbd2ac8fad60548edad7ad9704b_11827_512x512_fill_lanczos_center_3.png</url><title>PySide6</title><link>https://nccastaff.bournemouth.ac.uk/jmacey/tag/PySide6/</link></image><item><title>Lecture 6 Intro to PySide</title><link>https://nccastaff.bournemouth.ac.uk/jmacey/proggraphics/lectures/Lecture6/</link><pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate><guid>https://nccastaff.bournemouth.ac.uk/jmacey/proggraphics/lectures/Lecture6/</guid><description>&lt;h2 id="slideshttpsnccastaffbournemouthacukjmaceylecturesproggraphpyside6homejmaceyproggraphics">
&lt;a href="https://nccastaff.bournemouth.ac.uk/jmacey/Lectures/ProgGraph/PySide6/?home=/jmacey/proggraphics" target="_blank" rel="noopener">Slides&lt;/a>&lt;/h2>
&lt;iframe width=860 height = 440 allowfullscreen="allowfullscreen" src="https://nccastaff.bournemouth.ac.uk/jmacey/Lectures/ProgGraph/PySide6/?home=/jmacey/proggraphics/Lectures/Lecture6"> &lt;/iframe>
&lt;h2 id="self-study">Self Study&lt;/h2>
&lt;p>
&lt;a href="https://www.qt.io/" target="_blank" rel="noopener">Qt Homepage&lt;/a>&lt;/p>
&lt;iframe width="860" height="440" src="https://www.youtube.com/embed/9jxuMzU7r-8" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen>&lt;/iframe></description></item><item><title>Vibe learning rust by building an app (spoiler I didn't)</title><link>https://nccastaff.bournemouth.ac.uk/jmacey/post/VenvCleaner/VenvCleaner/</link><pubDate>Thu, 24 Apr 2025 00:00:00 +0000</pubDate><guid>https://nccastaff.bournemouth.ac.uk/jmacey/post/VenvCleaner/VenvCleaner/</guid><description>&lt;h1 id="introduction">Introduction&lt;/h1>
&lt;p>I have decided to write a simple .venv cleaning tool to use in the labs. I decided to use rust (as every new python tool is written in rust as it&amp;rsquo;s blazingly fast (tm) ). I don&amp;rsquo;t know rust, but I&amp;rsquo;m hoping Claude sonnet 4 does. I will be vibe coding this app using the techniques I discovered when writing my
&lt;a href="https://nccastaff.bournemouth.ac.uk/jmacey/post/AppsEre/AppsEre/" target="_blank" rel="noopener">Apps&amp;rsquo;ere&lt;/a> tool.&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>I already rust installed on my mac using
&lt;a href="https://rustup.rs/" target="_blank" rel="noopener">rustup&lt;/a> and I will again be using the zed editor. In the last demo I used copilot as my AI, this time I am going to sign up for the free trial of Claude Sonnet 4 that comes with Zed to give this a try.&lt;/p>
&lt;h1 id="rules-file">.rules file&lt;/h1>
&lt;p>To start with I have been doing some
&lt;a href="https://xkcd.com/293/" target="_blank" rel="noopener">RTFM&lt;/a> and discovered the zed
&lt;a href="https://zed.dev/docs/ai/rules" target="_blank" rel="noopener">rules&lt;/a> file which allows us to communicate set criterial with the agent. I have written the initial basic .rules file (note the typos again!)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>You are to use rust as the programming language.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>You can use any libraries that are required and these can be installed via cargo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>All code should have full comments and explainations and use the rust styleguide
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>This app is designed to work in three modes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>1. cli with command lines
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>2. tui with simple interface
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>3. gui which will use Qt6 rust bindings&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;h1 id="design-document">Design Document&lt;/h1>
&lt;p>Most articles on
&lt;a href="https://zapier.com/blog/how-to-vibe-code/#prd" target="_blank" rel="noopener">vibe coding&lt;/a> recommend writing a Product Requirments Documet
&lt;a href="https://www.productplan.com/glossary/product-requirements-document/" target="_blank" rel="noopener">PRD&lt;/a> I have written a very simple one to get started.&lt;/p>
&lt;details>
&lt;summary>PRD click to expand&lt;/summary>
&lt;h1 id="venv-cleaner">Venv cleaner&lt;/h1>
&lt;h2 id="cli-mode">cli mode&lt;/h2>
&lt;p>Is an 3 mode application to help manage and clean up .venv folders on mac and linux.&lt;/p>
&lt;p>The fist mode is cli, this allows the user to run the tool venv_cleaner [dir] with the following command lines&lt;/p>
&lt;p>-r recurse and search from the current directory
-f force always delete&lt;/p>
&lt;p>The tool will search for a .venv in the current folder or one passed and prompt the user if found if it should be deleted. If yes then the .venv folder will be removed. If the -r or -f flags are used&lt;/p>
&lt;p>-q query&lt;/p>
&lt;p>will recurse the directory passed or current directory and print out the path / and size of the .venv folder. The size should be reported in either Mb or Gb depending upon the size.&lt;/p>
&lt;h2 id="tui">tui&lt;/h2>
&lt;p>This will use the rust tui library to give a console based application. this is activated using the &amp;ndash;tui flag.&lt;/p>
&lt;p>It will open the current folder and present a view of each .venv folders found by recursing.&lt;/p>
&lt;p>It will display in a list the following information&lt;/p>
&lt;p>location size in bytes last used data created date&lt;/p>
&lt;p>There should be the ability to open a new folder , delete the selected .venv in the list as well as order by date of creation&lt;/p>
&lt;h2 id="gui">Gui&lt;/h2>
&lt;p>This will as the same functionality as the tui version but use a Qt6 based GUI rather than a tui.&lt;/p>
&lt;/details>
&lt;h2 id="getting-started">Getting Started&lt;/h2>
&lt;p>With all this in place I sent the agent a message, including the .rules and Design.md&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Write the initial project files and folders for the venv cleaner app. Start with the cli mode described.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>As I had zed in
&lt;a href="https://zed.dev/docs/ai/agent-panel#built-in-profiles" target="_blank" rel="noopener">&amp;ldquo;write&amp;rdquo;&lt;/a> mode it went off and wrote a file of stuff for me.&lt;/p>
&lt;p>First a Cargo.toml file with all the elements required. Then a src folder with a number of rust files. This took a while so I got a coffee!&lt;/p>
&lt;p>It generate 7 files including README.md and a License file. It then asked if it could compile and run the tool to check it. It had written a load of unit tests as well.&lt;/p>
&lt;p>Compilation actually failed so it went back and fixed it. Finally it compiles with a few warning.&lt;/p>
&lt;p>It then asked permission to run the tests. Which worked after the fixes.&lt;/p>
&lt;h2 id="slow-down">Slow down!&lt;/h2>
&lt;p>The agent then went a bit mental writing all sorts of scripts to build the tools and also to install and setup rust none of which were required. It has only written the basic command line tool which seems to work well.&lt;/p>
&lt;p>In the overall build setup there are executables for each of the TUI / GUI mode but none of the TUI / GUI mode stuff actually works.&lt;/p>
&lt;p>This initial setup has created a 45k/200k context and used up 28/50 of my prompt usage (I was on about 12 when I started so not too bad).&lt;/p>
&lt;p>I&amp;rsquo;ve not actually looked at any of the code generated or how the project actually works yet!&lt;/p>
&lt;h2 id="tui-mode">TUI mode&lt;/h2>
&lt;p>I prompted the agent to develop the tui mode for me an let it work whilst I got breakfast (it is 6.30 am). This took about 20 minutes so managed to do the washing up too!&lt;/p>
&lt;p>At some stage the Agent asked me to turn on
&lt;a href="https://zed.dev/docs/ai/models#burn-mode" target="_blank" rel="noopener">Burn Mode&lt;/a> this seems to eat up the free usage I have (44/50) I switched to the pro trial for 14 days to give it a go.&lt;/p>
&lt;p>You can see some of zed in action here&lt;/p>
&lt;video width="320" height="240" controls>
&lt;source src="https://nccastaff.bournemouth.ac.uk/jmacey/jmacey/post/VenvCleaner/VibeCode.mov" type="video/mp4">
&lt;/video>
&lt;h2 id="some-upgrades">Some upgrades.&lt;/h2>
&lt;p>The basic TUI system was working well but I wanted to make a few updates after using it. The main one was to get it to add feedback to the user and show the tui when scanning the directories. This worked well.&lt;/p>
&lt;h2 id="gui-mode">GUI Mode&lt;/h2>
&lt;p>Next I wanted to add a gui mode, however after a little bit of reading I decided not to use the Qt rust bindings as it seems a little over complicated for what I needed. There are a number of
&lt;a href="https://simplifycpp.org/?id=a0507" target="_blank" rel="noopener">gui libraries&lt;/a> for rust, in the end I decided to use
&lt;a href="https://github.com/emilk/egui" target="_blank" rel="noopener">egui&lt;/a> as it seemed the simplest one. First thing I did was to update the .rules file.&lt;/p>
&lt;pre>&lt;code>3. gui which will use egui rust bindings
&lt;/code>&lt;/pre>
&lt;p>I have quite a large context window now (144k/200k) so this may cause some issues. but I added the prompt&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Now write a full gui version of the tool using egui. Try to immitate the tui version.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>I started off the process and made more coffee! It took a while and had a few initial compilation errors but now I have a full gui!&lt;/p>
&lt;h2 id="app-working">App working&lt;/h2>
&lt;video width="320" height="240" controls>
&lt;source src="https://nccastaff.bournemouth.ac.uk/jmacey/jmacey/post/VenvCleaner/VenvCleanerDemo.mov" type="video/mp4">
&lt;/video>
&lt;h2 id="analysis">Analysis&lt;/h2>
&lt;p>The full source code is on
&lt;a href="https://github.com/NCCA/VenvCleaner" target="_blank" rel="noopener">Github&lt;/a>&lt;/p>
&lt;p>The agent has developed 13 rust files, split into a folder structure as follows&lt;/p>
&lt;pre>&lt;code>ls src/
cli core gui main.rs tui
&lt;/code>&lt;/pre>
&lt;p>It further developed a Cargo.toml build file as well as a build script all of which work and I have re-built the tool under linux (needed to install a few extra system libraries first).&lt;/p>
&lt;p>My final context window is 185K / 200K and I have used up approx 50 prompts from my allowance (i didn&amp;rsquo;t make notes of this to start) this is approx $2.50 if I have understood the
&lt;a href="https://zed.dev/docs/ai/models" target="_blank" rel="noopener">billing&lt;/a> correctly.&lt;/p>
&lt;h3 id="timeline-of-development">Timeline of development&lt;/h3>
&lt;p>Monday Night&lt;/p>
&lt;ol>
&lt;li>Monday night, had an idea that I needed a tool to make cleaning .venvs easier for the students.&lt;/li>
&lt;li>Decided to vibe code in rust tomorrow ( I also dream designed some of it!)&lt;/li>
&lt;/ol>
&lt;p>Tuesday Morning&lt;/p>
&lt;p>I started writing this post whilst the AI was doing stuff, and finished it off after lunch.&lt;/p>
&lt;ul>
&lt;li>6 am started to design the .rules file and PDB&lt;/li>
&lt;li>7 am initial code written by AI had breakfast&lt;/li>
&lt;li>8 am commit first version (08:13) did school run and thought about next steps&lt;/li>
&lt;li>9 am got cli working and tested added a few features&lt;/li>
&lt;li>10 am started the TUI version committed about 10.30 (had coffee)&lt;/li>
&lt;li>11 am did research about gui options and made gui version&lt;/li>
&lt;li>11.30 got it working on linux which required lib installs and coffee&lt;/li>
&lt;li>12.30 finished gui version deployed to linux and my AppsEre app&lt;/li>
&lt;/ul>
&lt;p>That&amp;rsquo;s it for the day, I made a sandwich whilst the gui version was building, guess it&amp;rsquo;s time for the pub now :-)&lt;/p>
&lt;h2 id="final-thoughts">Final Thoughts&lt;/h2>
&lt;p>Yet again I have written a fully working program with no knowledge of the code or how it works. Am I scared? Not sure yet. My next step is top analyze both code bases and see what I have produces.&lt;/p>
&lt;p>I&amp;rsquo;m really happy with the cli and TUI versions and I must say the Agent has design the layout and key bindings well. It has added extra features I did not specify (for example &amp;ndash;dry-run and &amp;ndash;force)&lt;/p>
&lt;p>I needed to add some extra features for the TUI such as prompts to show the tool in action when scanning large folders etc.&lt;/p>
&lt;p>The gui is not quite as nice but does work. I will keep it for now but may in future see how I can use Qt / QML in rust (once I have learnt how to program in rust).&lt;/p>
&lt;p>You can see the full agent dialog
&lt;a href="https://github.com/NCCA/VenvCleaner/blob/main/AIChat1.md" target="_blank" rel="noopener">here&lt;/a>&lt;/p>
&lt;p>I will be using both the tools I have developed, I may even have to incorporate this into my teaching.&lt;/p>
&lt;p>BTW I have yet to learn rust!&lt;/p></description></item><item><title>I vibe coded and App and don't know how it works (yet!)</title><link>https://nccastaff.bournemouth.ac.uk/jmacey/post/AppsEre/AppsEre/</link><pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate><guid>https://nccastaff.bournemouth.ac.uk/jmacey/post/AppsEre/AppsEre/</guid><description>&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>I recently decided I needed to write an new &amp;ldquo;Launcher&amp;rdquo; app for our linux build to match what we have on windows (AppsAnywhere) this would make it easier for students who are new to Linux and make it easier to see what is actually installed on the build which is not always obvious.&lt;/p>
&lt;p>As an experience developer I had a number of tools I could have used to build this, however I also want to learn some new api as part of the development so I can use them in teaching next year. To this end I decided to use PySide6 (which I already use) but instead of using QWidgets I decided to use
&lt;a href="https://doc.qt.io/qt-6/qtquick-index.html" target="_blank" rel="noopener">QML / QtQuick&lt;/a> instead.&lt;/p>
&lt;p>I started by doing a few of the excellent tutorials at the
&lt;a href="https://www.qt.io/academy" target="_blank" rel="noopener">Qt Academy&lt;/a> but learning by video is not really my thing and I wanted to just dive into the code.&lt;/p>
&lt;h2 id="using-vibes">Using Vibes&lt;/h2>
&lt;p>Recently there has been lots of talk about &amp;ldquo;vibe coding&amp;rdquo; which according to
&lt;a href="https://en.wikipedia.org/wiki/Vibe_coding" target="_blank" rel="noopener">wikipedia&lt;/a> is&lt;/p>
&lt;blockquote>
&lt;p>is an approach to producing software by using artificial intelligence (AI), where a person describes a problem in a few natural language sentences as a prompt to a large language model (LLM) tuned for coding. The LLM generates software based on the description, shifting the programmer&amp;rsquo;s role from manual coding to guiding, testing, and refining the AI-generated source code.&lt;/p>
&lt;/blockquote>
&lt;p>This also seems to be an approach used by many students over the last few year so I thought I would give it a go, after all what could go wrong?&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>Whilst the target for the app is our Lab Linux build (RHEL 9.5) I typically do all of my development on my Mac and remote into my Linux Machine when needed. The setup I am going to use is the excellent
&lt;a href="https://zed.dev/" target="_blank" rel="noopener">zed&lt;/a> editor. I will use
&lt;a href="https://docs.astral.sh/uv/" target="_blank" rel="noopener">uv&lt;/a> for all my python setup as this is now my core python workflow.&lt;/p>
&lt;p>For the AI / LLM I have several options.&lt;/p>
&lt;ol>
&lt;li>ChatGPT mac desktop version.&lt;/li>
&lt;li>Github Co-Pilot Chat (GPT-4.1) as part of Github classroom&lt;/li>
&lt;li>Ollama installed models such as Devstall running locally on mac&lt;/li>
&lt;/ol>
&lt;p>I decided to mainly use co-pilot as it is integrated into zed well and I get very high usage as part of the educational package.&lt;/p>
&lt;h2 id="getting-started">Getting Started&lt;/h2>
&lt;p>I already had a plan of what I wanted to do, and after reading some articles on vibe coding many people suggested creating a markdown document with the initial design which feeds into the context of the LLM chat.&lt;/p>
&lt;p>I started with this basic outline of the the app&lt;/p>
&lt;p>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>md AppLauncher/Design.md
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>This is a PySide6 App using QML for the core GUI elements. It uses an json to store the app information.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>App Json format
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>App : [Path, Executable Name, App description, path to icons] The app will have pages of related items in tabs represented as icon buttons.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Each App will have a json entry to say which tab it belongs too and the user is able to re-arrange the items in the button window.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>The user is also able to right click on the buttons and add to a new favourite tab as well.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
Next I asked it to&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Write a python json loader / writer with unit test for this format.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The results were ok but not really what I wanted (see chat log
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat1.md#user" target="_blank" rel="noopener">here&lt;/a>) So I jumped straight in for a full app.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>write a tabbed QML Pyside window which allows the user to re-arrange square buttons in each of the tabs. When pressed these tabs will launch an app loaded from the json file&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The agent came back with suggestions of two files.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Here’s a basic structure for a PySide6 app using QML that meets your requirements:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Tabs: Each tab represents a category (from the JSON).
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Square Buttons: Each app is a draggable square button in its tab.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Rearrange: Drag-and-drop to rearrange buttons within a tab.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Launch: Clicking a button launches the app (using subprocess).
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> JSON Loading: Loads app data from your JSON file.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Below are the main files you’ll need:&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;details>
&lt;summary>main.qml click to expand&lt;/summary>
&lt;pre>&lt;code>import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
id: window
visible: true
width: 800
height: 600
title: &amp;quot;App Launcher&amp;quot;
property var tabsModel: []
TabView {
id: tabView
anchors.fill: parent
Repeater {
model: tabsModel
Tab {
title: modelData.tabName
GridView {
id: gridView
anchors.fill: parent
cellWidth: 100
cellHeight: 100
model: modelData.apps
dragMargin: 20
interactive: true
delegate: Rectangle {
width: 90
height: 90
color: &amp;quot;#f0f0f0&amp;quot;
border.color: &amp;quot;#888&amp;quot;
radius: 8
Drag.active: dragArea.drag.active
Drag.hotSpot.x: 45
Drag.hotSpot.y: 45
Image {
source: icon
anchors.centerIn: parent
width: 48
height: 48
}
Text {
text: name
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
font.pixelSize: 14
elide: Text.ElideRight
}
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
onClicked: {
appLauncher.launchApp(path, execName)
}
}
}
onMove: {
appLauncher.rearrange(tabView.currentIndex, from, to)
}
}
}
}
}
}
&lt;/code>&lt;/pre>
&lt;/details>
&lt;details>
&lt;summary>main.py click to expand&lt;/summary>
&lt;pre>&lt;code class="language-python">import sys
import json
import subprocess
from PySide6.QtWidgets import QApplication
from PySide6.QtCore import QObject, Slot, Property, QUrl, Signal
from PySide6.QtQml import QQmlApplicationEngine
class AppLauncher(QObject):
def __init__(self, apps_by_tab):
super().__init__()
self._apps_by_tab = apps_by_tab
@Slot(str, str)
def launchApp(self, path, execName):
try:
subprocess.Popen([f&amp;quot;{path}/{execName}&amp;quot;])
except Exception as e:
print(f&amp;quot;Failed to launch: {e}&amp;quot;)
@Slot(int, int, int)
def rearrange(self, tabIndex, fromIndex, toIndex):
# Implement rearrange logic and persist to JSON if needed
tab = self._apps_by_tab[tabIndex]
apps = tab['apps']
app = apps.pop(fromIndex)
apps.insert(toIndex, app)
# Optionally: save to JSON here
def load_apps_json(json_path):
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# Organize by tab
tabs = {}
for app_name, entry in data.items():
path, exec_name, desc, icon, tab_name = entry
if tab_name not in tabs:
tabs[tab_name] = []
tabs[tab_name].append({
'name': app_name,
'path': path,
'execName': exec_name,
'desc': desc,
'icon': icon
})
# Convert to list of dicts for QML
return [{'tabName': tab, 'apps': apps} for tab, apps in tabs.items()]
if __name__ == &amp;quot;__main__&amp;quot;:
app = QApplication(sys.argv)
apps_by_tab = load_apps_json(&amp;quot;apps.json&amp;quot;)
engine = QQmlApplicationEngine()
appLauncher = AppLauncher(apps_by_tab)
engine.rootContext().setContextProperty(&amp;quot;tabsModel&amp;quot;, apps_by_tab)
engine.rootContext().setContextProperty(&amp;quot;appLauncher&amp;quot;, appLauncher)
engine.load(QUrl(&amp;quot;main.qml&amp;quot;))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
&lt;/code>&lt;/pre>
&lt;/details>
&lt;p>Wow amazing, not really. This didn&amp;rsquo;t work. First there was no apps.json file to load (simple fix as the agent to write one for me!).&lt;/p>
&lt;p>From the
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat1.md#how-to-fix" target="_blank" rel="noopener">chats&lt;/a> you can see I have a number of exchanges just pasting in errors until it fixed it for me (for this is how you vibe code!). Eventually I had a working app framework.&lt;/p>
&lt;p>&lt;img alt="app1" src="https://nccastaff.bournemouth.ac.uk/jmacey/jmacey/post/AppsEre/App1.png">&lt;/p>
&lt;h2 id="analysis">Analysis&lt;/h2>
&lt;p>The overall structure isn&amp;rsquo;t too bad and it works well, I like the fact it used the repeater in qml which really does make the code work well.&lt;/p>
&lt;p>The python code is mainly boiler plate but does have a few quirks, for example it uses mixed styles for function name etc, do real type hints or docstrings (more on this later). It does however understand PySide
&lt;a href="https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html" target="_blank" rel="noopener">Signals / Slots&lt;/a> which is fundamental to a PySide app.&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>After this I made a bit of a mistake as I started a new Chat (I&amp;rsquo;ve done this a few times) whilst not really an issue in this having the chats in bigger sections I have discovered will make it work better
&lt;a href="https://www.ibm.com/think/topics/context-window" target="_blank" rel="noopener">see here&lt;/a>. However I have also discoved adding things (just files) with no context can also give different / better result (as the agent is really only guessing!).&lt;/p>
&lt;h2 id="add-to-favourites">Add to Favourites&lt;/h2>
&lt;p>The next step was to allow right clicking on buttons to add this to the favourites tab. I used the promt&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Add an extra favourites tab and allow the user to right click and add their own apps to the favourites tab&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The Agent produced quite a lot of extra
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat1.md#user-14" target="_blank" rel="noopener">code&lt;/a>&lt;/p>
&lt;p>It broke down what to add and where to add it quite well. It also tried to explain what it was doing, but I&amp;rsquo;ve been ignoring all these explainations in true &amp;ldquo;student&amp;rdquo; fashion, so still not sure what is happening.&lt;/p>
&lt;h2 id="save-the-favourites">Save the favourites&lt;/h2>
&lt;p>This is the part where domain knowledge really comes into play. I use PySide / Qt a lot so I know it comes with a built in class called
&lt;a href="https://doc.qt.io/qt-6/qsettings.html" target="_blank" rel="noopener">QSettings&lt;/a> which provided platform specific saving and loading of settings.&lt;/p>
&lt;p>I used (now in a new
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat2.md" target="_blank" rel="noopener">chat&lt;/a>) the following prompt. (not the spelling mistakes!)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>save the favourites using QSettings as user favourites. also allow the removal of favoureites&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>As i was in a new Chat / Context I started to write me code in C++ (this is where I learnt the valuable lesson about keeping things in a bigger theread).&lt;/p>
&lt;p>You will notice from the
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat2.md#user-2" target="_blank" rel="noopener">chat&lt;/a> there is a lot of back and forth about things not working but eventually all was good. It was also at this stage I got lazy and asked it to fully re-write the qml / python files as needed. zed has a system called
&lt;a href="https://zed.dev/agentic" target="_blank" rel="noopener">agenic editing&lt;/a> but I&amp;rsquo;ve not been using it on this projects, however it will be something to explore in the future as cut / paste / insert is a bit problematic at times, which leads me to the other &amp;ldquo;big thing to use when vibing&amp;rdquo; always commit before change!&lt;/p>
&lt;p>zed has excellent github integrations so I have been using this, however I&amp;rsquo;ve been using my own commit messages for now. zed will actually generate them for you if you like (more Agent fun!).&lt;/p>
&lt;h2 id="a-search-bar">A search bar&lt;/h2>
&lt;p>Next I asked the Agent to&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>add the ability to search for an app and place the buttons matching in a view&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The agent responded with some quite useful
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat2.md#agent-5" target="_blank" rel="noopener">code&lt;/a>&lt;/p>
&lt;details>
&lt;summary>searchApps click to expand&lt;/summary>
&lt;pre>&lt;code class="language-python">@Slot(str, result='QVariantList')
def searchApps(self, query):
&amp;quot;&amp;quot;&amp;quot;Return a flat list of apps matching the query in their name.&amp;quot;&amp;quot;&amp;quot;
query = query.strip().lower()
if not query:
return []
matches = []
for tab in self._apps_by_tab:
for app in tab[&amp;quot;apps&amp;quot;]:
if query in app[&amp;quot;name&amp;quot;].lower():
matches.append(app)
return matches
&lt;/code>&lt;/pre>
&lt;/details>
And this section of the development worked very well, there was a little back and forth to correct errors and add features but in the end it worked.
&lt;h2 id="single-file-hell">Single File Hell!&lt;/h2>
&lt;p>The problem I was facing now was the QML file was getting big and becoming a bit of a pain to locate things. So I used my domain knowledge of QML and asked.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Can you partition the QML file into smaller more logical areas&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>I was quite impressed with the
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat2.md#agent-9" target="_blank" rel="noopener">result&lt;/a>&lt;/p>
&lt;pre>&lt;code>AppLauncher/
├── main.qml
├── SearchBar.qml
├── SearchResultsView.qml
├── AppGrid.qml
├── AppDelegate.qml
&lt;/code>&lt;/pre>
&lt;p>I know that PySide can use the
&lt;a href="https://doc.qt.io/archives/qt-5.15/resources.html" target="_blank" rel="noopener">Qt Resource System&lt;/a> so I asked the Agent to&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>create a qt rcc file for the qml files&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>What was nice is that it decided to re-structure the project in a sensible way.&lt;/p>
&lt;pre>&lt;code>AppLauncher/
├── main.py
├── qml/
│ ├── main.qml
│ ├── SearchBar.qml
│ ├── SearchResultsView.qml
│ ├── AppGrid.qml
│ └── AppDelegate.qml
└── resources.qrc
&lt;/code>&lt;/pre>
&lt;details>
&lt;summary>resources.qrc click to expand&lt;/summary>
&lt;pre>&lt;code class="language-xml">&amp;lt;RCC&amp;gt;
&amp;lt;qresource prefix=&amp;quot;/&amp;quot;&amp;gt;
&amp;lt;file&amp;gt;qml/main.qml&amp;lt;/file&amp;gt;
&amp;lt;file&amp;gt;qml/SearchBar.qml&amp;lt;/file&amp;gt;
&amp;lt;file&amp;gt;qml/SearchResultsView.qml&amp;lt;/file&amp;gt;
&amp;lt;file&amp;gt;qml/AppGrid.qml&amp;lt;/file&amp;gt;
&amp;lt;file&amp;gt;qml/AppDelegate.qml&amp;lt;/file&amp;gt;
&amp;lt;/qresource&amp;gt;
&amp;lt;/RCC&amp;gt;
&lt;/code>&lt;/pre>
&lt;/details>
&lt;p>It even showed me how to build the rcc file and use it.&lt;/p>
&lt;pre>&lt;code class="language-bash">pyside6-rcc resources.qrc -o resources_rc.py
&lt;/code>&lt;/pre>
&lt;p>Then, in your &lt;code>main.py&lt;/code>, import the resource module &lt;strong>before&lt;/strong> loading QML:&lt;/p>
&lt;pre>&lt;code class="language-python">import resources_rc # This registers the resources with Qt
&lt;/code>&lt;/pre>
&lt;p>And load your QML like this:&lt;/p>
&lt;pre>&lt;code class="language-python">engine.load(QUrl(&amp;quot;qrc:/qml/main.qml&amp;quot;))
&lt;/code>&lt;/pre>
&lt;h2 id="updates-to-the-json">Updates to the json&lt;/h2>
&lt;p>Next I was getting a bit annoyed with the json file as it was not really a full dictionary so I asked&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>I want it to be a proper dictionary&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>The
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat2.md#agent-12" target="_blank" rel="noopener">Agent&lt;/a> gave lots of suggestions and there was a lot of back and forth and tinkering as you can see in the linked chat.&lt;/p>
&lt;p>I also made a small diversion to write a simple GUI to allow the editing and creating of the json files but gave up on that after a while as it was quicker and easier to edit the json file myself.&lt;/p>
&lt;h2 id="wait-something-went-wrong">Wait something went wrong.&lt;/h2>
&lt;p>In the
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat3.md" target="_blank" rel="noopener">Chat3.md&lt;/a> you will see I started a new thread to try and fix a bug I had introduced in the last change. I can&amp;rsquo;t fully remember why this happend (as I was vibing) but it took a while to get the search back working. I was also not particularly good at commit as yet so going back was not really helping either! A good lesson learnt and finally everything got fixed.&lt;/p>
&lt;h2 id="i-should-really-see-how-this-works">I should really see how this works.&lt;/h2>
&lt;p>Everything was now quite a mess, I decided to start a new context
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat4.md" target="_blank" rel="noopener">Chat4.md&lt;/a> and get the Agent to re-factor the code and add comments / docstring where applicable.&lt;/p>
&lt;p>Basically for each file I attached it to the agent then added the prompt&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>document this file and tidy it up a bit&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>This actually worked quite well. But the comments are very generic and not overly useful in the larger context.&lt;/p>
&lt;details>
&lt;summary>click to expand&lt;/summary>
&lt;pre>&lt;code>import QtQuick 2.15
import QtQuick.Controls 2.15
/**
* AppDelegate.qml
*
* Represents a single application icon with its name, supporting launching and context menu actions.
* Used within an app launcher grid or list.
*/
Rectangle {
// The name of the current tab (e.g., &amp;quot;Favourites&amp;quot;, &amp;quot;All Apps&amp;quot;)
property string tabName: &amp;quot;&amp;quot;
// The app object, expected to have: name, icon, path, execName
property var app: {}
width: 90
height: 90
color: &amp;quot;#f0f0f0&amp;quot;
border.color: &amp;quot;#888&amp;quot;
radius: 8
// App icon
Image {
source: app.icon
anchors.centerIn: parent
width: 48
height: 48
}
// App name label
Text {
text: app.name
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
font.pixelSize: 14
elide: Text.ElideRight
}
// Mouse interaction area for launching and context menu
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
// Launch app on left click
onClicked: function(mouse) {
if (mouse.button === Qt.LeftButton) {
appLauncher.launch_app(app.path, app.execName);
}
}
// Show context menu on right click
onPressed: function(mouse) {
if (mouse.button === Qt.RightButton) {
contextMenu.popup();
}
}
}
// Context menu for adding/removing favourites
Menu {
id: contextMenu
MenuItem {
text: &amp;quot;Add to Favourites&amp;quot;
visible: tabName !== &amp;quot;Favourites&amp;quot;
onTriggered: appLauncher.add_to_favourites(app.name)
}
MenuItem {
text: &amp;quot;Remove from Favourites&amp;quot;
visible: tabName === &amp;quot;Favourites&amp;quot;
onTriggered: appLauncher.remove_from_favourites(app.name)
}
}
}
&lt;/code>&lt;/pre>
&lt;/details>
&lt;p>In retrospect, I need to add to the original context that all code should have appropriate comments and type hints if applicable. This would make this happen by default I hope.&lt;/p>
&lt;h2 id="chat5mdhttpsgithubcomnccaapplauncherblobmainaichatschat5md-were-vibing-now">
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/AIChats/Chat5.md" target="_blank" rel="noopener">Chat5.md&lt;/a> we&amp;rsquo;re vibing now!&lt;/h2>
&lt;p>This is my finaly chat, and where I finally got what vibe coding is. At the top of the zed window I finally see my context length displayed (currently 35K/128K) this now means I&amp;rsquo;m actually getting good results as the Agent has lots more to work with.&lt;/p>
&lt;p>I can now add / update code quite well and I do now have a full working app.&lt;/p>
&lt;video width="320" height="240" controls>
&lt;source src="https://nccastaff.bournemouth.ac.uk/jmacey/jmacey/post/AppsEre/AppsEre.mov" type="video/mp4">
&lt;/video>
&lt;h2 id="deployment">Deployment&lt;/h2>
&lt;p>I wanted to deploy the app as an executable rather than python. I already teach this so I again have domain knowledge. However I thought I would ask ChatGPT how to do it (but I gave the hint to use uv and PyInstaller).&lt;/p>
&lt;p>It gave semi correct answers (for example using pip rather than uv add) but also some totally incorrect ones. Especially adding a deploy section to the pyproject.toml&lt;/p>
&lt;pre>&lt;code>[tool.pyinstaller]
entry = &amp;quot;main.py&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>In the end I have written my own
&lt;a href="https://github.com/NCCA/AppLauncher/blob/main/deploy.sh" target="_blank" rel="noopener">deploy script &lt;/a> to make it easier to build and deploy the app. I also asked ChatGPT to create and show me how to make the app launch on startup which worked first time, and finally this.&lt;/p>
&lt;p>&lt;img src="https://nccastaff.bournemouth.ac.uk/jmacey/jmacey/post/AppsEre/Logo.png">&lt;/p>
&lt;p>This prompt was fun.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Can you create me a simple Icon for my Launcher app called AppsEre&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>Agent :-&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Sure! I can create a simple launcher icon for your app AppsEre. First, a couple of quick questions to make it more tailored:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 1. Style preference? (Flat, 3D, minimalist, playful, etc.)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 2. Color scheme? (e.g., blue tones, dark background, vibrant colors?)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 3. Symbol or motif? (e.g., letter “A”, rocket, toolbox, grid of apps, etc.)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Or would you like me to generate a default clean icon with the text A or AE inside a colored circle — a classic launcher look?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Let me know, or I’ll generate a clean default one right away.&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>
&lt;p>I chose I think it should have an ear in it, make it 3D and vibrant colour&lt;/p>
&lt;h2 id="would-i-do-this-again">Would I do this Again?&lt;/h2>
&lt;p>This was a fun project, and I will be adding Agent based coding into my work and I think there is scope to use some of this in teaching, however the code produced is not always that good.&lt;/p>
&lt;p>Main issues are&lt;/p>
&lt;ol>
&lt;li>I don&amp;rsquo;t fully know where everything is yet (as I&amp;rsquo;ve not been looking)&lt;/li>
&lt;li>It&amp;rsquo;s a little tangled and illogical in places&lt;/li>
&lt;li>Naming is hard, AI naming is terrible (my new mantra).&lt;/li>
&lt;/ol>
&lt;h2 id="what-next">What Next&lt;/h2>
&lt;p>There are a couple of features I need to add for the final version&lt;/p>
&lt;ol>
&lt;li>add a popup optional flag for the json so I can display messages when using the installers&lt;/li>
&lt;li>add optional flags to the json so I can use things like the &amp;ndash;debug flag.&lt;/li>
&lt;/ol>
&lt;p>I will vibe code this then take a snapshot, then I will re-factor the code and finally understand the structure etc, I will do this by writing it up as a project for the students to see (as we do in assignments).&lt;/p></description></item></channel></rss>