Why Qt for C++ is STILL the truth: F the noise

Thabo David Klass
6 min readSep 5, 2017

--

Nowadays, when you speak about desktop development, people look at you like you're some kind of Luddite. Despite the hype with mobile, the honest truth is that the most productive and complex work is still being done on desktop (or through browsers that run on desktop).

I love Java, Swift and them, but when it comes to building desktop applications, C++ in tandem Qt is still the best. Here are a few reasons I'm still a Qt junkie in 2017:

Easy

Qt with C++ is just easy to use. The only other development environment that is comparable is XCode. With tons of great examples at startup, it doesn't take long to get your feet wet. I know that the appeal of being a coder is dealing with the kind of complexity that "mere mortals" can barely wrap their heads around, but I am also a big fan of simplifying rudimentary tasks like UI building so that it becomes an art instead of it being comparable to solving a complex mathematical problem. Coming from a Java Swing and PyGTK background, Qt was heaven for me.

Qt Creator running on macOS Sierra

Fast. Very fast.

It's common knowledge that C++ is a very fast language and I believe Qt has leveraged some of that speed. Comparing the development and interactions with software that I have built in the past, Qt always felt a bit more nimble (I haven't done any benchmarks so I could be wrong). Even today, when I spend most of my days on XCode, I still can't help but marvel at the speed and lightness of Qt. This of course may be based on my internal biases and limitations as a coder. Below is a snippet of a crude GUI based merge-sort I did a LONG time ago. Worked like a charm and was noticeable crisper than Java when given a large data set. You can try it out yourself.

// MergeSort.cpp
// Class MergeSort member-function definition.
#include <vector>
using std::vector;
#include “merge_sort_budget.h” // class MergeSoft definition/**
The constructor for the MergeSort class.

@param btList btList the budget tab list.
*/
MergeSortBudget::MergeSortBudget(BudgetTabList btList)
{
size = btList.size(); //validate vectorSize
// fill the vector with random BudgetTabItems with different dates
for (int i = 0; i < btList.size(); i++)
{
data.push_back(btList.at(i));
}
} // end MergeSort constructor
///**
Split vector, sort subvectors and merge subvectors into sorted vector

@param btList the budget tab list.
@return nothing.
*/
void MergeSortBudget::sort(BudgetTabList btList)
{
sortSubVector(0, size — 1, btList); // recursively sort entire vector
} // end function sort
/**
Recursive function to sort subvectors

@param low the low tab.
@param high the high tab.
@param btList the budget tab list.
@return nothing.
*/
void MergeSortBudget::sortSubVector(int low, int high, BudgetTabList btList)
{
// test base case; size of vector equals 1
if ((high — low) >= 1) // if not base case
{
int middle1 = (low + high) / 2; // calculate middle of vector
int middle2 = middle1 + 1; // calculate next element over
// split vector in half; sort each half (recursive calls)
sortSubVector(low, middle1, btList); // first half of vector
sortSubVector(middle2, high, btList); // second half of vector
// merge two sorted vectors after split calls return
merge(low, middle1, middle2, high, btList);
} // end if
} // end function sortSubVector
/**
Merge two sorted subvectors into one sorted subvector

@param left the left.
@param middle1 the high tab.
@param middle2 the high tab.
@param right the high tab.
@param btList the budget tab list.
@return nothing.
*/
void MergeSortBudget::merge(int left, int middle1, int middle2, int right, BudgetTabList btList)
{
int leftIndex = left; // index into left subvector
int rightIndex = middle2; // index into right subvector
int combinedIndex = left; // index into temporary working vector
vector<BudgetTabItem> combined; // working vector
for (int i = 0; i < size; i++)
combined.push_back(BudgetTabItem(“”, 0, 0, 0));
// merge vectors until reaching end of either
while (leftIndex <= middle1 && rightIndex <= right)
{
// place smaller of current elements into result
// and move to next space in vector
if ((data[leftIndex].getYear() >= data[rightIndex].getYear()
&& data[leftIndex].getMonth() > data[rightIndex].getMonth()) ||
(data[leftIndex].getYear() > data[rightIndex].getYear()
&& data[leftIndex].getMonth() >= data[rightIndex].getMonth()) ||
(data[leftIndex].getYear() > data[rightIndex].getYear()
&& data[leftIndex].getMonth() < data[rightIndex].getMonth()))
combined[combinedIndex++] = data[leftIndex++];
else
combined[combinedIndex++] = data[rightIndex++];
} // end while
if (leftIndex == middle2) // if at end of left vector
{
while (rightIndex <= right) //copy in rest of right vector
combined[combinedIndex++] = data[rightIndex++];
} // end if
else // at end of right vector
{
while (leftIndex <= middle1) // copy in rest of left vector
combined[combinedIndex++] = data[leftIndex++];
} // end else
// copy values back into original vector
for (int i = left; i <= right; i++)
{
BudgetTabItem item = combined[i];
item.setTabIndex(i);
data[i] = item;
}
} // end function merge
/**
Display elements in vector

@param none.
@return nothing.
*/
void MergeSortBudget::displayElements() const
{
displaySubVector(0, size — 1);
} // end function displatElements
/**
Display certain values in vector

@param none.
@return nothing.
*/
void MergeSortBudget::displaySubVector(int low, int high) const
{
// output spaces for alignment
for (int i = 0; i < low; i++)
//cout << “ “;
// output elements left in vector
for (int i = low; i <= high; i++)
{
BudgetTabItem item = data[i];
}
} // end function displatSubVector
/**
Gets the sorted index.

@param month. the month of the tab.
@param year. the year of tab.
@return sortedIndex
*/
int MergeSortBudget::getSortedTabIndex(int month, int year)
{
int sortedIndex;
for (int i = 0; i < size; i++)
{
if ((data[i].getYear() == year) && (data[i].getMonth() == month))
{
sortedIndex = data[i].getTabIndex();
}
}
return sortedIndex;
}

Platform agnostic

There's been a lot of emphasis on being platform agnostic in mobile development and a lot of tools have been built with that in mind. Qt did it a LONG time ago on desktop and did it in a big way. Porting your apps to different platforms doesn't feel like hard work. They run the same on every OS/platform with little to no porting.

CakeHeap Budget Professional running on macOS

Snapping out of the current zeitgeist

Apps. Apps. Apps! Mobile apps! "Hey dude, can you build me an app bro?", said the old college buddy. Lately, it feels like ubiquity is associated with mobile and mobile with success. Maybe that's true. It can also be as exhausting as listening to the mainstream media constantly harp on AI. Maybe this is just me getting sentimental but Qt has the feel of authentic and real-world programming — a coding culture that isn't based on hype or the latest hot thing. It's advanced but primal. It's comprehensive but not closed. It feels real. It feels true. It doesn't feel StackOverflow-y. I recently saw a cool WIRED documentary about the startup scene in Israel. The documentary made me feel the same way I felt when I first started tinkering with Qt —like I was part of something true. Check it out below:

There's an entire generation of coders that might make the tragic mistake of ignoring desktop and Qt (with C++). It would hurt them, not just in terms of history but also in terms of making them whole and broad. There is a whole big world of computer science out there: the hyped-up fields being AI and data science at the moment. In all likelihood, I'll be working with both on a full-time basis within the next six months. That being said, nothing beats the intimacy of building something from scratch with something like Qt — it's a pleasure that no coder should deny themselves.

I am Thabo Klass and I work at Spreebie. Cheers.

--

--