This example shows how to create a Resource file which contains a list of various file names which will be embedded in your application. When the executable is created the files listed in the resource file are bundled into the executable. The original files, which are now embedded, do not need to be distributed with the binary. The most common type of files include images, text, icons, and translation files.
#include <QtCore>
#include <QtGui>
class MainWindow : public QWidget
{
public:
MainWindow();
private:
QByteArray readJson(QString fName);
};
This declaration for MainWindow declares the constructor and one private method which is used to read the contents of a JSON file.
MainWindow::MainWindow()
{
setMinimumSize(600, 400);
// example 1
QPushButton *plus_PB = new QPushButton("plus");
QPushButton *minus_PB = new QPushButton("minus");
QFrame *frame = new QFrame();
QPixmap plusImage(":/resources/plus.png");
plus_PB->setIcon(plusImage);
QPixmap minusImage(":/resources/minus.png");
minus_PB->setIcon(minusImage);
// example 2
QComboBox *wordList_CB = new QComboBox();
wordList_CB->setMinimumWidth(250);
QString fileName = ":/resources/words.txt";
QFile dictionary(fileName);
dictionary.open(QFile::ReadOnly);
QTextStream inputStream(&dictionary);
while (! inputStream.atEnd()) {
wordList_CB->addItem(inputStream.readLine());
}
wordList_CB->model()->sort(0);
wordList_CB->setCurrentIndex(0);
// example 3
QByteArray data = readJson(":/resources/config.json");
QJsonDocument doc = QJsonDocument::fromJson(data);
QJsonObject object = doc.object();
QVariantMap map = object.toVariantMap();
QTableView *view = new QTableView();
QStandardItemModel *model =
new QStandardItemModel(map.size(), 2);
model->setHeaderData(0, Qt::Horizontal,
QString("Json Key"));
model->setHeaderData(1, Qt::Horizontal,
QString("Value"));
view->setModel(model);
view->setColumnWidth(0, 200);
view->setColumnWidth(1, 250);
view->horizontalHeader()->setStretchLastSection(true);
int row = 0;
QStandardItem *item;
for (auto iter = map.begin(); iter != map.end(); ++iter) {
item = new QStandardItem(iter.key());
model->setItem(row, 0, item);
item = new QStandardItem(iter.value().toString());
model->setItem(row, 1, item);
++row;
}
QHBoxLayout *layout1 = new QHBoxLayout();
layout1->addStretch();
layout1->addWidget(plus_PB);
layout1->addSpacing(20);
layout1->addWidget(minus_PB);
layout1->addStretch();
QPushButton *close_PB = new QPushButton();
close_PB->setText("Close");
QHBoxLayout *layout2 = new QHBoxLayout();
layout2->addStretch();
layout2->addWidget(close_PB);
layout2->addStretch();
QVBoxLayout *layoutMain = new QVBoxLayout(this);
layoutMain->setContentsMargins(45, 35, 45, 25);
layoutMain->addLayout(layout1);
layoutMain->addSpacing(30);
layoutMain->addWidget(wordList_CB, 0, Qt::AlignHCenter);
layoutMain->addSpacing(30);
layoutMain->addWidget(view);
layoutMain->addSpacing(20);
layoutMain->addLayout(layout2);
connect(close_PB, &QPushButton::clicked,
this, &QWidget::close);
}
Our application contains three separate examples which use files listed in the example_35.qrc resource file. The purpose of a Resource file is to embed other files in your binary application. Once embedded there is no need to distribute them with your project. For more information about resource files refer to the next section.
The first example starts on line 6 where we declare two push buttons. On line 11 the name of a png file is passed to the constructor of QPixmap. The syntax used to identify the “plus.png” file must also include the full path as defined in the .qrc file. On line 12 we set the QPushButton icon to the given QPixmap object.
Our next example creates a QComboBox which is populated with a list of words located in the “words.txt” file. The next few lines open the text file and use a QTextStream to read the data and add each word to the combo box.
The last example shows a table which contains the keys and values located in a json file. The file name is passed to readJson() on line 36 and the method simply returns the contents of the given file. Lines 38 through 40 are responsible for parsing the json data and store the information in a map. We are using a QVariantMap since the data types for the values may not be the same. The source code for this method is available in the example_35.zip file.
The next 25 lines of code create a QTableView and copies the keys (the json keys) in the map to column one and the values (the json values) in the map to column two. QTableView was shown in example 23. The remaining lines of code are used to define the layout for our push buttons, combo box, and the table.
It is important to mention that since files like “words.txt” are embedded into your application there is no way for a user to modify the contents. In addition, if you change the contents of any file referenced in the Resource file you must rebuild and redeploy your application.
Resource File
The contents of the “example_35.qrc” resource file, used in this example, is shown below. The base name can be anything however the file extension must be qrc. The contents of this file uses an XML format.
<RCC>
<qresource prefix="/">
<file>resources/config.json</file>
<file>resources/minus.png</file>
<file>resources/plus.png</file>
<file>resources/words.txt</file>
</qresource>
</RCC>
The CopperSpice distribution contains multiple libraries and several executables. The rcc executable is run when building your application. It will process the qrc file and generate a cpp file. The output looks more like binary code then actual C++ source code. In a later build step the cpp file will be compiled to create an object file which is then linked with your application.
The XML <file> element identifies a physical file with a path relative to the directory where the .qrc file is located. The following table shows an example directory structure.
Location of the .qrc file | <path>/src |
Location of the designated files | <path>/src/resources |
Main Function
Since the source code for main() has not changed there is no need to show it again. Refer to example 3 or download the full source for this example.
Running the Example
To build and run this example use the same CMake build file and commands as we showed for the first example. Line 2 of the CMakeLists.txt file needs to be changed from “example_1” to “example_35”.
The other required modification is a few extra commands to compile the resource file. On line 42 the generated resource cpp file is added to project sources. Lines 45 though 48 are commands which instruct CMake to compile the resource file and generate the qrc_example_35.cpp file. The implementation to call rcc is located in the CS CMake macro files.
list(APPEND PROJECT_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
qrc_example_35.cpp
)
# run rcc to generate qrc output
COPPERSPICE_RESOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/example_35.qrc
)