Qt comes with a QTreeWidget
class which can be used to show data in a tree view. It can be used to show hierarchical data using either Model/View framework or by manually creating the hierarchy. The QTreeWidget
supports multi-columns for each row and also allows editing of the individual cells. However, sometimes we need to present a QWidget
in a cell to allow user to interact with data. For example, we might want a user to choose a Boolean value for a cell and instead of asking the user to type Yes/No or True/False, we can present the user with a checkbox. This eliminates human errors in type the values. Often, there is also a need to embed a QPushButton within a cell to allow user to run some action.
Let’s dig in a single example on how to embed a QWidget
in a cell of a QTreeWidget
.
// Create a tree widget with three columns. QTreeWidget* treeWidget = new QTreeWidget(); treeWidget->setColumnCount(3); QStringList columnNames; columnNames << "Column 1" << "Column 2" << "Column 3"; treeWidget->setHeaderLabels(columnNames); // Add a top level tree widget item. QTreeWidgetItem* item = new QTreeWidgetItem(); treeWidget->addTopLevelItem(item); // Add a check box to the second column. QCheckBox* checkBox = new QCheckBox("Click Me!"); treeWidget->setItemWidget(item, 1, checkBox1); // Add tree widget to the parent widgets layout. this->setLayout(new QVBoxLayout()); this->setContentsMargins(0, 0, 0, 0); this->layout()->addWidget(treeWidget);
The above code produces the output as shown in the below image. The check box is left aligned and QTreeWidget
does not offer a way to center or right align it out of the box. A standard solution offered online is to inherit from QTreeWidgetItem
and take control of painting the item directly.
Inheriting from QTreeWidgetItem
is unnecessarily complicated and there is no need to do it. A simpler way is to put the checkbox in another widget and use a horizontal layout with stretch before and after the checkbox! This trick can be used to right align as well by omitting the stretch before the checkbox. Here is the code:
// Create a check box. QCheckBox* checkBox = new QCheckBox("Click Me!"); // Put the check box in a wrapping widget with appropriate layout. QWidget* checkBoxWrapper = new QWidget; QHBoxLayout* layout = new QHBoxLayout(); layout->addStretch(); layout->addWidget(checkBox); layout->addStretch(); layout->setContentsMargins(0, 0, 0, 0); checkBoxWrapper->setLayout(layout); // Add it to the tree widget. mTreeWidget->setItemWidget(item, 1, checkBoxWrapper);
This code is going to produce the following output:
The complete Visual Studio 2019 solution for this demo can be downloaded here.
SLogLib is a flexible logging library written in C++. It comes with three logging devices: console, file, and memory but often there is a need to show log directly on the user interface. I heavily use Qt for all projects requiring user interface, so I wrote a logging device for QWidget
. It is available in SLogLib
repository in the Contrib/QWidgetLogger
folder.
Here is how to use the QWidgetLogger:
QWidgetLogger* logger = new QWidgetLogger(new HtmlFormatter(), "WidgetLogger"); SLogLib::addLoggingDevice(logger);
Once above code is added, any of the SLOGLIB_LOG_MSG_*
logging macros will write to the QWidgetLogger
as well as any other loggers added to SLogLib. QWidgetLogger
internally uses SLogTextEdit
class derived from QTextEdit
. Instance of SLogTextEdit
used by QWidgetLogger
can be retrieved by QWidgetLogger::widget() function. This instance should be added to the UI to show the logging messages. QDockWidget
is a good choice to show logging widget with QMainWindow
.
SLogTextEdit
sets a monospace 10 point font and it can be changed using style sheet. The color and style of the messages logged can also be changed using the Formatter
. The HtmlFormatter
used in the example above define different colors for different types of logging messages using HTML codes.
In Qt, UI elements can only be updated from the main thread but the logging messages might come from any thread. So SLogTextEdit
checks if the message was posted from the main thread or some other worker thread. If the message was posted from a worker thread, SLogTextEdit
emits a signal to only of its own private slot and updates itself in the slot. In Qt slots always run in the context of the main thread. This method works well but signal and slot mechanism is slow and update to widget lags while logging too many messages in a short period of time.
Some time back, I developed a data entry application in Qt5. One of the requirements was to let the user select a single string from a predefined list of string. I developed a custom widget called SStringSelector
for this purpose. SStringSelector
has two views: display and selection. The display view presents the currently selected string (blank if no string is selected), and a push button. To select a string, the user clicks on the button which presents the user with the selection dialog. The selection dialog consists of a list of string in an QListWidget and the user can select one of them by double-clicking a string. If the list of strings are long, the user can filter them using a filter QLineEdit present above the QListWidget.
SStringSelector
is distributed as a part of QtUtils repository hosted on Github. The SStringSelector
widget is really simple to use. Simple add the SStringSelector.h and SStringSelector.cpp files in your project and add an instance of SStringSelector in the layout of your app.
Below are some screenshots of the widget under Windows:
Qt5 support standard dialogs such as QFileDialog, QFontDialog, and QColorDialog, however, it does not provide a color picker to allow a user to pick a color. Recently, I need a color picker for one of my projects and I implemented a simple color picker widget.
SColorPicker
is available from Github as a part of QtUtils repository. To use SColorPicker
, add the header and cpp files directly in your project. Then, simply add an instance of SColorPicker
in a layout. SColorPicker
will appear as 16×16 pixels colored square in the layout. If you need a different size, change it in the SColorPicker's
constructor. When a user double-clicks on the colored square, the system’s color dialog will appear allowing the user to choose a color. The selected color can be obtained from color()
function or by connecting to colorPicked()
signal.
Below are the screenshots of the SColorPicker_Demo
and system color dialog present to the user on Windows 10 computer.
This week, at work I had to implement a search box for a software I am working on. The search box is to filter some data dynamically as user types a query. I wanted to show a clear (cross) icon at the right side of the search box so that user can clear the results instead of selecting the current query and deleting it manually. Lastly, for clarity I wanted to show a search icon on the left side of search box. The search box looks like this:
After the user enters a query a clear icon appears on the right. The clear icon is in fact a button and clicking it will clear the current search.
It is really easy to make this search box using QLineEdit. We need only the following three lines of code:
QLineEdit* _lineEdit = new QLineEdit(); _lineEdit->setClearButtonEnabled(true); _lineEdit->addAction(":/resources/search.ico", QLineEdit::LeadingPosition); _lineEdit->setPlaceHolderText("Search..."); // add _lineEdit to your widget
Line 2 enables the clear button which adds the clear action and cross icon to the right. Line 3 adds another action with a search icon to the left of the QLineEdit. We don’t listen to this action as it is merely decorative. Line 4 adds a placeholder text which is shown in the QLineEdit but is cleared as soon as user starts typing.
We only connect textChanged(const QString&) signal which is emitted both when a user clicks on the cross icon and when he enters a search query.