Qt World Summit: Submit your Presentation

Canvas issue

  • Hi! In my main.qml I have Window as a root entity and nested Canvas in it (I decided that a Form will be an extra element in my app). At certain point of development it became necessary to set a background color for my Canvas (white color), but Canvas doesn't have a property for this, so I set "white" to the color property of a parent - Window entity. However, when I got access to a pixel array through getImageData() and looked through it I saw that RGBA color of each pixel on the clean Canvas was "(0,0,0,255)"(black) instead of "(255,255,255,255)"(white). Is it a bug? Or I did something wrong?

  • Your Canvas is a child of something indeed, but it has it's own paint methods.

    If you're trying to paint a JPG image for instance, each and every pixel will be painted according to your image, and JPG does not have transparency, so the white background you defined will always be replaced by the JPG value.

    So, maybe you are not doing anything wrong, but have the wrong kind of picture? (JPG instead of PNG)

  • @peteritv I used default settings of Canvas in terms of image type. My task was only to implement drawing with a mouse on the white Canvas and to code white pixels as 0 and colored pixels as 1 for the needs of my core logic class. And when I wrote a "for" cycle to iterate over all pixels on the Canvas, it revealed that the background pixels are black in the data array, though Canvas per se was displayed as white. Sort of magic....

  • Maybe I spoke before I knew what was really going on...

    It might help if you post the sceleton of your application, so we can see the context.

  • @peteritv Here you can see entire main.qml:

    import QtQuick 2.7
    import QtQuick.Window 2.2
    import QtQuick.Controls 2.0
    Window {
        id: "window"
        visible: true
        width: 640
        height: 480
        maximumHeight: height
        maximumWidth: width
        minimumHeight: height
        minimumWidth: width
        color: "white"
        title: "Однослойный перцептрон"
        Component.onCompleted: {
            setX(Screen.width/2 - width/2)
            setY(Screen.height/2 - height/2)
        property int xpos
        property int ypos
        property bool hold
        property bool clearCanvas:false
        Canvas {
            anchors.top: parent.top
            width: 640
            height: 410
            onPaint: {
                var ctx = getContext('2d')
                if(clearCanvas) {
                    ctx.fillStyle = "white"
                else {
                    ctx.lineCap = "round"
                    ctx.lineWidth = 30
                    ctx.strokeStyle = 'blue'
                    xpos = area.mouseX
                    ypos = area.mouseY
                    ctx.lineTo(xpos, ypos)
            MouseArea {
                anchors.fill: parent
                acceptedButtons: Qt.LeftButton | Qt.RightButton
                onPressed: {
                    if(mouse.buttons & Qt.LeftButton) {
                        xpos = mouseX
                        ypos = mouseY
                onPositionChanged: {
                    if(hold & (mouse.buttons & Qt.LeftButton)) {
                onReleased: {
                    hold = false
                onClicked: {
                    infoArea.visible = false
            Button {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            height: 50
            width: 300
            anchors.bottomMargin: 8
            onClicked: {
                var image = canvas.getContext('2d').getImageData(0,0,canvas.width,canvas.height)
                var norm_px = []
                for(var i = 0, n=image.data.length; i<n; i+=4) {
                    if(image.data[i]===0 && image.data[i+1]===0 && image.data[i+2]===255 && image.data[i+3]===255) {
                neuro.signal = norm_px
                if  (neuro.exitSignal===1) {
                else if (neuro.exitSignal===2) {
                else {
                infoArea.visible = true
                exitInfo.text = "\u03F4: "+ neuro.exitTheta.toFixed(5) + " " + "\u03A8: " + neuro.exitPsi.toFixed(5);
            Rectangle {
                visible: false
                id: "infoArea"
                anchors.horizontalCenter: canvas.horizontalCenter
                anchors.verticalCenter: canvas.verticalCenter
                width: 200
                height: 200
                color: "white"
                border.color: "black"
                border.width: 3
                radius: 10
                Text {
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.verticalCenter: parent.verticalCenter
                    font.family: "Helvetica"
                    font.pointSize: 100
                    color: "green"
                MouseArea {
                    id: "hoverArea"
                    anchors.fill: parent
                    hoverEnabled: true
                    ToolTip {
                        visible: hoverArea.containsMouse

    Only the color of mouse traces is defined correctly, unlike the background and it's strange.

    P.S. Sorry for my English, it is my second language, I will try to be more clear if you don't understand something in my posts.

  • After reading some docs, I am sure you are not telling something.

    You want to draw on something that is white, correct?
    So your canvas must be a child of something that is white.

    For instance:
    Rectangle { color: white; Canvas { ... } }

    Is that the case here?

  • @peteritv Yes, you are correct. In my case I set Canvas as a child of a white Window, but Context2D shows me, suddenly, that the canvas is the child of the black Window. Though it is displayed as white.

  • OK, I just run your example, and it seems to work.

    I have a white background on which I can draw.
    When I draw I see the traces of my mouse with a big "point" size.
    Draw color is blue.

    Everything seems to work.

    Now, since I don't have your "Neuro" file, THAT may be your problem...

  • We have a synchronisation issue here to :)

    So when you run your program, you are drawing on a black thing?

  • Where/How do you use Context2D?

  • Ahhhh! I understand now! (I think)

    You think that what ever background you choose, it will be part of your canvas?
    That is NOT the case!

    The canvas just is a container for some points being drawn!

    For instance, you can take the canvas, and put it on something else like a red Rectangle.
    It will still have the same points, but now on a red background.

    In other words, the canvas does NOT hold any information at all about the background. It just knows about some pixels.

  • So in your case, you need to fill your Canvas with white pixels itself.

    So with ur ctx functions, draw a white rectangle first, which will be the base of your canvas for drawing on.

  • So, instead of making your parent white:

    Within your canvas, draw a white rectangle on start,
    and then start drawing on that

  • But that explaines why you see "black" instead of "white" on your Context2D

    I am assuming you are just interested in the points, and not the background, for further processing.
    So forget about the canvas background, ok?

  • @peteritv Huge thanks, I finnally got what's going on! A visible background of working application is just a result of visual compositing the Canvas with it's parent and these two does not share any properties between each other. Thanks a lot again, I think it is very important to know such nuances.

Log in to reply