Learn Qt 5
上QQ阅读APP看书,第一时间看更新

Mastering MVC

Now that our solution structure is in place, we’ll get started on the MVC implementation. As you’ll see, it is very minimal and incredibly easy to set up.

First, expand cm-ui > Resources > views.qrc > / > views, right-click on main.qml, select Rename, and rename the file as MasterView.qml. If you get a message about project editing, just select Yes to continue anyway:

If you do get the error message, the file will still appear as main.qml in the Projects pane, but the file will have been renamed in the filesystem.

Next, edit views.qrc (right-click on it and select Open With > Plain Text Editor). Replace the content as follows:

<RCC>
 <qresource prefix="/views">
 <file alias="MasterView.qml">views/MasterView.qml</file>
 </qresource>
</RCC>

If you recall how we load this QML file in main.cpp, the syntax is qrc:<prefix><filename>. We previously had a / prefix and a views/main.qml relative filename. This gave us qrc:/views/main.qml.

A prefix of / isn’t terribly descriptive. As you add more and more QML files, it’s really helpful to organize them into blocks with meaningful prefixes. Having unstructured resource blocks also makes the Projects pane ugly and more difficult to navigate, as you just saw when you had to drill down through views.qrc > / > views. So, the first step is to rename the prefix from / to /views.

However, with a prefix of /views and a relative filename of views/main.qml, our URL is now qrc:/views/views/main.qml.

This is worse than it was before, and we still have a deep folder structure in views.qrc. Fortunately, we can add an alias for our file to make both of these problems go away. You can use the alias of a resource in place of the relative path, so if we assign an alias of main.qml, we can replace views/main.qml with simply main.qml, giving us qrc:/views/main.qml.

That’s concise and descriptive, and our Projects pane is neater too.

So, going back to our updated version of views.qrcwe have simply updated the name of the file from main.qml to MasterView.qml, consistent with the file rename we performed, and we have also provided a shortcut alias, so we don't have to specify views twice.

We now need to update our code in main.cpp to reflect these changes:

engine.load(QUrl(QStringLiteral("qrc:/views/MasterView.qml")));

You should be able to run qmake, and build and run to verify that nothing has broken.

Next, we’ll create a MasterController class, so right-click on the cm-lib project and select Add New… > C++ > C++ Class > Choose…:

Use the Browse… button to create the source/controllers subfolder.

By selecting QObject as the base class and including it, Qt Creator will write some of the boilerplate code for us. You can always add it yourself later, so don’t feel like it’s a necessary part of creating a new class.

Once you’ve skipped version control and created the class, declare and define it as follows. Our MasterController doesn’t do anything particularly exciting just yet, we’re just doing the groundwork.

Here's master-controller.h:

#ifndef MASTERCONTROLLER_H
#define MASTERCONTROLLER_H
#include <QObject> #include <cm-lib_global.h>
namespace cm { namespace controllers {
class CMLIBSHARED_EXPORT MasterController : public QObject { Q_OBJECT
public: explicit MasterController(QObject* parent = nullptr); };
}}
#endif

All we’ve really added to the default implementation Qt Creator gave us is the CMLIBSHARED_EXPORT macro Qt Creator wrote for us in cm-lib_global.h to take care of our shared library exports, and to put the class inside a namespace.

always  have the project name as a root namespace and then additional namespaces that reflect the physical location of the class files within the source directory, so in this case, I use cm::controllers ,   as the class is located in the directory   source/controllers .

This is master-controller.cpp:

#include "master-controller.h"

namespace cm {
namespace controllers {
MasterController::MasterController(QObject* parent) : QObject(parent) { }
}}

I use a slightly unorthodox style in the implementation file—most people just add   using namespace cm::controllers;  at the top of the .cpp file. I often like to put the code within the scope of namespaces because it becomes collapsible in the IDE. By repeating the innermost namespace scope ( controllers  in this example), you can break your code up into collapsible regions much like you can in C#, which helps with navigation in larger files, as you can collapse the sections you’re not interested in. It makes no functional difference, so use whichever style you prefer.