Logo    
KDWinUtils
Helper library for MFC to Qt migration
Loading...
Searching...
No Matches
For MFC developers

The KDWinUtils library provides classes with an API close the the MFC API, but using Qt underneath. Some high-level concepts like message maps or data exchange are migrated to a Qt equivalent.

The library is split between:

  • corelib: aimed at replacing data primitives
  • widgets: aimed at replacing everything UI-related

Conventions

Any methods starting with an uppercase letter (DoSomething) are coming from the MFC API. If a method starts with a lowercase letter (doSomething), it's a new API.

To match the Qt API, new APIs that are handling callbacks (for message handling, command updating...) start with connect.

Class equivalence

Make sure to read the documentation of the different classes as there may be some small differences and API changes.

Note: Some API may be missing in those classes.

Corelib

MFC class KDWinUtils class Comment
CImageList KImageList
CPoint KPoint
CRect KRect
CSize KSize
CString KString No separation between unicode and non-unicode
CStringArray KStringArray

All those primitive classes have implicit and explicit conversion methods from/to their MFC and Qt equivalent.

Widgets

MFC class KDWinUtils class Comment
CBrush KBrush
KButtonGroup Use for DDX_Radio
CCheck KCheck
CComboBox KComboBox
KCommandManager Use for handling menubars and toolbars
CDialog KDialog
CEdit KEdit For single line edit
CEdit KMultiEdit For multi-line edit
CFont KFont
CHeaderCtrl KHeaderCtrl
CListCtrl KListModel
CMenu KMenu
KNumber Use for DDX_Text linked to an integral or floating point member
CDC KPainter The class using for drawing in Qt is QPainter
CPen KPen
CPropertyPage KPropertyPage
CPropertySheet KPropertySheet
CSliderCtrl KSliderCtrl
KSortFilterProxyModel Use internally by KListModel for sorting and filtering
CTabCtrl KTabCtrl
KText Use for DDX_Text linked to a string
CWnd KWidget QWidget is the base class for all graphical items
CSpinButtonCtrl KSpinButtonCtrl

Resource migration

The RC file contains different items:

  • Dialogs
  • String tables
  • Assets
  • Menus and toolbars
  • ...

All those items are migrated in different ways, using Qt paradigms.

Dialog descriptions

All dialogs have a description in the RC file, with the position and size of all the controls in the dialog. Qt also has a way to describe a dialog, using UI files, which can easily be edited graphically using the Qt Designer.

The migration will transform the description from the RC file into a Qt UI file. Note that contrary to MFC, there's one UI file per dialog.

Strings

In MFC RC files, strings are typically handled by referencing them through resource IDs. These IDs are assigned to strings within the RC file and then used to access the corresponding string resources programmatically.

However, in Qt, there's no direct equivalent to MFC RC files for managing string resources. Instead, Qt relies on other mechanisms like internationalization (i18n) and Qt Linguist for handling translations and managing strings.

To bridge this gap and enable similar functionality, a ResourceHelper file is created with a Helper::GetString method returning the string from its ID. This will typically allow using the Qt translation system, while still using ID-based string access.

Assets

Qt already has a system in place to deal with assets (icons, images...): the Qt Resource System. The major difference with MFC is that MFC uses resource IDs to reference and access resources.

To bridge this gap and enable similar functionality, a ResourceHelper file is created with a Helper::GetAsset method returning the asset from its ID.

Note: the qrc file is quite easy to create from a script, it is however advised to convert the BMP images to PNG images, as well as making them semi-transparent if needed (instead of relying on specific colors like Magenta).

Menus and toolbars

TODO

Dialogs and Windows

The CWnd is the base class for all graphical objects in MFC, particularly it's the base class for CDialog. Within KDWinUtils, their equivalent are respectively KWidget and KDialog: in Qt, the base class for any graphical objects is a QWidget.

But contrary to MFC, those classes are not directly inherited from one to another, as we already have a Qt inheritance hierarchy in place:

KWidget/KDialog class diagram

This has an impact on the GetParent method, you now have 3 methods:

  • GetParent<T>: template method to retrieve the direct parent,
  • GetParentWidget: returns the parent as a KWidget, or nullptr if it's not one,
  • GetParentDialog: goes up in the parent-child tree to find the first KDialog and returns it, or nullptr if none.

Message handling

Message map

Message map is a corner feature for any control or window (CWnd, CDialog...) in MFC. They are used mainly for 2 different scenarios:

  • responding to an external event: system event (timer) or user events (mouse or key events)
  • handling notifications between components

Those 2 scenarios map perfectly to Qt own paradigms:

  • Qt event handlers for the former
  • Signal slot connections for the latter

So a simple message map:

BEGIN_MESSAGE_MAP(CTutorialDlg, CDialog)
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_BN_CLICKED(ID_BTN_ADD, OnBnClickedBtnAdd)
END_MESSAGE_MAP()

will be migrated in the code below:

// In the CTutorialDlg class
void paintEvent(QPainterEvent *event); // ON_WM_PAINT, replaces OnPaint
void mouseMoveEvent(QMouseEvent *event); // ON_WM_MOUSEMOVE, replaces OnMouseMove
// In the CTutorialDlg constructor, signal slot connection for ON_BN_CLICKED
connect(m_ui->btn_add, &QPushButton::clicked, this, &CTutorialDlg::OnBnClickedBtnAdd);

Message sending and posting

It is possible to send (synchronous) and post (asynchronous) messages to a specific control or window. This is done with the SendMessage and PostMessage APIs. Those messages are either handled from the message map (with ON_MESSAGE) or using PreTranslateMessage.

In KDWinUtils, the SendMessage and PostMessage APIs still exist (see in KWidgetBase). The way it's done is that it's going to create a Qt event, and either send it directly to the widget (synchronous) or post it on the event loop (asynchronous). The handling is done:

  • using ConnectMessage to replace the ON_MESSAGE
  • overloading QObject::event to replace PreTranslateMessage

Warning: There are no PeekMessage, as it's not possible with Qt. Such a code need to be changed.

Data exchange

Data exchange is a concept only available in MFC, there are no such things in Qt. MFC has some kind of model-view architecture, with explicit synchronization points. In Qt, there are no such things, developers are using directly the widgets and their API in the code.

To simplify the migration, we keep the members (a CComboBox becomes a KComboBox), but those are just proxies on top of existing widgets. The DoDataExcahnge method is used to link those proxies with their widgets.

For example, if we have a combo box in a dialog, we will have something like this:

void CMyDlg::DoDataExchange()
{
m_comboCtrl.setWidget(m_ui->comboBox);
// ...
}

Then, when the developer calls m_comboCtrl.AddString("foo"), he is calling the corresponding Qt API on the combo box, in this case m_ui->comboBox->addItem("foo").

It would be possible to remove all members and only use the Qt API, but that would require changing a lot of code. The code is still readable as is, and you can always manipulate the widget directly, without any harm.

Drawing

Drawing is done using primitives close to the MFC primitives:

MFC class KDWinUtils class
CBrush KBrush
CFont KFont
CDC / CPaintDC KPainter
CPen KPen

Contrary to the MFC API, the preferred way to work in Qt is to create objects (pen, brush...) on the stack, beyond that the general usage is the same.

The biggest difference is that Qt is using a double buffer by default, and there's no immediate painting possible. All paint operations need to be done in the paintEvent method of widgets.