Skip to content

Commit f063ca7

Browse files
committed
Started a page with some examples for inspiration
1 parent 2ac671a commit f063ca7

File tree

6 files changed

+217
-3
lines changed

6 files changed

+217
-3
lines changed

.reuse/dep5

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ Upstream-Contact: <[email protected]>
44
Source: https://www.github.com/KDAB/KDAlgorithms
55

66
#misc source code
7-
Files: run .gitignore CMakeLists.txt CMakePresets.json README.md _clang-format .pre-commit-config.yaml appveyor.yml Documentation/* Example/CMakeLists.txt
7+
Files: run .gitignore CMakeLists.txt CMakePresets.json README.md _clang-format .pre-commit-config.yaml appveyor.yml Documentation/* Example/CMakeLists.txt Inspiration/CMakeLists.txt
88
Copyright: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
99
License: MIT

CMakeLists.txt

+9-1
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,13 @@ if(BUILD_TESTING AND ${KDALGORITHMS_BUILD_TEST})
8080
add_executable(tst_return_type_traits tests/tst_return_type_traits.cpp)
8181

8282
# Make it show up in Qt Creator
83-
add_custom_target(additional_files SOURCES README.md run Documentation/algorithms.md Documentation/deploying.md)
83+
add_custom_target(additional_files SOURCES
84+
README.md
85+
run
86+
Documentation/algorithms.md
87+
Documentation/deploying.md
88+
Documentation/inspiration.md
89+
)
90+
91+
add_subdirectory(Inspiration)
8492
endif()

Documentation/inspiration.md

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
Just for Inspiration
2+
====================
3+
This page contains a number of (well one for now) examples, where you may use algorithms to write clearer code.
4+
5+
It took me (Jesper) quite a long time before I could really appreciate usage of algorithms, and furthermore
6+
I was often struggling to find the right one to use.
7+
I was also often paralyzed when I had to chose between two solutions to the same problem:
8+
one using a relative simple for loop and one which was more complex but using algorithms.
9+
10+
Today, I have settled with the understanding that algorithms is a means to an end, not the end itself.
11+
Their primary purpose is to make the code more expressive - so instead of having to read through a for loop to understand exactly what it is building up, I can see that it for example filters out some items, and transform the result to another format.
12+
13+
14+
Traversing a list which do not provide iterators
15+
------------------------------------------------
16+
(Example in Inspiration/qlistview_all_columns_selected.cpp)
17+
18+
Sometimes you want to filter, transform, or apply any other algorithm to a *list* provided to you via an API which do *not* offer iterators, and which you therefore *can not* apply algorithms on.
19+
20+
One solution is of course to create a wrapper object providing an iterator API, but as this solution shows, another solution is to simply create a list of indexes to iterate.
21+
22+
### The Problem
23+
Imagine you want to check if all columns of a given row in a table (here QTableWidget) is selected. This looks a lot like <a href="https://github.com/KDAB/KDAlgorithms/blob/main/Documentation/algorithms.md#all_any_none">all_of</a>, doesn't it?
24+
25+
To get to the selected items, you will have to ask the table for its QItemSelectionModel, which in turn, naturally does not offer a *are all columns for a given row selected* API, nor does it offer an iterator to traverse all columns for a given row (which would have been a really weird API to begin with, if it did).
26+
27+
What the selection model does offer you is to answer yes or no to the question is a given (row, column) selected.
28+
29+
A solution often looks like this:
30+
31+
```
32+
bool allColumnsSelected = true;
33+
int row = m_table->currentRow();
34+
auto selectionModel = m_table->selectionModel();
35+
auto model = m_table->model();
36+
for (int i = 0; i < m_table->columnCount(); ++i) {
37+
if (!selectionModel->isSelected(model->index(row, i))) {
38+
allColumnsSelected = false;
39+
break;
40+
}
41+
}
42+
43+
if (allColumnsSelected)
44+
doSomething();
45+
```
46+
47+
The code is proper Qt code, and might not be super readable to you if you are not a Qt developer, but even if you are, you need to read all lines carefully to understand it. The key part in the above is the explicit for loop over all columns.
48+
49+
Here is a solution using KDAlgorithms, and more specifically **all_of**:
50+
51+
```
52+
auto columns = kdalgorithms::iota(m_table->columnCount());
53+
auto isColumnSelected = [row = m_table->currentRow(),
54+
selectionModel = m_table->selectionModel(),
55+
model = m_table->model()](int column) {
56+
return selectionModel->isSelected(model->index(row, column));
57+
};
58+
59+
if (kdalgorithms::all_of(columns, isColumnSelected))
60+
doSomething();
61+
```
62+
63+
The trick is to iterate (implicitly inside the algorithms) over the list of indexes for the columns. We do so by first fetching a list of all indexes (the variable *columns*). Following that we create a lambda expression to answer if a given column is selected, and now the test is super readable.
64+
65+
### Some after thoughts
66+
If you have that feeling that you have seen this trick before, namely creating a list of the indexes and operating on that, then chances are you occasionally write Python code. In python you often find code like:
67+
68+
```
69+
vector = [1, 2, 3, 4, 5]
70+
for i in range(len(vector)):
71+
if vector[i] % 2 == 1:
72+
vector[i] = 0
73+
```
74+

Inspiration/CMakeLists.txt

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmake_minimum_required(VERSION 3.9)
2+
project(Inspiration)
3+
4+
set(CMAKE_INCLUDE_CURRENT_DIR ON)
5+
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui)
6+
find_package(Qt${QT_VERSION_MAJOR} CONFIG REQUIRED COMPONENTS Core Gui Widgets)
7+
set(CMAKE_AUTOMOC TRUE)
8+
set(CMAKE_AUTORCC TRUE)
9+
10+
11+
add_executable(qlistview_all_columns_selected
12+
qlistview_all_columns_selected.cpp
13+
)
14+
target_link_libraries(qlistview_all_columns_selected Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/****************************************************************************
2+
**
3+
** This file is part of KDAlgorithms
4+
**
5+
** SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
6+
**
7+
** SPDX-License-Identifier: MIT
8+
**
9+
****************************************************************************/
10+
11+
#include "../src/kdalgorithms.h"
12+
#include <QApplication>
13+
#include <QDebug>
14+
#include <QLabel>
15+
#include <QTableWidget>
16+
#include <QVBoxLayout>
17+
18+
/*
19+
For details see https://github.com/KDAB/KDAlgorithms/blob/main/Documentation/inspiration.md
20+
*/
21+
class Test : public QWidget
22+
{
23+
public:
24+
Test()
25+
{
26+
auto layout = new QVBoxLayout(this);
27+
28+
m_table = new QTableWidget(5, 5);
29+
layout->addWidget(m_table);
30+
31+
m_label1 = new QLabel("Select Something");
32+
layout->addWidget(m_label1);
33+
connect(m_table, &QTableWidget::currentCellChanged, this, &Test::updateLabelV1);
34+
35+
m_label2 = new QLabel("Select Something");
36+
layout->addWidget(m_label2);
37+
connect(m_table, &QTableWidget::currentCellChanged, this, &Test::updateLabelV2);
38+
39+
m_label3 = new QLabel("Select Something");
40+
layout->addWidget(m_label3);
41+
connect(m_table, &QTableWidget::currentCellChanged, this, &Test::updateLabelV3);
42+
}
43+
44+
private:
45+
/* The normal implementation using for loops */
46+
void updateLabelV1()
47+
{
48+
bool allColumnsSelected = true;
49+
int row = m_table->currentRow();
50+
auto selectionModel = m_table->selectionModel();
51+
auto model = m_table->model();
52+
for (int i = 0; i < m_table->columnCount(); ++i) {
53+
if (!selectionModel->isSelected(model->index(row, i))) {
54+
allColumnsSelected = false;
55+
break;
56+
}
57+
}
58+
59+
if (allColumnsSelected)
60+
m_label1->setText("All columns selected");
61+
else
62+
m_label1->setText("Not all columns selected");
63+
}
64+
65+
/* The improved version using algorithms */
66+
void updateLabelV2()
67+
{
68+
auto columns = kdalgorithms::iota(m_table->columnCount());
69+
auto isColumnSelected = [row = m_table->currentRow(),
70+
selectionModel = m_table->selectionModel(),
71+
model = m_table->model()](int column) {
72+
return selectionModel->isSelected(model->index(row, column));
73+
};
74+
75+
if (kdalgorithms::all_of(columns, isColumnSelected))
76+
m_label2->setText("All columns selected");
77+
else
78+
m_label2->setText("Not all columns selected");
79+
}
80+
81+
/* The version I would have written without algorithms */
82+
void updateLabelV3()
83+
{
84+
bool allColumnsSelected = [this] {
85+
int row = m_table->currentRow();
86+
auto selectionModel = m_table->selectionModel();
87+
auto model = m_table->model();
88+
for (int i = 0; i < m_table->columnCount(); ++i) {
89+
if (!selectionModel->isSelected(model->index(row, i))) {
90+
return false;
91+
}
92+
}
93+
return true;
94+
}();
95+
96+
if (allColumnsSelected)
97+
m_label3->setText("All columns selected");
98+
else
99+
m_label3->setText("Not all columns selected");
100+
}
101+
102+
QTableWidget *m_table;
103+
QLabel *m_label1;
104+
QLabel *m_label2;
105+
QLabel *m_label3;
106+
};
107+
108+
int main(int argc, char **argv)
109+
{
110+
QApplication app(argc, argv);
111+
112+
Test test;
113+
test.resize(600, 300);
114+
test.show();
115+
app.exec();
116+
}

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ The purpose of this library is to make it easier to work with algorithms in C++1
55

66
* <a href="Documentation/algorithms.md">Documentation of all the algorithms</a>
77
* <a href="Documentation/deploying.md">Deploying the algorithms with CMake</a>
8-
* <a href="tests/tst_kdalgorithms.cpp">Be inspired by all the unit tests</a>
8+
* <a href="Documentation/inspiration.md">Get inspired by some real world examples</a>
9+
* <a href="tests/tst_kdalgorithms.cpp">Get inspired by all the unit tests</a>
910
* <a href="https://youtu.be/iAEIPk64ZJw?list=PL6CJYn40gN6gf-G-o6syFwGrtq3kItEqI">Youtube video introducing the library</a>
11+
* <a href="https://www.kdab.com/introducing-kdalgorithms">A blog post on KDAlgorithms</a>
1012

1113
Example - filtered
1214
------------------

0 commit comments

Comments
 (0)