Changing the graphic engine changes the way a path is drawn
-
Using Qt Quick 5.15.2, I need to draw a dashed rounded rectangle outline. As unfortunately it's not possible to reach a such drawing with the
Rectangle.border
properties, I created my own shape path to reach the rendering I needed.However the path I created is sometimes broken, and so inconsistent. First of all, I needed to introduce kind of compensatory values in my path, because sometimes the position was shifted by 1 pixel in relation to the expected one, for a reason I cannot figure out. And after reaching the expected drawing, it may become broken again if I change the graphic engine used by Qt, e.g by using or not OpenGLES.
For that reason I wrote 2 different paths, which I switch depending on which graphic engine I use. However, although all is fine on my computer, several of my clients complain that the rectangle is drawn completely broken, which makes me suppose that Qt may change the graphic engine internally, depending on the target computer capabilities.
This is a very annoying issue, and I would like to know what I'm doing wrong, as well as how a such path should be written to work correctly on ALL computers.
Here is my qml code:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 import QtQuick.Shapes 1.15 import QtGraphicalEffects 1.15 import QtQuick.Templates 2.15 as T /** * Dashed border *@author JMR */ T.Control { // advanced properties property int m_StrokeWidth: 1 property int m_Radius: 5 property string m_FillColor: "transparent" property string m_StrokeColor: "#bac1db" property bool m_UseOpenGLES: true//false /** * Background rectangle */ Rectangle { // common properties anchors.fill: parent color: m_FillColor radius: m_Radius /** * Dashed outline shape (OpenGLES version) */ Shape { // common properties id: shDashedBorderOGLES anchors.fill: parent anchors.margins: 0 //layer.enabled: true //layer.samples: 8 smooth: true visible: m_UseOpenGLES /** * Dashed outline shape path */ ShapePath { // common properties fillColor: "transparent" strokeColor: m_StrokeColor strokeWidth: m_StrokeWidth strokeStyle: ShapePath.DashLine dashPattern: [5, 5] startX: m_Radius startY: 0 // path commands PathLine {x: shDashedBorderOGLES.width - m_Radius; y: 0;} PathQuad {x: shDashedBorderOGLES.width; y: m_Radius; controlX: shDashedBorderOGLES.width; controlY: 0;} PathLine {x: shDashedBorderOGLES.width; y: shDashedBorderOGLES.height - m_Radius;} PathQuad {x: shDashedBorderOGLES.width - m_Radius; y: shDashedBorderOGLES.height - 1; controlX: shDashedBorderOGLES.width; controlY: shDashedBorderOGLES.height;} PathLine {x: m_Radius; y: shDashedBorderOGLES.height - 1;} PathQuad {x: 0; y: shDashedBorderOGLES.height - m_Radius; controlX: 0; controlY: shDashedBorderOGLES.height;} PathLine {x: 1; y: m_Radius;} PathQuad {x: m_Radius; y: 0; controlX: 0; controlY: 0;} } } /** * Dashed outline shape (non-OpenGLES version) */ Shape { // common properties id: shDashedBorderNOGLES anchors.fill: parent anchors.margins: 0 //layer.enabled: true //layer.samples: 8 smooth: true visible: !m_UseOpenGLES /** * Dashed outline shape path */ ShapePath { // common properties fillColor: "transparent" strokeColor: m_StrokeColor strokeWidth: m_StrokeWidth strokeStyle: ShapePath.DashLine dashPattern: [5, 5] startX: m_Radius startY: 1 // path commands PathLine {x: shDashedBorderNOGLES.width - m_Radius; y: 1;} PathQuad {x: shDashedBorderNOGLES.width; y: m_Radius; controlX: shDashedBorderNOGLES.width; controlY: 0;} PathLine {x: shDashedBorderNOGLES.width; y: shDashedBorderNOGLES.height - m_Radius;} PathQuad {x: shDashedBorderNOGLES.width - m_Radius; y: shDashedBorderNOGLES.height; controlX: shDashedBorderNOGLES.width; controlY: shDashedBorderNOGLES.height;} PathLine {x: m_Radius; y: shDashedBorderNOGLES.height;} PathQuad {x: 0; y: shDashedBorderNOGLES.height - m_Radius; controlX: 0; controlY: shDashedBorderNOGLES.height;} PathLine {x: 1; y: m_Radius;} PathQuad {x: m_Radius; y: 0; controlX: 0; controlY: 0;} } } } }
And below is the graphic engine I may enable or disable:
QCoreApplication::setAttribute(Qt::ApplicationAttribute::AA_UseOpenGLES, true);
-
So as nobody answered this question, I found a workaround which seems to resolve my issue. I changed the stroke width from 1 to 1.5. However this unfortunately doesn't explain what happened here, and why the
ShapePath
object behaves this way. I have my own idea about that: I think it's a kind of pen alignment, as in GDI+ (https://docs.microsoft.com/en-us/windows/win32/api/gdiplusenums/ne-gdiplusenums-penalignment), however I found absolutely no way to configure that.So below is my solution, which works correctly in all situations on my side:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 import QtQuick.Shapes 1.15 import QtGraphicalEffects 1.15 import QtQuick.Templates 2.15 as T /** * Dashed border *@author JMR */ T.Control { // advanced properties property real m_StrokeWidth: 1.5 property int m_Radius: 5 property string m_FillColor: "transparent" property string m_StrokeColor: "#bac1db" /** * Background rectangle */ Rectangle { // common properties anchors.fill: parent color: m_FillColor radius: m_Radius /** * Dashed outline shape */ Shape { // common properties id: shDashedBorder anchors.fill: parent anchors.margins: 0 //layer.enabled: true //layer.samples: 8 smooth: true clip: true /** * Dashed outline shape path */ ShapePath { // common properties fillColor: "transparent" strokeColor: m_StrokeColor strokeWidth: m_StrokeWidth strokeStyle: ShapePath.DashLine dashPattern: [5, 5] startX: m_Radius startY: 0 // path commands PathLine {x: shDashedBorder.width - m_Radius; y: 0;} PathQuad {x: shDashedBorder.width; y: m_Radius; controlX: shDashedBorder.width; controlY: 0;} PathLine {x: shDashedBorder.width; y: shDashedBorder.height - m_Radius;} PathQuad {x: shDashedBorder.width - m_Radius; y: shDashedBorder.height; controlX: shDashedBorder.width; controlY: shDashedBorder.height;} PathLine {x: m_Radius; y: shDashedBorder.height;} PathQuad {x: 0; y: shDashedBorder.height - m_Radius; controlX: 0; controlY: shDashedBorder.height;} PathLine {x: 0; y: m_Radius;} PathQuad {x: m_Radius; y: 0; controlX: 0; controlY: 0;} } } } }