This is not a tutorial, guide, or howto. This is a detailed, near real-time log of a journey learning a new set or tools in programming. I usually keep (admittedly less detailed) notes whenever I start something new. I like to record any assumed knowledge or stumbling blocks. If I see something I like but don’t have time to pursue, I make a note of that. This time, I decided to get more detailed and publish my progress.
I wanted to learn making a cross-platform desktop/mobile gui. I have an idea for an application in mind that is an offline-first, private journal which works like a microblogging/twitter client, complete with tags, key-value pairs, advanced search, and a report builder. Log small things like “kid lost his second tooth today” or “purchased #oil gallons:200 cost:$800”. This would be super easy for me as a web application or command line tool, but I want this on my laptop and my phone, and I don’t want to rely on a network connection. All my prior work has been backend server or web application. While a lot of people are approaching this by making a webapp and then packaging that in someting like electron, I eventually decided to give Qt (pronounced “cute”) + Go a try. I admit this is probably like playing on hard mode because I have to learn two things at once, also not many people are making GUIs in Go. It would probably be easier to learn Qt + Python, since I’m already well versed in Python. But my goal is to be able to create no-dependency binaries for each platform I’m targeting.
It starts with Qt. I have never worked with Qt before, and I’ve never made a GUI before. Qt is nice in that it’s got a large amount of tutorials and working examples you can put together without actually needing the underlying logic code. Qt has some negatives like being expensive for commercial distribution ($500/month). The commercial trial is only 30 days. This is way too much for learning or hobby applications. The free version requires you to distribute the application separately from the Qt shared libraries. You can’t legally make a single binary for distribution and distributing the shared libraries adds a bit of complexity to deployment. That said, it has some positives. First off, if you are planning to sell your app, the price is manageable. Ten copies of your $5 application per month, or any combination of applications or subscriptions that nets you $6000/year to break even on Qt licensing. Even without going commercial, there are a number of guides on how to distribute or wrap your application to handle shared libraries. Once you manage to get past concerns about distributing your application (which you haven’t even started writing yet), then the other benefits of Qt really come into play. Qt has lots of support, documentation, an activite community, lean, and compiles down to just about every platform out there. It works on Windows, Mac, Linux, Androis, and iOS. You can spend weeks, months, years developing your application, letting people test it out and give feedback, you can even sell it (as long as you follow the LGPL requirements for Qt), and do all that for free. If you get to the point where you
During install, the first thing that confused me was a lack of default options. While it will install the QT Creator, you get no components with it. Nothing is checked. I am so used to installers selecting the most useful or commonc components that I had to run through the installer more than once. When installing, expand the Qt section and select the latest non-preview version of Qt (Qt 5.12.2 currently). I selected all in that version. Unless you’re working with older Qt, I don’t think there’s any need to select older versions of it.
Once installed, I went ahead and launched Qt Creator and brought up the qtwidgets notepad tutorial. I went ahead and setup version control.These tutorials will create cpp code. I’ll follow the tutorial with that, then I’ll eventually circle back and work on a Go program to do the same thing. The wysiwyg editor creates a .ui
file, which can be loaded up in therecipe/qt Qt Go bindings. I’m starting with widgets, but using Quick/QML is also of high interest to me, especially if I venture into mobile.
Things went fine. I opened the mainwindow.ui, added a text edit widget, and saved it. But in the tutorial, when they get to the mainwindow.h file, their example showed basically the file I had, plus a lot of “private slots” with interesting names like newDocument, open, save. Mine had nothing like that.
private slots:
void newDocument();
void open();
void save();
The entirety of my file was like this:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
At this point, I’m already a bit frustrated as it seems the tutorial author took a step more than what’s in the tutorial. All sorts of entries related to files and fonts show up in their example, but not on mine. Then I went back through and found that even my main.cpp was different.
This is what the tutorial says I should have link:
#include "notepad.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication EditorApp(argc, argv);
Notepad Editor;
Editor.show();
return EditorApp.exec();
}
This is what I have:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I went back through, recreating the project and realized I hadn’t set the class name to Notepad (defaulted to MainWindow), and my new main.cpp but my new files came out exactly the same, just with references to mainwindow replaced with notepad. So right off the bat, I’m getting less code than the tutorial author is starting out with. Where does this Editor.show() and EdditorApp.exec() come from? Logically, the generated Notepad w
and w.show();
is equivalent to Notepad Editor;
and Editor.show();
. The author edited this file and neglected to tell us. It’s not a problem codewise, but it causes confusion. Especially when I’m later seeing all the extra stuff in notepad.h. Did the author add that as well or did I miss a step? Well, as it turns out, if you ignore the author writing “the wizard generated this file” and read all the way to the bottom of the tutorial to user interactions, you see him start adding these methods we saw in private slots.
This is super annoying. I’m going to rant about it for a couple paragraphs because I spent so much time just going up down the tutorial to figure this out. I’m not just being nitpicky about a formatting error or a typo, but this is something that stopped the learning process while I had to work through what happened. Maybe other people just download the completed project files and then read the tutorial, but I really wanted to go through the steps. If you want to tell me that the wizard generated this file, you should clarify that you are referring to yourself as wizard, and you mean sometime in the future, not at the current step of the tutorial that you are currently on. I’m spending my Saturday going through your tutorial so I can learn about your product. You want me to spend $500/month on your product, based on how great your documentation and support is. Document your process and try to keep it in chronological order.
For now, I will go ahead and edit my main.cpp to match the author’s. I’m going to ignore the missing parts of my notepad.h file because I have to guess that at some point in the tutorial, it will start to match up. I’m also going to have to ignore the fact that “The source file that the wizard generated for the Notepad class looks as follows” which I count at 161 lines, while mine is 14 lines long. Going to their final version of notepad.cpp, that balloons to 253 lines, so it seems that they used a version from somewhere halfway through.
To get away from my negativity, the tutorial does explain what each line does. I do like that. Each bit of code contains a link to the reference page for any functions listed, so you can fully read up on what everything does.
Now, as I read through the parts explaining notepad.cpp, we get to a line where we type stuff. “In order to have the text edit field occupy the whole screen, we add setCentralWidget to the main window.”. Sure enough, there’s a block of code that we can add after line 8 in our file (“ui->setupUi(this);”). This code was already in the example above, but at least now we know where to add stuff and can hopefully start following along again.
Or so I thought. But I do see that the next section of adding user interaction should define those missing pieces.
The next part is in the WYSIWYG editor. You click on the words “Type Here” and then type in what you want the menu item to be (New, Open, Save, Save as, Print and Exit). Hit enter after each entry to save it and create a new “Type Here” box.
The instructions read:
Click on “Type Here”, and add the options New, Open, Save, Save as, Print and Exit. This creates 5 lines in the Action Editor below. To connect the actions to slots, right-click an action and select Go to slot > triggered(), and complete the code for that given slot.
I would expect typing a new item to create an action item below, but that didn’t happen for me.
However, if I go down to Action Editor and click the new icon, I can create an action. I deleted “New” from the menu above, and created an action called New in the Action Editor. Then I can right-click on it and do slot-> triggered().
Adding this actionNew clears up one of my editor errors. I also have to go into notepad.h and add a QString currentFile;
under private:
. There’s a solid hope that as we go along, we’ll define all the missing pieces and the errors will go away. I don’t see any instructions, but I had to go into notepad.h and under private slots:
, add void newDocument();
.
At this point, I’m not seeing anywhere the author adds to notepad.h. I’ve tried doing running Build All in the UI designer, but that never changes notepad.h. Now that I’ve added actions, I’m getting all sorts of errors and can’t build. I’m going to kill this project and start over.