How do I learn to program on Poli

Learn to program with Qt

← Home With these instructions (tutorial) you will learn how to program computers in the C ++ language with the Qt framework.

motivation

Why does the world need programmers?

Try saying "Roast me a stork!" To some language assistant. to command. While three assistants provide completely inappropriate answers, Siri simply does not react at all (as of Feb. 2020). However, all three can answer questions about the weather report very well. How come

The crux of the matter is that computers can only answer the questions that have been programmed into them. They can't do anything with unexpected inquiries, because computers are not creative. That is why it will probably be a long time before autonomous cars without drivers are allowed on the streets.

On the other hand, our computers work with mathematical precision, quickly and tirelessly. They do boring work for us and they entertain us. We are so into these little helpers that there are already toothbrushes and saucepans with an internet connection.

To develop all of these machines, good responsible programmers are constantly sought after all over the world. Have programmers Fun at workbecause they create something meaningful. Besides, they will well paid.

Work equipment

Programming language C ++

Programs consist of a large set of numerical instructions that are executed by the CPU (the "brain" of the computer):
1037000 7878 3131 3231 6162 6973 5f63 7473 6972 1037020 676e 7749 7453 3131 6863 7261 745f 6172 1037040 7469 4973 4577 6153 7749 4545 4c70 5245 1037060 534b 5f34 5f00 4e5a 3031 5351 7274 6e69 534a520 534a574 64e5a561 374a520 534a574 534e561 374a520 534a574 534a520 534a574 534a520 5f5f 7863 3178 3131 1037140 6232 7361 6369 735f 7274 6e69 4967 7344 1037 160 7453 3131 6863 7261 745f 6172 7469 4973 1037200 7344 5345 4961 7344 4545 5f39 5f4d 756d 1037220 6174 6574 67d573 6e69d 444b220 6174 6574 6d45 50637d 537ef3 6174 6574 67d573 6e69 4967 7344 69d573 6d45 737d 444b231 69d573 6e69 4967 7344 1037160 6d45 50637d 444b2b2 69d573 6d45 50637d 537ef3 68d573 6e69 4967 7344 1037160 ..

Such a "matrix" can only be read by heroes from fantasy films. That's why programmers write their instructions in a programming language that both machine and human can understand:

if (age <16) {showMessage ("You are not allowed to use Whatsapp yet"); } else {registerAccount (username, password); }

This text is called Source code. One of the tools of the programmer is a Compilerwhich translates such source texts into numerical machine code.

In this guide you will get to know the programming language C ++. The strength of this programming language is that it is available on all platforms: from tiny 8-bit microcontrollers to mainframe computers.

Qt framework

Since programmers are given similar tasks over and over again, they began to build so-called frameworks in the 1990s. These are very extensive collections of useful building blocks from which programs can be put together. One example is the printer dialog, which is used again in numerous programs:

Each framework has its own variant here.

Qt is such a framework. A very special aspect of Qt is that it is platform-independent. With Qt you can write programs for numerous operating systems, for example: Windows, Linux, macOS*. I think the concept of Qt is sustainable.

*) Theoretically, Qt is also suitable for smartphones, according to the idea of ​​"one app for everyone". Unfortunately, both Google and Apple stopped supporting this technology in the very year it started to work properly. Apparently both manufacturers want to force the use of their own development tools. C ++ developers feel this clearly - starting with version conflicts between the tools, to missing functions and approval for the App Store.

Development environment

Before you can program your computer, you have to install a development environment (English abbreviation: IDE). Download the online installer from the Qt Creator development environment.

Installation on Windows

On Windows you get an .exe file when you download it, which you can start directly.

If the installation program does not start and reports that a DLL file with "140" in the name is missing, then install the "C ++ Redistributable for Visual Studio 2015" package from Microsoft, both versions for x64 and x86.

The first thing the installation program will ask you to do is to create a "Qt Account", without which you will not get any further. Then you have to accept the terms of the contract. Finally you come to the selection of the Qt components. The standard installation includes

  • Qt Creator
  • a current version of the Qt libraries for desktop MinGW 64-bit
  • MinGW 64-bit compiler
  • Debugger tools
You don't need any more. Bring the installation to the end, then you can start the Qt Creator development environment.

Installation on Linux

On Linux you get a .run file when you download it, which you have to mark as executable in the file manager (with the right mouse button, then properties) before you can start it.

The first thing the installation program will ask you to do is to create a "Qt Account", without which you will not get any further. Then you have to accept the terms of the contract. Finally you come to the selection of the Qt components. The standard installation includes

  • Qt Creator
  • a current version of the Qt libraries for desktop gcc 64-bit

In addition, you have to install the following from your Linux distribution:

  • GNU C ++ compiler
  • GNU debugger
  • the developer version of the OpenGL API
This can be done with the following command in the terminal window:
Debian, Ubuntusudo apt install build-essential gdb libgl1-mesa-dev
Fedora, RedHat, CentOSsudo yum groupinstall "C Development Tools and Libraries"
sudo yum install mesa-libGL-devel
openSUSEsudo zypper install -t pattern devel_basis

You can now start the Qt Creator development environment.

introduction

I think the best way to get to know a programming language is to use it. If you don't fully understand my explanations yet, don't worry. Understanding comes with time. First of all, it is only important that you get the examples up and running on your computer.

Hello World!

An old tradition says that the first program "Hello world!" should display.

To write such a program, go to the File / New ... menu in the development environment.

Set in this dialog that you want to create a "Qt console application". The term console refers to the window shown above, which is intended for text-based input and output. It's called a console or terminal window.

Another dialog appears where you should give your project a name and specify the folder in which the project should be saved.

Then click on "next" a few times until the text editor for the source text appears.

Replace the source text given there with the following, exactly like this, with all the strange special characters:

#include int main () {QTextStream out (stdout); out << "Hello world!" << Qt :: endl; QTextStream in (stdin); in.readLine (); }
Then click on the green triangle in the lower left to run the program. The result should look something like this:

If the output appears in the IDE in the "Application output" area instead, go to "Projects" on the left. There you can check the box for "Execute in Terminal" under "Execute". Then go back to "Edit" on the left to get back to the previous view.

The first line in the source code

#include
tells the compiler to insert the contents of the named text file here. This is located somewhere in the Qt installation directory. There is a corresponding file for each component of the framework.

The QTextStream component provides functions for outputting and reading text. In technical terminology, such components are called classes.

Your hello world! The program uses two objects from the QTextStream class:

QTextStream out(stdout); out << "Hello world!" << Qt :: endl; QTextStream in(stdin); in.readLine ();
The upper object has the arbitrarily chosen name "out" and is used to output the text "Hello world!" used.

The lower object has the name "in" and is used to read a line. Really? Try it!

If you have closed the program window in the meantime, start it again. You see the text "Hello world!" and a blinking cursor. The cursor signals that the program is waiting for an input. Try typing something:

Aha, the computer actually responded to the input. The message "Press the key to close the window ..." does not come from your program, but from the development environment. It was added as a comfort factor so that the window does not close by itself. Your program has already ended at this point.

Your program needs two individual objects from the QTextStream class because they are initialized with different parameters - the marked parts:

QTextStream out (stdout); out << "Hello world!" << Qt :: endl; QTextStream in (stdin); in.readLine ();
The upper object is initialized with the "stdout" channel. This channel is provided by your operating system so that the program can output text. The lower object is initialized with the "stdin" channel, which your operating system also provides. Your keyboard is connected to this channel.

Try changing the output text. Make sure you only change the text inside the double quotes. For example:

QTextStream out (stdout); out << "Jo, we can do it!"<< Qt :: endl;
The operator << pushes the specified text into the object "out". Since this object is connected to the "stdout" channel, which in turn is connected to your terminal window, the text ultimately appears in the terminal window.

After the text has been output, "Qt :: endl" is added. This special keyword triggers a line break. The blinking cursor goes down to the next line.

Console application

In this chapter we take a look under the "hood" what a C ++ program looks like. You will also get to know parts of the Qt framework. We start very simply.

Output and import text

Copy the following program into the text editor of the development environment:
#include / * This program shows something on the screen. * / int main () {QTextStream out (stdout); out << "The police" << Qt :: endl << "your friend" << Qt :: endl << "and helpers"; QTextStream in (stdin); in.readLine (); // wait for input}

The source code contains comments from the programmer that the compiler ignores. Multi-line comments begin with / * and end with * /. Single line comments begin with //.

However, the output does not correspond to the expectation:

The last line is missing because there is no "Qt :: endl" for the final line break in the source text. Text output is always held back until a line break or a "flush" occurs. Try both ("Qt :: endl" and "Qt :: flush") to see the difference.

Here is an example with flush:

#include int main () {QTextStream out (stdout); out << "The police" << Qt :: endl << "your friend" << Qt :: endl << "and helpers" << Qt :: flush; QTextStream in (stdin); in.readLine (); }
This is what the output looks like:

You can see that the blinking cursor has stopped after the third line instead of jumping to the next line. This makes sense, for example, in such a case:

#include int main () {QTextStream out (stdout); out << "Name:" << flush; QTextStream in (stdin); QString input = in.readLine (); out << "Thank you" << input << "." << Qt :: endl; }
The output looks like this:

You can now enter your name there:

On this occasion I gave you an example of how the input from stdin can be processed further.

QTextStream in (stdin); QString input = in.readLine ();
The in.readLine () method is used to read a line from the input channel (read line). The result of this method is stored in a variable that I arbitrarily named "input". This variable stores an object of the QString class, which is simply a text.

Or read the other way around from left to right: There is a variable from the QString class with the name "input", and it is filled with the result of the in.readLine () method.

A variable is a placeholder for some kind of data, like the "X" in math formulas. In the C ++ programming language, each variable always has a defined type that defines exactly what can be stored in it. In this case it is a string.

Look at the last line:

out << "Thank you" << input << "." << Qt :: endl;
There I inserted the variable "input" into the output text. That is why the character string from the variable "input" is displayed here.

Now we only have one line left that was not explained - a block to be precise:

This is simply the function that your operating system performs when the program starts - the so-called entry point. Your program can contain many functions, but the one with the specified name main () will start automatically.

The commands (= instructions) that are to be executed are written between the curly brackets.

It is specified that the main () function must supply a return value as an integer number. These are positive or negative numbers with no decimal places. Some programs use the return value to report errors:

int main () {... return 99; }
Only the number 0 has a fixed meaning, namely "Everything OK". For all other numbers, the programmer can think of what they should mean. If you omit the "return" statement, a 0 is automatically returned.

You have to write strings between quotation marks. Numbers are written without quotation marks.

Make sure that your numbers don't start with a leading 0, otherwise the compiler will interpret this as an octal number.

Your first own function

In this section, I'll show you what functions are good for.

Change the "Hello world!" Program in such a way that it displays the name, date of birth, school class and phone number of three students on the screen.

Before reading any further, try to solve the problem on your own. You already know the necessary commands. The result should look like this:

Then compare your approach with mine:

#include int main () {QTextStream out (stdout); out << "Name: Lisa Lob" << Qt :: endl; out << "Date of birth: 05/01/2007" << Qt :: endl; out << "Class: 8a" << Qt :: endl; out << "Call number: 0211/1234567" << Qt :: endl; out << Qt :: endl; out << "Name: Hanna Kornblut" << Qt :: endl; out << "Date of birth: 08/12/2007" << Qt :: endl; out << "class: 8b" << Qt :: endl; out << "Call number: 0211/234567" << Qt :: endl; out << Qt :: endl; out << "Name: Max Robinson" << Qt :: endl; out << "Date of birth: 11/20/2006" << Qt :: endl; out << "Class: 8a" << Qt :: endl; out << "Call number: 0211/345678" << Qt :: endl; out << Qt :: endl; }
Your approach may well look a little different. As long as it works, that's fine. In programming, there are always several ways to get a job done. It never hurts to discuss different solutions with other programmers.

If you continue this for the whole school, you will think you will be a wolf. The repeated input of the labels would be particularly questionable. Can't your computer automate this? Sure, you just have to program it.

That brings us to the concept of functions. A function is a piece of reusable program code. I'll show you an example:

#include static QTextStream out (stdout); // Output function: output void (QString name, QString date of birth, QString school class, QString call number) {out << "Name:" << name << Qt :: endl; out << "date of birth:" << date of birth << Qt :: endl; out << "class:" << school class << Qt :: endl; out << "phone number:" << phone number << Qt :: endl; out << Qt :: endl; } int main () {output ("Lisa Lob", "01.05.2007", "8a", "0211/1234567"); output ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); output ("Max Robinson", "11/20/2006", "8a", "0211/345678"); }
That can be expanded much better for the whole school. The output function () saves you a lot of typing.

The first line of the function defines a list of parameters that are passed to the function from outside and then used within the function. Each parameter has a specific type (in this case QString) and a name that you can think of yourself. Output () is called three times in the main () function, but each time with different values ​​for the parameters.

I have taken the liberty of designing the source text clearly by indenting it with spaces. These additional spaces have no meaning for the C ++ compiler. In theory, you could even write the entire program on a single line, but I strongly advise against that. Source texts should be designed as clearly as possible so that they can be read easily.

Output to the left of the function name () is the strange word "void". It means that this function has no return value. Below we will write functions with a return value.

Notice that I moved the "out" object further up. If "out" were still inside main (), it could only be used inside the main () function. But now it is outside the main () function and can therefore be reached for both functions.

The keyword "static" tells the C ++ compiler that this object should only be accessible in this one source text file. Larger programs consist of many files, so this limitation can be helpful to avoid conflicts with objects with the same name. Accordingly, the IDE displays a message if you omit the word "static". Try it.

The object-oriented concept

C ++ is an object-oriented programming language. Objects combine functions and the associated data into one unit. This concept is very helpful for organizing large programs.

The photo shows three students in a library. In computer science one would say: we have three objects from the "pupil" class. We also see many objects from the "Book" class in the background.

The following C ++ class describes the properties of a student that are relevant for our program. Below that, three student objects with individual properties are created:

#include static QTextStream out (stdout); class Student {public: // Properties: QString name; QString date of birth; QString school class; QString phone number; // Function: output void () {out << "Name:" << name << Qt :: endl; out << "date of birth:" << date of birth << Qt :: endl; out << "class:" << school class << Qt :: endl; out << "phone number:" << phone number << Qt :: endl; out << Qt :: endl; }}; int main () {student a; a.name = "Lisa Praise"; a.date of birth = "05/01/2007"; a.schulklasse = "8a"; a.rufnummer = "0211/1234567"; Student b; b.name = "Hanna Kornblut"; b.date of birth = "08/12/2007"; b.schulklasse = "8b"; b.call number = "0211/234567"; Student c; c.name = "Max Robinson"; c. date of birth = "11/20/2006"; c.schulklasse = "8a"; c.call number = "0211/345678"; a.output (); b.output (); c.output (); }
Try the program. The output on the screen looks exactly as before.

The C ++ class "Student" defines which properties and functions a student can have:

class Student {public: // Properties: QString name; QString date of birth; QString school class; QString phone number; // Function: output void () {...}};
but without defining specific values.

The keyword "public" specifies that the things below should be visible outside of the C ++ class.

Several objects are created from this class, which receive specific individual property values:

int main () {student a; a.name = "Lisa Praise"; a.date of birth = "05/01/2007"; a.schulklasse = "8a"; a.rufnummer = "0211/1234567"; Student b; b.name = "Hanna Kornblut"; b.date of birth = "08/12/2007"; b.schulklasse = "8b"; b.call number = "0211/234567"; Student c; c.name = "Max Robinson"; c. date of birth = "11/20/2006"; c.schulklasse = "8a"; c.call number = "0211/345678"; ...}

The three student objects output themselves to the screen when their output () method is called:

int main () {... a.output (); b.output (); c.output (); }

Classes define the properties of objects without specific values. Then you create objects of the class that have individual property values. Then you can use the functions of the objects to do something with the values.

That is the basic principle of object-oriented programming.

The functions of classes are called "methods" in technical terms.

Construct objects

Now the main () function is much longer than before. Does it have to be like that? Of course not. You can also create the student objects with compact one-liner. To do this, you have to add a constructor to the C ++ class. Constructors create objects and set their initial properties.

It works like this:

#include static QTextStream out (stdout); // saves a student's data class Student {public: QString name; QString date of birth; QString school class; QString phone number; Student (QString n, QString g, QString k, QString r) {name = n; date of birth = g; school class = k; phone number = r; } print void () {out << "Name:" << name << Qt :: endl; out << "date of birth:" << date of birth << Qt :: endl; out << "class:" << school class << Qt :: endl; out << "phone number:" << phone number << Qt :: endl; out << Qt :: endl; }}; int main () { Schueler a ("Lisa Lob", "05/01/2007", "8a", "0211/1234567"); Schueler b ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); Schueler c ("Max Robinson", "11/20/2006", "8a", "0211/345678"); a.output (); b.output (); c.output (); }
The main () function can now use the constructor of the C ++ class to create student objects and at the same time to initialize them with concrete data.

Constructors look a lot like methods. But they have to have the same name as the C ++ class and they have no return value - not even void.

The output has not changed:

How do you like the names of the parameters (n, g, k, and r) of the constructor ?:

Student (QString n, QString g, QString k, QString r) {name = n; date of birth = g; school class = k; phone number = r; }

They are not meaningful. We should improve that very quickly. But you cannot just write them out completely, because otherwise expressions like "name = name" would result, which would not be clear enough for the C ++ compiler. Which name is then the target and which is the source? One does not know.

The keyword "this" solves this problem:

#include static QTextStream out (stdout); // saves a student's data class Student {public: QString name; QString date of birth; QString school class; QString phone number; Student (QString name, QString date of birth, QString school class, QString phone number) { this->name = name; this->date of birth = date of birth; this->school class = school class; this->phone number = phone number; } print void () {out << "Name:" << name << Qt :: endl; out << "date of birth:" << date of birth << Qt :: endl; out << "class:" << school class << Qt :: endl; out << "phone number:" << phone number << Qt :: endl; out << Qt :: endl; }}; int main () {student a ("Lisa Lob", "05/01/2007", "8a", "0211/1234567"); Schueler b ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); Schueler c ("Max Robinson", "11/20/2006", "8a", "0211/345678"); a.output (); b.output (); c.output (); }
The lines with the "this" mean something like:
  • Fill in the name of this student with the name from the parameter list.
  • Fill in the date of birth of this student with the date of birth from the parameter list.
  • Fill the school class of this student with the school class from the parameter list.
  • Fill in the phone number of this student with the phone number from the parameter list.

Flexible output

The C ++ class would be a bit more flexible if it weren't forcibly writing its output on the screen. What if you want to write the output to a text file, for example? For this purpose we add a parameter to the method output (), which determines where the output is to be written.

Later we will take advantage of this to output the text somewhere else - namely to a file.

#include static QTextStream out (stdout); // saves a student's data class Student {public: QString name; QString date of birth; QString school class; QString phone number; Student (QString name, QString date of birth, QString school class, QString call number) {this-> name = name; this-> date of birth = date of birth; this-> school class = school class; this-> call number = call number; } print void (QTextStream & where to) { where << "Name:" << name << Qt :: endl; where << "Date of birth:" << Date of birth << Qt :: endl; where << "class:" << school class << Qt :: endl; where << "Call number:" << Call number << Qt :: endl; where << Qt :: endl; }}; int main () {student a ("Lisa Lob", "05/01/2007", "8a", "0211/1234567"); Schueler b ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); Schueler c ("Max Robinson", "11/20/2006", "8a", "0211/345678"); a.output (out); b.output (out); c. output (out); }
The method output () now has a new parameter with which its caller can determine where the output is to be written.

Output to a file

The next task is: Rewrite the program so that it not only lists the students on the screen, but also writes them to a text file. It's easy, you just need to add a few lines to the main.cpp file:
#include #include static QTextStream out (stdout); // saves a student's data class Student {public: QString name; QString date of birth; QString school class; QString phone number; Student (QString name, QString date of birth, QString school class, QString call number) {this-> name = name; this-> date of birth = date of birth; this-> school class = school class; this-> call number = call number; } Output void (QTextStream & where) {where to << "Name:" << name << Qt :: endl; where << "date of birth:" << date of birth << Qt :: endl; where to << "class:" << school class << Qt :: endl; where << "phone number:" << phone number << Qt :: endl; where to << Qt :: endl; }}; int main () {student a ("Lisa Lob", "05/01/2007", "8a", "0211/1234567"); Schueler b ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); Schueler c ("Max Robinson", "11/20/2006", "8a", "0211/345678"); a. output (out); b. output (out); c. output (out); QFile file ("test.txt"); if (file.open (QIODevice :: WriteOnly)) {QTextStream stream (& file); a.output (current); b.output (current); c. output (current); file.close (); } }
At the top there is a new #include line because we are using the QFile class. This class provides methods for accessing files.

Below we create an object of this class, which is initialized with the file name "test.txt". Then the file is opened for writing (WriteOnly).

If (if) that worked, we create a second object of the class QTextStream with the name "stream" and output all three students with it. We'll deal more with the if statement in a moment.

Finally the file is closed with close (). After that, at the latest, you can view them with a text editor.

Do that. Start the program and then look for the output file text.txt in the build directory. It is located where your project directory is located. The name of the directory is quite long and starts with "build":

Open the test.txt file to check it:

Looks good, doesn't it?

There are other files in the build directory:

  • Makefile is a configuration file that controls the compilation process.
  • main.o contains the machine code that the compiler created from main.cpp.
  • schueler.o contains the machine code that the compiler created from schueler.cpp.
  • test (Linux) or test.exe (Windows) contains the complete executable program, i.e. the content of all * .o files.
You can simply delete this entire build directory at any time. If you start the program in the development environment, it will be regenerated.

Conditional execution

We come to the explanation of the if statement. They are used to execute a single command or a block of commands only when a certain condition is met. Some examples:
#include static QTextStream out (stdout); int main () {if (4 + 5 == 9) {out << "4 plus 5 is 9" << Qt :: endl; } if (7> 5) {out << "7 is greater than 5" << Qt :: endl; } if (3 == 4) {out << "3 equals 4" << Qt :: endl; // no! } if (3! = 4) {out << "3 is not equal to 4" << Qt :: endl; } if (1) {out << "1 is true" << Qt :: endl; } if (0) {out << "0 is true" << Qt :: endl; // no! }}
The output is:

As you can see, the two false statements were skipped. This is exactly what the if statement is used for.

Note that you need the double "==" sign to compare numbers. The simple "=" is reserved for assigning something to a variable, as we have already done a few times above.

  • x == 5 checks whether x has the value 5, but
  • x = 5 set the variable x to the value 5!

Also note that you can always just use a simple number instead of a comparison expression. Where 0 is always treated as "untrue" and all other numbers are "true".

Now let's take a look at the documentation to see what QFile :: open () actually returns:

Oh, if it is successful, the method returns true. Then our if expression in main.cpp is correct:

if (file.open (QIODevice :: WriteOnly)) {QTextStream stream (& file); a.output (current); b.output (current); c. output (current); file.close (); }
That means: If the opening of the file was successful, then output something and close it again. Otherwise not.

You could also tell the computer to do something else:

QFile file (""); if (file.open (QIODevice :: WriteOnly)) {QTextStream stream (& file); a.output (current); b.output (current); c. output (current); file.close (); } else {out << "The file cannot be opened" << Qt :: endl; }
The error case is deliberately provoked this time by using an empty file name:

References instead of copies

Note the "&" sign at the marked position:
Output void (QTextStream &where) {where to << "Name:" << name << Qt :: endl; where << "date of birth:" << date of birth << Qt :: endl; where to << "class:" << school class << Qt :: endl; where << "phone number:" << phone number << Qt :: endl; where to << Qt :: endl; }
That is new.

Without the "&" sign, a copy of the QTextStream would be passed to the method. You could then modify the copy within the method without affecting the original.

With the "&" sign, however, a reference to the existing object is transferred. The reference does not occupy any additional memory.

With the QTextStream, a copy does not make sense, because channels like "stdout" cannot be used more than once. There can only be one single object that uses this "stdout" channel. You now have the reason why a reference to the existing object has to be passed here.

Nasty error message

Try to compile the same source code without "&" and look at the error messages that result:

This is a perfect example of a very nasty, difficult to understand error message 🙁

First of all, you should know that the compiler always tries to continue working in spite of errors. Therefore, the first error message is the most important, all others could be consequential errors. With such chains of error messages, always focus on the first one.

Furthermore, there is a very good chance of finding help on the Internet because someone raised the same problem in a discussion forum. So search Google for the text of the error message. If Google doesn't find anything, leave out all names. In this case, search for "call to deleted constructor of 'QTextStream'" or for "call to deleted constructor" if the first attempt doesn't work.

I've just tried it (on February 26th, 2020) - the first attempt already provides a suitable explanation as the first result.

The C ++ programming language automatically creates a so-called copy constructor for each object, which is used under the hood when the object is copied. So exactly your case, because the "&" sign is missing. Now the Qt framework also offers the possibility to delete such copy constructors with the macro Q_DISABLE_COPY.

This is always done when copies of the object would not work properly, which is the case with QTextStream.

Split into multiple files

The program is slowly starting to grow. Now is a good time to split it up into multiple files. To do this, right-click on "Source files" and then select the "Add ..." command.

In the dialog that follows, select the "C ++ class" template. Enter "student" as the class name and then click on "continue" and then on "complete". Your IDE then creates two new files (schueler.h and schueler.cpp), which appear in the project structure on the left.

One C ++ class, but two files, why is that?

In the programming language C ++ you can publish libraries without their source code. In Windows these are the numerous .dll files, in Linux they have the ending .so.

In order for programmers to be able to use these libraries properly, they need a clear listing of the class (es) in them, including their attributes. The compiler also needs this information. The header file with the extension .h is intended for this description.

The program code of the methods is then either as numerical machine code in the library or as source code in the .cpp files. This division into two files is usually also used for self-written C ++ classes.

So now fill the schueler.cpp file with the methods of the C ++ class. The constructor also belongs to it:

#include "schueler.h" Student::Student (QString name, QString date of birth, QString school class, QString call number) {this-> name = name; this-> date of birth = date of birth; this-> school class = school class; this-> call number = call number; } void Student::output (QTextStream & where) {where to << "Name:" << name << Qt :: endl; where << "date of birth:" << date of birth << Qt :: endl; where to << "class:" << school class << Qt :: endl; where << "phone number:" << phone number << Qt :: endl; where to << Qt :: endl; }
Since such a .cpp file can theoretically contain several C ++ classes (but this is rarely done), the compiler requires that the name of the respective class be written in front of the methods. I've marked this here.

The development environment currently shows a lot of red hints because the associated header file schueler.h is still empty:

So, next we will devote ourselves to the header file, copy the following text into it:

#ifndef SCHUELER_H #define SCHUELER_H #include // saves the data of a student class Student {public: QString name; QString date of birth; QString school class; QString phone number; Student (QString name, QString date of birth, QString school class, QString phone number); print void (QTextStream & where); }; #endif // SCHUELER_H
And hey presto - the red messages in the other .cpp file disappear.

We'll take a closer look at the content of the two files in a moment. First, let's rewrite the main program main.cpp to use these two new files.

#include #include "schueler.h" static QTextStream out (stdout); int main () {student a ("Lisa Lob", "05/01/2007", "8a", "0211/1234567"); Schueler b ("Hanna Kornblut", "08/12/2007", "8b", "0211/234567"); Schueler c ("Max Robinson", "11/20/2006", "8a", "0211/345678"); a. output (out); b. output (out); c. output (out); }
Finished. So the whole thing can now be carried out again. Test the program. The output is still as usual:

Take a look at the highlighted change in main.cpp. We have removed the entire source code of the C ++ class "Student" from the main program and replaced it with the instruction

replaced. At this point the compiler mentally inserts the content of the named header file. This header file describes the C ++ class with its methods and attributes, but without the specific source code of the methods. This in turn is located in the associated .cpp file.

With the #include instruction, the file name is not in angle brackets this time ("<>"), but in double quotation marks. This way, the compiler knows that it has to look for the file in your project directory. Files in angle brackets, however, it looks for in the installation directory of Qt.

The header files of Qt classes are always named exactly like the classes in them, without any extension. Your own header files, on the other hand, have lowercase file names with the extension .h.

The header file schueler.h contains a few interesting lines that were specified by the IDE:

#ifndef SCHUELER_H #define SCHUELER_H ... #endif // SCHUELER_H
This construct prevents error messages in the event that the schueler.h file is included (linked) multiple times. These are so-called preprocessor macros. I recommend that you just accept it at this point. Later you can read through the linked Wikipedia article to deepen the topic.

Note that the QTextStream file is included in the schueler.h file.

If QTextStream is already included because the C ++ class "QTextStream" is used, shouldn't one also include QString because the class "QString" is used?

Yes, you can do it. You can also omit the inclusion of QString, because exactly such a #include instruction is already in the header file of QTextStream. Look at it! Ctrl-click the file name:

Oops, there's little in it! Funnily enough, a header file is included here again. Also Ctrl-click it to look inside:

Aha, the file header file qstring.h is included there. That is the reason why you can leave out the line "#include " in your program. Click on the small "x" above to close the files again.

Handling Unicode

I think we should finally deal with umlauts. You have probably noticed that I have consistently avoided umlauts so far. That changes from now on.

Many years ago the gradual conversion of our computer systems to Unicode began in order to be able to display the characters of all languages ​​worldwide. This change is practically complete, but the C ++ compiler still expects simple strings to be encoded in 8-bit so as not to break old programs.

However, you can rewrite the line in question so that the whole Unicode character set works:

out << QStringLiteral ("The file cannot be opened") << Qt :: endl;
QStringLiteral () accepts source text in Unicode format. You should keep this in mind, because it solves the problem with umlauts - in this case with the "ö".

If it weren't for the annoying legacy of Windows ...

Although Windows switched to Unicode a long time ago, the console still uses an old 8-bit character set, namely the code page CP850. Qt can automatically convert from Unicode to this code page, but you have to specify this manually:

out.setCodec ("CP850"); out << QStringLiteral ("The file cannot be opened") << Qt :: endl;
Your source code now contains UTF-8 and Qt converts that to CP850 so that the umlauts appear correctly in the console.

If you add the following lines, setCode () is automatically omitted for all other operating systems:

#ifdef Q_OS_WIN out.setCodec ("CP850"); #endif out << QStringLiteral ("The file cannot be opened") << Qt :: endl;
This source code now works correctly on both Linux and Windows. The codec is set on Windows, but not on Linux.

Read in file

The next task is to load the addresses from a separate text file instead of writing them directly into the source text. Right click on the project name, then on "Add ...":

In the next dialog, select the General / Empty file template. The file should be named schueler.csv. The content should be:

Lisa Lob, 05/01/2007, 8a, 0211/1234567 Hanna Kornblut, 08/12/2007, 8b, 0211/2345678 Max Robinson, 11/20/2006, 8a, 0211/3456789 Natalia Safran, 04/03/2007, 8a, 0211/4567890 Murat Amir , 24.06.2007, 8c, 0211/5678901 Sasha Nimrod, 03.02.2007, 8c, 0211/6789012 Melina Grohe, 11.07.2007, 8a, 0211/7890123 Robert Schmitz, 14.12.2006, 8b, 0211/8901234 Thomas Hörner, 04.01 .2007, 8a, 0211/9012345
The following program opens this file using the QFile class, and then reads it line by line using the QTextStream class. Let's start with this first:
#include #include #include int main () {QTextStream out (stdout); #ifdef Q_OS_WIN out.setCodec ("CP850"); #endif QFile file ("../ test / schueler.csv"); if (file.open (QIODevice :: ReadOnly)) {QTextStream stream (& file); strom.setCodec ("UTF-8"); // because the file contains an "ö" in UTF-8 QString line = strom.readLine (); out << line << Qt :: endl; file.close (); }}
You already know all the classes and instructions used. The file name is relative to the build directory where your executable program is located. If you want you can also enter the full path name, for example: C: /Users/Stefan/Documents/Programmierung/Qt/test/schueler.csv

In the case of Windows, there are two particularities to note here: Firstly, some folders (Users and Documents) have English names, but the file manager (Explorer) displays them in German. Second, you have to use either the shown slashes "/" (slashes) or double "\" (backslashes) as separators. Because simple backslashes initiate escape sequences.

The output looks like this:

Repeat loop

Unfortunately the program only reads one line from the file. You need a loop that repeats part of the program until the entire .csv file has been read.
#include #include #include int main () {QTextStream out (stdout); #ifdef Q_OS_WIN out.setCodec ("CP850"); #endif QFile file ("../ test / schueler.csv"); if (file.open (QIODevice :: ReadOnly)) {QTextStream stream (& file); strom.setCodec ("UTF-8"); while (strom.atEnd () == false) { QString line = stream.readLine (); out << line << Qt :: endl; } file.close (); }}

The while () statement ensures that the following block is executed repeatedly, as long as the specified condition is true. The method atEnd () of the QTextStream class reports whether the end of the data stream has been reached. This expression therefore means something like "repeat as long as the end of the data stream has not been reached".

Another variant with exactly the same result would be the negation:

while (! strom.atEnd ()) {...}
This expression means something like "repeat as long as the end of the data stream has not been reached". So actually the same, just written differently.

Parse text

Now we want to break these lines down into their components in order to fill many objects of the C ++ class "Student" with the individual values. This process is called "parsing" - we parse the file.
#include #include #include int main () {QTextStream out (stdout); #ifdef Q_OS_WIN out.setCodec ("CP850"); #endif QFile file ("../ test / schueler.csv"); if (file.open (QIODevice :: ReadOnly)) {QTextStream stream (& file); strom.setCodec ("UTF-8"); while (strom.atEnd () == false) {QString line = strom.readLine (); QStringList parts = line.split (","); out << "Name:" << share [0] << Qt :: endl; out << "Date of birth:" << share [1] << Qt :: endl; out << "class:" << share [2] << Qt :: endl; out << "Call number:" << share [3] << Qt :: endl; out << Qt :: endl; } file.close (); }}
Here we use the split () method from the QString class to split the line into its components. The split () method returns a list of strings in the form of the QStringList class.

The program outputs the parts for checking. Notice how we access the individual elements (parts) of the list: by specifying which part we want in square brackets. Where [0] supplies the first element.

The output looks like this:

It is noticeable here that there are still a few spaces too many. They come from the .csv file. So next we cut off the spaces, and then we can fill the objects of the C ++ class "Student".

#include "schueler.h" #include #include #include int main () {QTextStream out (stdout); #ifdef Q_OS_WIN out.setCodec ("CP850"); #endif QFile file ("../ test / schueler.csv"); if (file.open (QIODevice :: ReadOnly)) {QTextStream stream (& file); strom.setCodec ("UTF-8"); while (strom.atEnd () == false) {QString line = strom.readLine (); QStringList parts = line.split (","); Student student (divide [0] .trimmed (), // Surname divide [1] .trimmed (), // Date of birth divide [2] .trimmed (), // school class parts [3] .trimmed ()); // phone number student.spending (out); } file.close (); }}
The expression share [n] returns part of the line as a QString. We then apply the QString :: trimmed () method to truncate spaces (before and after the text). With this we initialize an object of the C ++ class "Student", whose method Student :: output () ensures a nice display on the screen.

Lists

When we had the student data directly in the source code above, each student had their own object instance of the C ++ class "Student". We gave them the names a, b, and c. We had exactly as many variables as there were students. What would you like to name the variables if you had 2000 students in the .csv file?

Consecutive numbering is obvious here, perhaps similar to what was already done above with the parts of the lines. It works like this:

#include "schueler.h" #include #include #include int main () {QTextStream out (stdout); #ifdef Q_OS_WIN out.setCodec ("CP850"); #endif QList list; out << "Read the file ..." << Qt :: endl; QFile file ("../ test / schueler.csv"); if (file.open (QIODevice :: ReadOnly)) {QTextStream stream (& file); strom.setCodec ("UTF-8"); while (strom.atEnd () == false) {QString line = strom.readLine (); QStringList parts = line.split (","); Student student (share [0] .trimmed (), // name share [1] .trimmed (), // date of birth share [2] .trimmed (), // school class share [3] .trimmed ()); // phone number liste.append (student); } file.close (); } out << QStringLiteral ("Now all students are in memory") << Qt :: endl; out << QStringLiteral ("List the students on ...") << Qt :: endl; int i; for (int i = 0; i }
The output looks like this:

When we split the lines from the .csv file into parts, the QString :: split () method returned a QStringList object, i.e. a list of QStrings.

To have many students in memory, you need a list of students. Conveniently, the Qt Framework contains a universal list class that can hold any objects.

QList list; ... liste.append (student);
QList is a template class. In the case of templates, you write in angle brackets which class they should include. So we now have a list of students that we fill by repeatedly calling their append () method.

We use the for loop for output. For loops repeat a block while counting the number of passes:

for (int i = 0; i The syntax (notation) of the for loop looks complicated, but you get used to it. What's happening?

The list numbers its 9 elements starting with 0, so: [0], [1], [2], [3], [4], [5], [6], [7] and [8]. Therefore, the for loop should be repeated with numbers from 0 to 8.

The part "int i = 0" creates a variable of the type int, which is initialized with 0. This is the starting value for the first loop pass.

The part "i

The part "i ++" defines the step size in which i is increased. i ++ is a frequently used abbreviation for "i = i + 1".

Debug

To better understand the program flow, you can use the debugger from your development environment. With a debugger you can run the program line by line and look at the contents of all objects. The debugger gives you an insight into the inner workings of your program. The instructions are there.

I will now show you how to use the debugger. First you have to make sure that the debug mode is set at the bottom left:

 

In debug mode, the compiler inserts information into the program that the debugger needs to function. Then you can click on the gray beetle at the top to open the debug view.

Now you have to tell the debugger where to pause the program. To do this, click to the left of the line number of the line "List the students on ...". Then a red breakpoint will appear there.

Now start the program by clicking on the green arrow with the beetle at the very bottom left (above the hammer). It will run to the breakpoint and then pause. The output in the terminal window confirms that:

The debugger view now looks something like this:

There is a yellow arrow in front of line 37, which shows the current program line. The lines above have already been processed. The content of the currently known variable is displayed in the right-hand area. Here you can see that the list of students has 9 items. I opened the first element so that you can see what data is stored there.

In the lower area is a very narrow bar with important buttons:

Here you can manually control the further course of the program. If you hover over the symbols with the mouse, a helpful label will appear. How to find the buttons for individual steps:

  • "Single step over" means that when a method is called, it is executed in one go. You don't get to see the inside of the method.
  • "Step in" means that when a method is called, you go into that method and see how this is processed line by line.
Now click slowly several times on the "Single step over" button until you have reached "list [i]. Output (out)".

Take another look at the output in the terminal window, a new line has been added: "List the students ...". That is logical, you have just executed the corresponding line from the program.

You are now inside the for loop. The debugger shows you at the top right that a new variable has become accessible, namely i. And i currently has the value 0.

Now continue the program by slowly clicking repeatedly on the "Single step above" button. Observe how the yellow arrow and the display of the variables change at the top right.

When i reaches the value 8 and you then click again, the program ends. Keep clicking on the button, then you will see that the yellow arrow now jumps wildly back and forth a few times. This is because the program now gives each object the opportunity to perform a final cleanup method called a destructor.

Eventually you end up in this strange view:

This is the machine code that outputs the message "Press the key to close the window ...". The machine code appears here because you did not install the source code files for this part of the Qt framework.

You can still continue the program by clicking the "Single step via" button, or you click on the first button labeled "Continue GDB for test", then the program will run through to the end on its own.

While debugging, you may have noticed that the variable i was not displayed at the beginning (top right). This is because each variable only exists in the block in which it was created. In this case, the variable i was created in the for loop and therefore only exists within this loop. When the end of the loop has been reached, the variable disappears again. This limited visibility is called the scope.

Command line arguments

Console programs are often started with command line arguments that control the behavior of the program. So you may know the command "rm" for deleting a file, which expects the name of the file to be deleted as a parameter. I will now show you how your own program can receive such command line arguments:
#include int main (int argc, char * argv []) {QTextStream out (stdout); out << "Number of parameters:" << argc << Qt :: endl; for (int i = 0; i Start the program in the development environment, then you will get the following output:

The operating system always fills argc with the number of command line arguments. The arguments are passed to the program as argv and numbered starting with 0. The first argument is always the program itself. This can be followed by further arguments. We use the well-known for loop here to output the arguments in the console window.

To try out more arguments, you can configure the project in the development environment:

Switch back to the "Edit" view and start the program again.

I think we've experimented enough with the console by now. Next I want to show you how to output colorful graphics.

Output graphic

An empty window

This chapter builds on the previous one!

The console window can only output text. We are now adding another window based on the QWidget class that enables graphical output.

To do this, we first have to change a line in the test.pro project file to include the libraries for graphic applications and widgets. Change "QT - = gui" to:

Press Ctrl-S to save the change. The development environment now needs a few seconds to integrate the graphic libraries. The first graphic program should look like this:
#include #include #include int main (int argc, char * argv []) {QApplication app (argc, argv); QTextStream out (stdout); out << "Start graphic output ..." << Qt :: endl; QWidget widget; widget.show (); return app.exec (); }

If you close the empty graphical window, the program also ends. You can recognize this from the corresponding message in the console window:

Events control the process

The first major change here is the use of QApplication:
int main (int argc, char * argv []) {QApplication app (argc, argv); ... return app.exec (); }

While console programs run from top to bottom, graphic programs wait for events (e.g. mouse clicks and key presses) to be processed.

Every graphical program based on the Qt Framework must contain exactly one QApplication object. The QApplication constructor initializes the processing of the events. The QApplication :: exec () method contains a queue that receives and processes the events.

In between we can insert commands that should be executed when the program starts. In this case, an object of the QWidget class is created, which is the graphical program window.

Many windows

Try starting two windows:
#include #include #include int main (int argc, char * argv []) {QApplication app (argc, argv); QTextStream out (stdout); out << "Start graphic output ..." << Qt :: endl; QWidget widget; widget.show (); QWidget widget2; widget2.show (); return app.exec (); }
Now the program actually has a total of three windows:

Output messages without a console

We no longer need the console window for further experiments with graphics, so remove the "console" from the "CONFIG" line in the test.pro file:

This line might look a little different for you if you're using a different version of QT. Leave the other entries unchanged, just remove the "console". Then press Ctrl-S again to save the change. The development environment takes a few seconds to process the change.

Start the program again to check success. The console is gone now, only two graphic windows open.

Note the text highlighted in red. What was previously written into the console now appears in the lower area of ​​the development environment. This is very useful for outputting details for error analysis that normally should not be visible (in the graphic windows).

Replace the entire source code of main.c with the following:

#include #include int main (int argc, char * argv []) {QApplication app (argc, argv); qDebug ("start widget ..."); qWarning ("Warning of the vicious dog!"); qCritical ("That's an error message."); QWidget widget; widget.show (); return app.exec (); }
We have now only left one window and switched the output of QTextStream to special functions for debug messages.

On Linux these messages now appear in red:

This is because the messages no longer flow via the output channel "stdout", but rather via the channel "stderr". You could have used it with QTextStream too.

The real advantage of these debug messages, however, is that they can be automatically supplemented with additional information and that they can be filtered according to importance.

The formatting of the debug messages can be controlled with an environment variable. Qt's documentation suggests the following line:

QT_MESSAGE_PATTERN = "[% {type}]% {appname} (% {file}:% {line}) -% {message}"
Such environment variables are usually set centrally in the Windows control panel, or in Linux in the / etc / profile file. For a start, however, it is better to only do this in the development environment for this one project. I've shown how to get there in the following picture:

Enter "QT_MESSAGE_PATTERN" as the name and "[% {type}]% {appname} (% {file}:% {line}) -% {message}" as the value.

Switch back to the "Edit" view on the left edge of the development environment and start your program again. Now the debug messages look different:

Because every line is now marked with the importance at the beginning, you can filter according to it. For example, if you enter "[critical]" in the white filter field, you will only see critical messages.

As an alternative to the environment variable, you can specify the output format directly in your source code with the qSetMessagePattern () function. Take a look at this article, there are more formatting instructions listed that may interest you.

Drawing colorful graphic

We now want to draw a colorful graphic in the widget.

The flow control of your operating system requires that windows draw their contents themselves on command, at any time and any number of times. If necessary, the operating system sends a signal to the window with the command "Redraw yourself". Then the window has to draw its own content.

That means: You cannot just actively draw in your source text in the window, you have to wait for such a signal. The QApplication class does the waiting, so all that remains is the need to write a method that does the drawing.

Object-oriented programming includes the option of deriving your own classes from existing ones and adding additional properties (attributes) and methods. You can also replace existing methods with your own. That is exactly what we have to do, because the existing method of the QWidget, which reacts to the command "Draw yourself", simply does nothing. That's why the window is still completely empty at the moment.

Create a new class called MyWidget:

Use the template for C ++ classes and set there that the base class should be QWidget.

Open the generated file meinwidget.h and add the method paintEvent () to it. This method is called when the window receives the command "Redraw yourself".

#ifndef MEINWIDGET_H #define MEINWIDGET_H #include class MeinWidget: public QWidget {Q_OBJECT public: explicit MeinWidget (QWidget * parent = nullptr); void paintEvent (QPaintEvent * event); signals: public slots:}; #endif // MEINWIDGET_H
Then you have to insert the source code of the method paintEvent () into the generated file meinwidget.cpp:
#include "meinwidget.h" #include MyWidget :: MyWidget (QWidget * parent): QWidget (parent) {} void MyWidget :: paintEvent (QPaintEvent * event) {QPainter painter (this); painter.drawRect (50,50,150,100); }
We have derived our own class from the QWidget, which replaces the paintEvent () method with its own variant. In this method we use a QPainter to draw a rectangle in the window.

How the thing with the derivation works exactly and what the lines mean that your development environment has generated, I will explain in detail below in the chapter Classes and Objects.

Now you have to rewrite the main.cpp so that your own MeinWidget is used as the main window instead of QWidget.

#include "meinwidget.h" #include int main (int argc, char * argv []) {QApplication app (argc, argv); MyWidget widget; widget.show (); return app.exec (); }
Try the program:

If you paid attention, you noticed the message "Unused parameter 'event'":

In fact, the event parameter is actually not used within the paintEvent () method. That's okay in this case, because we don't need it. But we are not allowed to simply remove the parameter, because otherwise the Qt Framework would no longer call this function.

What we can do, however, is to replace the name of the parameter with the comment "unused". Then the warning disappears:

void MeinWidget :: paintEvent (QPaintEvent * / * unused * /) {QPainter painter (this); painter.drawRect (50,50,150,100); }
Let's add a few more graphical elements to the paintEvenet () method:
#include "meinwidget.h" #include MeinWidget :: MeinWidget (QWidget * parent): QWidget (parent) {} void MeinWidget :: paintEvent (QPaintEvent * / * unused * /) {QPainter painter (this); // head painter.drawRect (50,50,150,100); // eyes painter.setBrush (QBrush (Qt :: blue)); painter.drawEllipse (75,75,20,20); painter.drawEllipse (150,75,20,20); // mouth painter.setPen (QColor (Qt :: red)); painter.drawArc (60,80,130,50, -30 * 16, -120 * 16); // hair painter.setPen (QColor (Qt :: darkGreen)); painter.drawLine (123,50,115,30); painter.drawLine (125,50,125,30); painter.drawLine (128,50,135,30); }

Now I want to check when and how often this paintEvent () method is actually executed. To do this, add a line to the paintEvent () method:

void MeinWidget :: paintEvent (QPaintEvent * / * unused * /) { qDebug ("paintEvent () was called"); QPainter painter (this); // Head ... }
When the program starts, the method is called once, which is logical:

If you change the size of the window, the paintEvent () method will be called multiple times. Give it a try and pay attention to the debug messages.

If you feel like it, you can draw more figures in the window or add text. Familiarize yourself with the functions of QPainter.

A button to click

I'll show you now how to add a button that triggers a function. You need to add a method to the mywidget.h file to do this.
#ifndef MEINWIDGET_H #define MEINWIDGET_H #include class MeinWidget: public QWidget {Q_OBJECT public: explicit MeinWidget (QWidget * parent = nullptr); void paintEvent (QPaintEvent * event); signals: public slots: void clicked (); }; #endif // MEINWIDGET_H
This method should be called when the button (which we are about to insert) sends the signal "I was clicked". Because the method receives the signal, it is called a "slot".

Now also change the file meinwidget.cpp in order to insert the button there and to implement the method clicked ():

#include "meinwidget.h" #include #include #include MyWidget :: MyWidget (QWidget * parent): QWidget (parent) { QPushButton * button = new QPushButton ("Click me!", This); connect (button, & QPushButton :: clicked, this, & MeinWidget :: clicked); } void MeinWidget :: klickt () {QMessageBox :: information (this, "Info", "The button was clicked"); } void MeinWidget :: paintEvent (QPaintEvent * / * unused * /) {qDebug ("paintEvent () was called"); QPainter painter (this); // head painter.drawRect (50,50,150,100); // eyes painter.setBrush (QBrush (Qt :: blue)); painter.drawEllipse (75,75,20,20); painter.drawEllipse (150,75,20,20); // mouth painter.setPen (QColor (Qt :: red)); painter.drawArc (60,80,130,50, -30 * 16, -120 * 16); // hair painter.setPen (QColor (Qt :: darkGreen)); painter.drawLine (123,50,115,30); painter.drawLine (125,50,125,30); painter.drawLine (128,50,135,30); }
We added two lines to the constructor of MyWidget to create a new QPushButton and to connect it to the clicked () slot method.

The result looks bad:

The main window (widget) is now tiny. Apparently it has automatically adjusted to the size of the button. But we want the window to stay large, so we add another line to the MeinWidget constructor:

MyWidget :: MyWidget (QWidget * parent): QWidget (parent) { setFixedSize (400,300); QPushButton * button = new QPushButton ("Click me!", This); connect (button, & QPushButton :: clicked, this, & MeinWidget :: clicked); }
Try the program.

Also try out what happens when the button is clicked: The slot method clicked () opens a QMessageBox to display the following information message.

We can move the button to a better location:

MyWidget :: MyWidget (QWidget * parent): QWidget (parent) {setFixedSize (400,300); QPushButton * button = new QPushButton ("Click me!", This); button-> move (80,190); connect (button, & QPushButton :: clicked, this, & MeinWidget :: clicked); }

Stack versus heap

Note that the keyword "new" was used in the MeinWidget constructor:
QPushButton * button = new QPushButton (...);
Normal objects take up space in the stack. Everything that is on the stack is removed again at the end of the method. The consequence would be that the button would no longer exist after the constructor was executed.

But it should exist much longer, at least until this window has been closed. This is exactly what is achieved with "new". Objects created in this way are stored in the heap. This is another storage area reserved for long-lived objects. The heap contains all of the free memory on your computer. It is therefore used jointly by the running programs. The operating system ensures that the programs do not look at each other's data.

The "button" variable is now a pointer to the memory space in the heap. The asterisk in front of "button" means something like "pointer to button". The attributes and methods of the button can be accessed by dereferencing them indirectly via the pointer. The operator "->" does this. When you write "button-> move ()", you call the move () method on the object pointed to by button.

I explain this topic in more detail below in the Pointers and References chapter.

The fact that the window has been given a button has turned it into an interactive dialog. Qt Creator contains a very convenient tool to design such dialog windows with a kind of paint program, so that you don't have to laboriously define the sizes and positions of all input elements (buttons, text fields, labels, ...) with source text . In the next chapter we will try this so called "Qt Designer".

Qt designer

In this chapter I will show you how you can create a dialog-based program with the Qt Designer. You can close the previous "test" project, we will create a new project.

Go to the File / New ... menu and select the "Qt Widgets Application" template. The project name should be "test2". Then click on "next" a few times until the new project has been created. The program is already executable, try it out.

Now open the form file mainwindow.ui with a double click, then you get to the Qt Desginer.

The dotted gray working area represents the content of the window. You can insert dialog elements there. But before you do that, switch to the edit view briefly on the far left. Then you will see that this .ui file is a readable XML file. This view is interesting to see which properties deviate from the standard specifications, because only these are written to the XML file.

Back in the designer view, you should now drag a push button from the left bar into the workspace and click "Click me!" label. To do this, use the right mouse button after dragging, then the command "Change text".

It should now look something like this:

Select the "MainWindow" object at the top right (next to the workspace), then look for the "windowTitle" property in the yellow area below. Change the value to "Save the world!". Start the control program, it should now look like this:

The button has no function yet, which we are now changing. Right-click on the button and select the command "Show slot ...". Select the slot clicked () by double-clicking it. Now the development environment changes to the editor view, which shows the C ++ source code of the mainwindow.cpp class.

You will see a call to the setupUi (this) method in the constructor. This is the place where the configuration is loaded from the Qt Designer.

Below the IDE has added a new empty method called on_pushButton_clicked (). This is the slot that is called when the button sends its "clicked ()" signal. Insert the marked lines:

#include "mainwindow.h" #include "ui_mainwindow.h" #include MainWindow :: MainWindow (QWidget * parent): QMainWindow (parent), ui (new Ui :: MainWindow) {ui-> setupUi (this); } MainWindow :: ~ MainWindow () {delete ui; } void MainWindow :: on_pushButton_clicked () { QMessageBox :: information (this, "Info", "The button was pressed"); }
Start the program again to try it out. Click the button.

I will now show you how to design dialog windows with the help of layouts.

Layouts automatically align dialog elements properly and ensure that they adapt to different screen sizes and font sizes.

Open the mainwindow.ui file again. The workspace has reserved space for a menu bar and a status bar at the top and bottom. We don't need them. Therefore delete the two objects "menuBar" and "statusBar" on the right edge of the IDE with the right mouse button.

Slide the button far down and then drag a "shape" layout into the workspace, something like this:

Drag two "labels" to the left edge of the form layout and change their labels (by double-clicking) on ​​"First name:" and "Last name:"

Drag two "Line Edit" fields into the red marking to the right of the labels:

On the far right in the IDE you should now change the object names of the two input fields. They are currently called "lineEdit" and "lineEdit_2". Right click on these names and then click on "Change Object Name" to change them to "First Name" and "Last Name":

Drag a "Horizontal Layout" under the existing layout in the workspace and push the button into it:

Now drag a "Horizontal Spacer" to the left of the button, the button is then pressed to the right edge.

You have a form with labels and input fields, and you have a button right aligned.

Right click in the object list with the right mouse button on MainWindow and then select the command "Layout -> Arrange objects in table". This will automatically adjust the form to the window size.

Make the window a little smaller. Like this:

Start the program to test it.

Looks good, doesn't it?

Switch to the edit view on the left edge of the development environment and open the mainwindow.cpp file. There the slot on_pushButton_clicked () should now be changed so that the name is output from the form:

#include "mainwindow.h" #include "ui_mainwindow.h" #include #include MainWindow :: MainWindow (QWidget * parent): QMainWindow (parent), ui (new Ui :: MainWindow) {ui-> setupUi (this); } MainWindow :: ~ MainWindow () {delete ui; } void MainWindow :: on_pushButton_clicked () { qDebug () << "The first name is" << ui-> first name-> text ();qDebug () << "The last name is" << ui-> last name-> text ();QString message = ui-> first name-> text () + "" + ui-> last name-> text () + ", you are a hero!"; QMessageBox :: information (this, "Info",report); }
As you can see from this example, the qDebug () function can be used exactly like the QTextStream object - with the << operator.

Below that the new message text for the MessageBox is put together by adding the two names together. The finished program looks like this:

Now you have got to know the basic way of working with the Qt Designer and how its generated code merges with what you have written yourself.

Share program

If you want to share your program with someone or start without a development environment, you have to proceed differently depending on the operating system.

Share program on Windows

You can find the output of the compiler in the same folder where your project is saved. The folder has a long name that starts with "build". This contains a file with the extension .exe, in this case "test.exe". This is your machine code in executable form, you have to share this file.